assertIsArray($referenceFiles, 'Unable to list .pro files in all-songs directory.'); sort($referenceFiles, SORT_STRING); $paths = []; foreach ($referenceFiles as $path) { if ($path === self::EMPTY_SKIP_FILE) { continue; } $bytes = @file_get_contents($path); $this->assertIsString($bytes, 'Unable to read file: ' . $path); if ($bytes === '') { $this->fail('Unexpected empty file not in skip list: ' . $path); } $paths[] = $path; } $paths[] = self::TEST_PRO_PATH; $this->assertCount( self::EXPECTED_NON_EMPTY_ALL_SONGS + 1, $paths, 'Expected 168 non-empty all-songs files plus Test.pro.' ); $failures = []; $identicalCount = 0; foreach ($paths as $path) { $original = @file_get_contents($path); $this->assertIsString($original, 'Unable to read file: ' . $path); $presentation = new Presentation(); try { $presentation->mergeFromString($original); } catch (\Throwable $throwable) { $failures[] = [ 'path' => $path, 'reason' => 'decode_error', 'message' => $throwable->getMessage(), ]; continue; } $reencoded = $presentation->serializeToString(); if ($original === $reencoded) { $identicalCount++; continue; } $firstMismatch = $this->firstMismatchOffset($original, $reencoded); $failures[] = [ 'path' => $path, 'reason' => 'byte_mismatch', 'original_length' => strlen($original), 'reencoded_length' => strlen($reencoded), 'length_delta' => strlen($reencoded) - strlen($original), 'first_mismatch_offset' => $firstMismatch, ]; } $total = count($paths); $mismatchCount = count($failures); $testProIdentical = !in_array(self::TEST_PRO_PATH, array_column($failures, 'path'), true); $message = "Binary round-trip results: {$identicalCount}/{$total} identical, {$mismatchCount} differ. Test.pro identical: " . ($testProIdentical ? 'yes' : 'no') . '.'; if ($mismatchCount > 0) { $message .= "\nDetails:\n" . json_encode($failures, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } $this->assertSame([], $failures, $message); } private function firstMismatchOffset(string $left, string $right): ?int { $leftLength = strlen($left); $rightLength = strlen($right); $limit = min($leftLength, $rightLength); for ($index = 0; $index < $limit; $index++) { if ($left[$index] !== $right[$index]) { return $index; } } if ($leftLength !== $rightLength) { return $limit; } return null; } }