Skip to content

Add tests for QueryResponseParser and fix default_value bug #499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions inc/Config/QueryRunner/QueryResponseParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
*/
final class QueryResponseParser {
/**
* Get a field value based on its type. This should be a primitive type
* Get a field value based on its type. This should be a primitive type.
*
* @param mixed $field_value The field value.
* @param string $type_name The field type.
* @param mixed $default_value The default value.
* @return mixed The sanitized field value.
*/
private function get_field_value( mixed $field_value, string $type_name, mixed $default_value = null ): mixed {
$sanitized_value = Sanitizer::sanitize_primitive_type( $type_name, $field_value ?? $default_value );
private function get_field_value( mixed $field_value, string $type_name ): mixed {
if ( null === $field_value ) {
return null;
}

$sanitized_value = Sanitizer::sanitize_primitive_type( $type_name, $field_value );

// Some fields get formatted based on their type.
switch ( $type_name ) {
Expand Down Expand Up @@ -55,20 +58,24 @@ private function get_field_value( mixed $field_value, string $type_name, mixed $
*/
public function parse( mixed $data, array $schema ): mixed {
$json_obj = $data instanceof JsonObject ? $data : new JsonObject( $data );
$default_path = ( $schema['is_collection'] ?? false ) ? '$[*]' : '$';
$is_collection = $schema['is_collection'] ?? false;
$default_path = $is_collection ? '$[*]' : '$';
$value = $json_obj->get( $schema['path'] ?? $default_path );

if ( is_array( $schema['type'] ?? null ) ) {
$value = $this->parse_response_objects( $value, $schema['type'] ) ?? [];
} elseif ( is_string( $schema['type'] ?? null ) ) {
$value = array_map( function ( $item ) use ( $schema ) {
return $this->get_field_value( $item, $schema['type'], $schema['default_value'] ?? null );
}, $value );
if ( $is_collection ) {
$value = array_map( function ( $item ) use ( $schema ) {
return $this->get_field_value( $item ?? $schema['default_value'] ?? null, $schema['type'] );
}, $value );
} else {
$value = [ $this->get_field_value( $value[0] ?? $schema['default_value'] ?? null, $schema['type'] ) ];
}
} else {
$value = [];
}

$is_collection = $schema['is_collection'] ?? false;
return $is_collection ? $value : $value[0] ?? null;
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"test:e2e:help": "wp-scripts test-playwright --help",
"test:php": "composer test",
"test:php:coverage": "composer test-coverage",
"test:php:debug": "wp-env run tests-cli --env-cwd=wp-content/plugins/remote-data-blocks ./vendor/bin/phpunit",
"test:integration": "wp-env run tests-cli --env-cwd=wp-content/plugins/remote-data-blocks ./vendor/bin/phpunit -c ./phpunit-integration.xml",
"test:js": "vitest --watch=false",
"test:js:watch": "vitest --watch=true",
Expand Down
259 changes: 259 additions & 0 deletions tests/inc/Config/QueryResponseParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
<?php declare(strict_types = 1);

namespace RemoteDataBlocks\Tests\Config\QueryRunner;

use PHPUnit\Framework\TestCase;
use RemoteDataBlocks\Config\QueryRunner\QueryResponseParser;

/**
* QueryResponseParserTest class
*/
final class QueryResponseParserTest extends TestCase {
private QueryResponseParser $parser;

protected function setUp(): void {
parent::setUp();
$this->parser = new QueryResponseParser();
}

public function test_json_path_expressions(): void {
$data = [
'users' => [
[
'name' => 'Alice',
'age' => 30,
],
[
'name' => 'Bob',
'age' => 25,
],
],
];

$schema = [
'path' => '$.users[*]',
'is_collection' => true,
'type' => [
'userName' => [
'path' => '$.name',
'type' => 'string',
],
'userAge' => [
'path' => '$.age',
'type' => 'integer',
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertIsArray( $result );
$this->assertCount( 2, $result );
$this->assertArrayHasKey( 'result', $result[0] );
$this->assertArrayHasKey( 'uuid', $result[0] );
$this->assertEquals( 'Alice', $result[0]['result']['userName']['value'] );
$this->assertEquals( 30, $result[0]['result']['userAge']['value'] );
$this->assertEquals( 'Bob', $result[1]['result']['userName']['value'] );
$this->assertEquals( 25, $result[1]['result']['userAge']['value'] );
}

public function test_generate_callback(): void {
$data = [
[
'firstName' => 'Charlie',
'lastName' => 'Brown',
],
];

$schema = [
'is_collection' => true,
'type' => [
'fullName' => [
'type' => 'string',
'generate' => function ( $item ) {
return $item['firstName'] . ' ' . $item['lastName'];
},
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertIsArray( $result );
$this->assertCount( 1, $result );
$this->assertArrayHasKey( 'result', $result[0] );
$this->assertArrayHasKey( 'uuid', $result[0] );
$this->assertEquals( 'Charlie Brown', $result[0]['result']['fullName']['value'] );
}

public function test_format_callback(): void {
$data = [
[ 'price' => 1234.56 ],
];

$schema = [
'is_collection' => true,
'type' => [
'formattedPrice' => [
'path' => '$.price',
'type' => 'float',
'format' => function ( $value ) {
return '$' . number_format( $value, 2 );
},
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertIsArray( $result );
$this->assertCount( 1, $result );
$this->assertArrayHasKey( 'result', $result[0] );
$this->assertArrayHasKey( 'uuid', $result[0] );
$this->assertEquals( '$1,234.56', $result[0]['result']['formattedPrice']['value'] );
}

public function test_non_collection_result(): void {
$data = [
'product' => [
'name' => 'Gadget',
'price' => 99.99,
],
];

$schema = [
'path' => '$.product',
'is_collection' => false, // Explicitly false
'type' => [
'productName' => [
'path' => '$.name',
'type' => 'string',
],
'productPrice' => [
'path' => '$.price',
'type' => 'float',
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertIsArray( $result );
$this->assertArrayHasKey( 'result', $result );
$this->assertArrayHasKey( 'uuid', $result );
$this->assertEquals( 'Gadget', $result['result']['productName']['value'] );
$this->assertEquals( 99.99, $result['result']['productPrice']['value'] );
}

public function test_primitive_type_parsing(): void {
$data = [ 'ids' => [ 101, 102, 103 ] ];

$schema = [
'path' => '$.ids[*]',
'is_collection' => true,
'type' => 'integer',
];

$result = $this->parser->parse( $data, $schema );

$this->assertIsArray( $result );
$this->assertEquals( [ 101, 102, 103 ], $result );
}

public function test_primitive_type_parsing_single_value(): void {
$data = [ 'status' => 'active' ];

$schema = [
'path' => '$.status',
'is_collection' => false,
'type' => 'string',
];

$result = $this->parser->parse( $data, $schema );

$this->assertEquals( 'active', $result );
}

public function test_default_value(): void {
$data = [
'items' => [
[ 'name' => 'Apple' ],
[
'name' => 'Banana',
'color' => 'Yellow',
],
],
];

$schema = [
'path' => '$.items[*]',
'is_collection' => true,
'type' => [
'itemName' => [
'path' => '$.name',
'type' => 'string',
],
'itemColor' => [
'path' => '$.color',
'type' => 'string',
'default_value' => 'Unknown',
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertCount( 2, $result );
$this->assertEquals( 'Unknown', $result[0]['result']['itemColor']['value'] );
$this->assertEquals( 'Yellow', $result[1]['result']['itemColor']['value'] );
}

public function test_nested_objects(): void {
$data = [
'orders' => [
[
'id' => 1,
'customer' => [
'name' => 'David',
'email' => '[email protected]',
],
],
],
];

$schema = [
'path' => '$.orders[*]',
'is_collection' => true,
'type' => [
'orderId' => [
'path' => '$.id',
'type' => 'integer',
],
'customerInfo' => [
'path' => '$.customer',
'type' => [
'customerName' => [
'path' => '$.name',
'type' => 'string',
],
'customerEmail' => [
'path' => '$.email',
'type' => 'string',
],
],
],
],
];

$result = $this->parser->parse( $data, $schema );

$this->assertCount( 1, $result );

$customer_info = $result[0]['result']['customerInfo']['value'];

$this->assertIsArray( $customer_info );
$this->assertArrayHasKey( 'result', $customer_info );
$this->assertEquals( 'David', $customer_info['result']['customerName']['value'] );
$this->assertEquals( '[email protected]', $customer_info['result']['customerEmail']['value'] );
}
}
Loading