From a9f719c4089e34d3a0f7c5e845960256c0baf578 Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Sun, 26 Apr 2026 20:26:06 -0500 Subject: [PATCH] feat: add json file transport --- src/Transport/FileTransportInterface.php | 16 ++++ src/Transport/JsonFileTransport.php | 45 +++++++++++ .../Unit/Transport/JsonFileTransportTest.php | 79 +++++++++++++++++++ tests/bootstrap.php | 5 +- 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 src/Transport/FileTransportInterface.php create mode 100644 src/Transport/JsonFileTransport.php create mode 100644 tests/Unit/Transport/JsonFileTransportTest.php diff --git a/src/Transport/FileTransportInterface.php b/src/Transport/FileTransportInterface.php new file mode 100644 index 0000000..025bcda --- /dev/null +++ b/src/Transport/FileTransportInterface.php @@ -0,0 +1,16 @@ +validator = $validator; + } + + public function export( ContentPackage $package ): string { + $json = wp_json_encode( $package->toArray(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ); + + if ( false === $json ) { + throw new \RuntimeException( 'Unable to encode content package JSON.' ); + } + + return $json; + } + + public function import( string $contents ): ContentPackage { + $decoded = json_decode( $contents, true ); + + if ( ! is_array( $decoded ) ) { + throw new \InvalidArgumentException( 'The selected file is not valid JSON.' ); + } + + $result = $this->validator->validate( $decoded ); + + if ( ! $result->isValid() ) { + throw new \InvalidArgumentException( implode( ' ', $result->errors() ) ); + } + + return ContentPackage::fromArray( $decoded ); + } +} diff --git a/tests/Unit/Transport/JsonFileTransportTest.php b/tests/Unit/Transport/JsonFileTransportTest.php new file mode 100644 index 0000000..db551bd --- /dev/null +++ b/tests/Unit/Transport/JsonFileTransportTest.php @@ -0,0 +1,79 @@ +export( $this->package() ); + + self::assertStringContainsString( "\n", $json ); + self::assertStringContainsString( '"schema_version": "1.0"', $json ); + } + + public function test_it_imports_valid_json_packages(): void { + $transport = new JsonFileTransport( new PackageValidator() ); + $package = $transport->import( $transport->export( $this->package() ) ); + + self::assertSame( '1.0', $package->schemaVersion() ); + self::assertSame( 'https://example.test', $package->source()['site_url'] ); + } + + public function test_it_rejects_invalid_json(): void { + $transport = new JsonFileTransport( new PackageValidator() ); + + $this->expectException( \InvalidArgumentException::class ); + $this->expectExceptionMessage( 'The selected file is not valid JSON.' ); + + $transport->import( '{"schema_version":' ); + } + + public function test_it_rejects_schema_errors(): void { + $transport = new JsonFileTransport( new PackageValidator() ); + + $this->expectException( \InvalidArgumentException::class ); + $this->expectExceptionMessage( 'records is required.' ); + + $transport->import( '{"schema_version":"1.0"}' ); + } + + private function package(): ContentPackage { + $records = array( + 'posts' => array(), + 'terms' => array(), + 'media' => array(), + 'custom_post_types' => array(), + ); + + return ContentPackage::fromArray( + array( + 'schema_version' => '1.0', + 'generated_at' => '2026-04-26T20:30:00+00:00', + 'source' => array( + 'site_url' => 'https://example.test', + 'name' => 'Example Production', + ), + 'destination' => array( + 'site_url' => 'https://staging.example.test', + 'name' => 'Example Staging', + ), + 'manifest' => array( + 'posts' => 0, + 'terms' => 0, + 'media' => 0, + 'custom_post_types' => 0, + ), + 'records' => $records, + 'checksums' => array( + 'records' => PackageChecksum::records( $records ), + ), + ) + ); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 586b930..3479c6e 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -143,11 +143,12 @@ if ( ! function_exists( 'wp_json_encode' ) ) { * Minimal JSON encoder for unit tests. * * @param mixed $value Value to encode. + * @param int $flags JSON encoding flags. * @return string|false */ - function wp_json_encode( $value ) { + function wp_json_encode( $value, $flags = 0 ) { // phpcs:ignore -- Test stub for WordPress' wp_json_encode(). - return json_encode( $value ); + return json_encode( $value, $flags ); } }