setAccessible(true); return $method->invokeArgs($object, $arguments); } function accepted(callable $call, string $message): bool { try { $call(); return true; } catch (RuntimeException | InvalidArgumentException $error) { if ($error->getMessage() !== $message) throw $error; return false; } } $row = ['ID' => 'example', 'VariableID' => 12345]; $cases = [ 'empty' => [[], true], 'one' => [[$row], true], 'two' => [[$row, $row], true], 'sparse' => [[0 => $row, 2 => $row], false], 'one-based' => [[1 => $row, 2 => $row], false], 'out-of-order' => [[1 => $row, 0 => $row], false], 'negative-key' => [[-1 => $row, 0 => $row], false], 'string-key' => [['source' => $row], false], 'mixed-keys' => [[0 => $row, 'source' => $row], false], 'scalar' => [false, false], 'null' => [null, false], ]; foreach ($cases as $name => [$value, $expected]) { ManagerSDLRuntime::reset(); $manager = new Manager(42); $manager->Create(); $json = json_encode($value, JSON_THROW_ON_ERROR); $manager->testProperties['AnlagenBatterien'] = $json; $result = accepted(static function () use ($manager, $value, $expected): void { $actual = invokePrivate($manager, 'leseAnlagenKonfigurationsliste', ['AnlagenBatterien']); if ($expected) verify($actual === $value, 'valid manager list unchanged'); }, 'AnlagenBatterien muss eine JSON-Liste sein.'); verify($result === $expected, 'manager list: ' . $name); ManagerSDLRuntime::child(42, 'EnergieflussSDL'); ManagerSDLRuntime::$properties[700]['Config'] = $json; $result = accepted(static fn() => invokePrivate($manager, 'synchronisiereSDLEnergiefluss', [700]), 'Die bestehende Energiefluss-Konfiguration ist keine Liste.'); verify($result === $expected, 'SDL list: ' . $name); verify(ManagerSDLRuntime::$writes === [], 'list validation cannot change SDL configuration'); verify(ManagerSDLRuntime::$properties[700]['Config'] === $json, 'SDL source remains byte-identical'); } $config = ['version'=>1, 'installationId'=>'e3a08f9e-af12-4695-99bd-8b51c0520021', 'assetId'=>'ev', 'managerId'=>17004, 'batteryInstanceId'=>44234, 'mode'=>'physical_sum', 'allowEstimatedForTrial'=>false, 'maxSkewSeconds'=>30, 'maxAgeSeconds'=>60, 'idleToleranceW'=>50.0, 'trackingToleranceW'=>200.0, 'sources'=>[]]; foreach (['grid', 'physical'] as $i => $role) { $config['sources'][] = ['key'=>'source'.$i, 'role'=>$role, 'variableId'=>100+$i, 'parentId'=>200, 'ident'=>'value'.$i, 'factorToW'=>1]; } $hash = Feedback::fingerprint($config); $reordered = array_reverse($config, true); $reordered['sources'] = array_reverse($config['sources']); verify(Feedback::fingerprint($reordered) === $hash, 'canonical configuration fingerprint unchanged'); foreach ([[], [1, 2], [0, 2], [1, 0], ['grid', 'physical']] as $keys) { $bad = $config; $bad['sources'] = $keys === [] ? [] : array_combine($keys, $config['sources']); verify(!accepted(static fn() => Feedback::configuration($bad), 'feedback_sources_invalid'), 'malformed feedback source keys remain rejected'); } echo 'PHP80_LISTS_OK ' . $count . " checks; real methods with isolated runtime only.\n";