0 && $cursor < $len); if ($depth !== 0) { throw new RuntimeException('unbalanced braces while extracting the rrd remap loop'); } $block = substr($src, $start, $cursor - $start); // Test-only: wraps a block read from this repo's own lib/api_device.php (not // external/untrusted input) so the test exercises the production source // unmodified, matching Issue7380GraphCreateWiringTest.php's technique. eval('function apidevice_remap_rrds(array $old_rrds, $new_dt, array $duped_graph_templates) { ' . $block . ' }'); beforeEach(function () { global $database_hostname, $database_port, $database_default, $database_sessions; $this->db_globals = [$database_sessions, $database_hostname, $database_port, $database_default]; $database_hostname = 'unit-local'; $database_port = 0; $database_default = 'unit-local'; $this->conn = new PDO('sqlite::memory:'); $this->conn->exec('CREATE TABLE data_template_rrd (id INTEGER PRIMARY KEY, data_template_id INTEGER, data_source_name TEXT, local_data_id INTEGER)'); $this->conn->exec('CREATE TABLE graph_templates_item (id INTEGER PRIMARY KEY, graph_template_id INTEGER, task_item_id INTEGER)'); $database_sessions = ["$database_hostname:$database_port:$database_default" => $this->conn]; }); // Put the real db_* globals back so later tests in the run don't hit this sqlite handle. afterEach(function () { global $database_sessions, $database_hostname, $database_port, $database_default; [$database_sessions, $database_hostname, $database_port, $database_default] = $this->db_globals; }); function seedOldRrd(PDO $conn, int $id, int $old_dt, string $name): void { $conn->exec("INSERT INTO data_template_rrd (id, data_template_id, data_source_name, local_data_id) VALUES ($id, $old_dt, '$name', 0)"); } function seedNewRrd(PDO $conn, int $id, int $new_dt, string $name): void { $conn->exec("INSERT INTO data_template_rrd (id, data_template_id, data_source_name, local_data_id) VALUES ($id, $new_dt, '$name', 0)"); } function seedGraphItem(PDO $conn, int $id, int $graph_template_id, int $task_item_id): void { $conn->exec("INSERT INTO graph_templates_item (id, graph_template_id, task_item_id) VALUES ($id, $graph_template_id, $task_item_id)"); } test('a matched data_template_rrd row wires task_item_id to the new rrd id', function () { seedNewRrd($this->conn, 20, 8, 'ds'); seedGraphItem($this->conn, 100, 5, 10); apidevice_remap_rrds( [['id' => 10, 'data_source_name' => 'ds']], 8, [5] ); $task_item_id = $this->conn->query('SELECT task_item_id FROM graph_templates_item WHERE id = 100')->fetchColumn(); expect((int) $task_item_id)->toBe(20); }); test('a missing data_template_rrd row leaves task_item_id untouched instead of corrupting it', function () { // No row in data_template_rrd for data_template_id = 8, data_source_name = 'ds': // the cloned Data Template has no matching RRD item. seedGraphItem($this->conn, 100, 5, 10); apidevice_remap_rrds( [['id' => 10, 'data_source_name' => 'ds']], 8, [5] ); $task_item_id = $this->conn->query('SELECT task_item_id FROM graph_templates_item WHERE id = 100')->fetchColumn(); // Pre-fix, db_fetch_cell_prepared() returns false here and the UPDATE // still runs, binding false and corrupting task_item_id to 0. expect((int) $task_item_id)->toBe(10); });