From d1e22dbad8e3b2bd463f67dc945ba25daad752e4 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 13 Aug 2022 12:09:41 +0000 Subject: [PATCH] Tests: Bring some consistency to serialization tests. There were two sets of tests for `is_serialized()`: * One in the `functions.php` file, based on the same file name in core. * One in a separate class in the `functions` directory. To avoid confusion and make it easier to decide where new tests should go in the future, the existing tests are now combined in the latter location. Includes: * Moving `is_serialized()` and `maybe_serialize()` tests into their own classes. * Using named data providers to make test output more descriptive. * Combining test cases and removing duplicates. Follow-up to [278/tests], [279/tests], [328/tests], [32631], [45754], [47452], [49382], [53886], [53889]. See #55652. git-svn-id: https://develop.svn.wordpress.org/trunk@53890 602fd350-edb4-49c9-b593-d223f7449a82 --- tests/phpunit/tests/functions.php | 146 ----------- .../phpunit/tests/functions/isSerialized.php | 223 ++++++++++++---- .../tests/functions/isSerializedString.php | 2 +- .../tests/functions/maybeSerialize.php | 246 ++++++++++++++++++ 4 files changed, 419 insertions(+), 198 deletions(-) create mode 100644 tests/phpunit/tests/functions/maybeSerialize.php diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index c122dbd4e3..5f5a49c975 100644 --- a/tests/phpunit/tests/functions.php +++ b/tests/phpunit/tests/functions.php @@ -373,152 +373,6 @@ class Tests_Functions extends WP_UnitTestCase { return $formats; } - /** - * @dataProvider data_is_not_serialized - */ - public function test_maybe_serialize( $value ) { - if ( is_array( $value ) || is_object( $value ) ) { - $expected = serialize( $value ); - } else { - $expected = $value; - } - - $this->assertSame( $expected, maybe_serialize( $value ) ); - } - - /** - * @dataProvider data_is_serialized - */ - public function test_maybe_serialize_with_double_serialization( $value ) { - $expected = serialize( $value ); - - $this->assertSame( $expected, maybe_serialize( $value ) ); - } - - /** - * @dataProvider data_is_serialized - * @dataProvider data_is_not_serialized - */ - public function test_maybe_unserialize( $value, $is_serialized ) { - if ( $is_serialized ) { - $expected = unserialize( trim( $value ) ); - } else { - $expected = $value; - } - - if ( is_object( $expected ) ) { - $this->assertEquals( $expected, maybe_unserialize( $value ) ); - } else { - $this->assertSame( $expected, maybe_unserialize( $value ) ); - } - } - - /** - * @dataProvider data_is_serialized - * @dataProvider data_is_not_serialized - */ - public function test_is_serialized( $value, $expected ) { - $this->assertSame( $expected, is_serialized( $value ) ); - } - - /** - * @dataProvider data_serialize_deserialize_objects - */ - public function test_deserialize_request_utility_filtered_iterator_objects( $value ) { - $serialized = maybe_serialize( $value ); - if ( get_class( $value ) === 'Requests_Utility_FilteredIterator' ) { - $new_value = unserialize( $serialized ); - $property = ( new ReflectionClass( 'Requests_Utility_FilteredIterator' ) )->getProperty( 'callback' ); - $property->setAccessible( true ); - $callback_value = $property->getValue( $new_value ); - $this->assertSame( null, $callback_value ); - } else { - $this->assertSame( $value->count(), unserialize( $serialized )->count() ); - } - } - - public function data_serialize_deserialize_objects() { - return array( - array( new Requests_Utility_FilteredIterator( array( 1 ), 'md5' ) ), - array( new Requests_Utility_FilteredIterator( array( 1, 2 ), 'sha1' ) ), - array( new ArrayIterator( array( 1, 2, 3 ) ) ), - ); - } - - public function data_is_serialized() { - return array( - array( serialize( null ), true ), - array( serialize( true ), true ), - array( serialize( false ), true ), - array( serialize( -25 ), true ), - array( serialize( 25 ), true ), - array( serialize( 1.1 ), true ), - array( serialize( 'this string will be serialized' ), true ), - array( serialize( "a\nb" ), true ), - array( serialize( array() ), true ), - array( serialize( array( 1, 1, 2, 3, 5, 8, 13 ) ), true ), - array( - serialize( - (object) array( - 'test' => true, - '3', - 4, - ) - ), - true, - ), - array( ' s:25:"this string is serialized"; ', true ), - ); - } - - public function data_is_not_serialized() { - return array( - array( null, false ), - array( true, false ), - array( false, false ), - array( -25, false ), - array( 25, false ), - array( 1.1, false ), - array( 'this string will be serialized', false ), - array( "a\nb", false ), - array( array(), false ), - array( array( 1, 1, 2, 3, 5, 8, 13 ), false ), - array( - (object) array( - 'test' => true, - '3', - 4, - ), - false, - ), - array( 'a string', false ), - array( 'garbage:a:0:garbage;', false ), - array( 's:4:test;', false ), - ); - } - - /** - * @ticket 46570 - * @dataProvider data_is_serialized_should_return_true_for_large_floats - */ - public function test_is_serialized_should_return_true_for_large_floats( $value ) { - $this->assertTrue( is_serialized( $value ) ); - } - - public function data_is_serialized_should_return_true_for_large_floats() { - return array( - array( serialize( 1.7976931348623157E+308 ) ), - array( serialize( array( 1.7976931348623157E+308, 1.23e50 ) ) ), - ); - } - - /** - * @ticket 17375 - */ - public function test_no_new_serializable_types() { - $this->assertFalse( is_serialized( 'C:16:"Serialized_Class":6:{a:0:{}}' ) ); - } - /** * @group add_query_arg */ diff --git a/tests/phpunit/tests/functions/isSerialized.php b/tests/phpunit/tests/functions/isSerialized.php index 64835085e3..8ecbd5273c 100644 --- a/tests/phpunit/tests/functions/isSerialized.php +++ b/tests/phpunit/tests/functions/isSerialized.php @@ -11,76 +11,197 @@ class Tests_Functions_IsSerialized extends WP_UnitTestCase { /** - * Run tests on `is_serialized()`. - * * @dataProvider data_is_serialized + * @dataProvider data_is_not_serialized * * @param mixed $data Data value to test. * @param bool $expected Expected function result. */ - public function test_is_serialized_string( $data, $expected ) { + public function test_is_serialized( $data, $expected ) { $this->assertSame( $expected, is_serialized( $data ) ); } /** - * Data provider method for testing `is_serialized()`. + * Data provider for `test_is_serialized()`. * * @return array */ public function data_is_serialized() { return array( - 'an array' => array( - 'data' => array(), - 'expected' => false, - ), - 'an object' => array( - 'data' => new stdClass(), - 'expected' => false, - ), - 'a boolean false' => array( - 'data' => false, - 'expected' => false, - ), - 'a boolean true' => array( - 'data' => true, - 'expected' => false, - ), - 'an integer 0' => array( - 'data' => 0, - 'expected' => false, - ), - 'an integer 1' => array( - 'data' => 1, - 'expected' => false, - ), - 'a float 0.0' => array( - 'data' => 0.0, - 'expected' => false, - ), - 'a float 1.0' => array( - 'data' => 1.0, - 'expected' => false, - ), - 'string that is too short' => array( - 'data' => 's:3', - 'expected' => false, - ), - 'not a colon in second position' => array( - 'data' => 's!3:"foo";', - 'expected' => false, - ), - 'no trailing semicolon (strict check)' => array( - 'data' => 's:3:"foo"', - 'expected' => false, - ), - 'valid serialized null' => array( - 'data' => 'N;', + 'serialized empty array' => array( + 'data' => serialize( array() ), 'expected' => true, ), - 'valid serialized Enum' => array( + 'serialized non-empty array' => array( + 'data' => serialize( array( 1, 1, 2, 3, 5, 8, 13 ) ), + 'expected' => true, + ), + 'serialized empty object' => array( + 'data' => serialize( new stdClass() ), + 'expected' => true, + ), + 'serialized non-empty object' => array( + 'data' => serialize( + (object) array( + 'test' => true, + '1', + 2, + ) + ), + 'expected' => true, + ), + 'serialized null' => array( + 'data' => serialize( null ), + 'expected' => true, + ), + 'serialized boolean true' => array( + 'data' => serialize( true ), + 'expected' => true, + ), + 'serialized boolean false' => array( + 'data' => serialize( false ), + 'expected' => true, + ), + 'serialized integer -1' => array( + 'data' => serialize( -1 ), + 'expected' => true, + ), + 'serialized integer 1' => array( + 'data' => serialize( -1 ), + 'expected' => true, + ), + 'serialized float 1.1' => array( + 'data' => serialize( 1.1 ), + 'expected' => true, + ), + 'serialized string' => array( + 'data' => serialize( 'this string will be serialized' ), + 'expected' => true, + ), + 'serialized string with line break' => array( + 'data' => serialize( "a\nb" ), + 'expected' => true, + ), + 'serialized string with leading and trailing spaces' => array( + 'data' => ' s:25:"this string is serialized"; ', + 'expected' => true, + ), + 'serialized enum' => array( 'data' => 'E:7:"Foo:bar";', 'expected' => true, ), ); } + + /** + * Data provider for `test_is_serialized()`. + * + * @return array + */ + public function data_is_not_serialized() { + return array( + 'an empty array' => array( + 'data' => array(), + 'expected' => false, + ), + 'a non-empty array' => array( + 'data' => array( 1, 1, 2, 3, 5, 8, 13 ), + 'expected' => false, + ), + 'an empty object' => array( + 'data' => new stdClass(), + 'expected' => false, + ), + 'a non-empty object' => array( + 'data' => (object) array( + 'test' => true, + '1', + 2, + ), + 'expected' => false, + ), + 'null' => array( + 'data' => null, + 'expected' => false, + ), + 'a boolean true' => array( + 'data' => true, + 'expected' => false, + ), + 'a boolean false' => array( + 'data' => false, + 'expected' => false, + ), + 'an integer -1' => array( + 'data' => -1, + 'expected' => false, + ), + 'an integer 0' => array( + 'data' => 0, + 'expected' => false, + ), + 'an integer 1' => array( + 'data' => 1, + 'expected' => false, + ), + 'a float 0.0' => array( + 'data' => 0.0, + 'expected' => false, + ), + 'a float 1.1' => array( + 'data' => 1.1, + 'expected' => false, + ), + 'a string' => array( + 'data' => 'a string', + 'expected' => false, + ), + 'a string with line break' => array( + 'data' => "a\nb", + 'expected' => false, + ), + 'a string with leading and trailing garbage' => array( + 'data' => 'garbage:a:0:garbage;', + 'expected' => false, + ), + 'a string with missing double quotes' => array( + 'data' => 's:4:test;', + 'expected' => false, + ), + 'a string that is too short' => array( + 'data' => 's:3', + 'expected' => false, + ), + 'not a colon in second position' => array( + 'data' => 's!3:"foo";', + 'expected' => false, + ), + 'no trailing semicolon (strict check)' => array( + 'data' => 's:3:"foo"', + 'expected' => false, + ), + ); + } + + /** + * @ticket 46570 + * @dataProvider data_is_serialized_should_return_true_for_large_floats + */ + public function test_is_serialized_should_return_true_for_large_floats( $value ) { + $this->assertTrue( is_serialized( $value ) ); + } + + public function data_is_serialized_should_return_true_for_large_floats() { + return array( + array( serialize( 1.7976931348623157E+308 ) ), + array( serialize( array( 1.7976931348623157E+308, 1.23e50 ) ) ), + ); + } + + /** + * @ticket 17375 + */ + public function test_no_new_serializable_types() { + $this->assertFalse( is_serialized( 'C:16:"Serialized_Class":6:{a:0:{}}' ) ); + } } diff --git a/tests/phpunit/tests/functions/isSerializedString.php b/tests/phpunit/tests/functions/isSerializedString.php index 78f6860864..f8f33a2c33 100644 --- a/tests/phpunit/tests/functions/isSerializedString.php +++ b/tests/phpunit/tests/functions/isSerializedString.php @@ -31,7 +31,7 @@ class Tests_Functions_IsSerializedString extends WP_UnitTestCase { 'data' => array(), 'expected' => false, ), - 'a class' => array( + 'an object' => array( 'data' => new stdClass(), 'expected' => false, ), diff --git a/tests/phpunit/tests/functions/maybeSerialize.php b/tests/phpunit/tests/functions/maybeSerialize.php new file mode 100644 index 0000000000..104c1b1134 --- /dev/null +++ b/tests/phpunit/tests/functions/maybeSerialize.php @@ -0,0 +1,246 @@ +assertSame( $expected, maybe_serialize( $value ) ); + } + + /** + * @dataProvider data_is_serialized + */ + public function test_maybe_serialize_with_double_serialization( $value ) { + $expected = serialize( $value ); + + $this->assertSame( $expected, maybe_serialize( $value ) ); + } + + /** + * @dataProvider data_is_serialized + * @dataProvider data_is_not_serialized + */ + public function test_maybe_unserialize( $value, $is_serialized ) { + if ( $is_serialized ) { + $expected = unserialize( trim( $value ) ); + } else { + $expected = $value; + } + + if ( is_object( $expected ) ) { + $this->assertEquals( $expected, maybe_unserialize( $value ) ); + } else { + $this->assertSame( $expected, maybe_unserialize( $value ) ); + } + } + + /** + * Data provider for `test_maybe_unserialize()`. + * + * @return array + */ + public function data_is_serialized() { + return array( + 'serialized empty array' => array( + 'data' => serialize( array() ), + 'expected' => true, + ), + 'serialized non-empty array' => array( + 'data' => serialize( array( 1, 1, 2, 3, 5, 8, 13 ) ), + 'expected' => true, + ), + 'serialized empty object' => array( + 'data' => serialize( new stdClass() ), + 'expected' => true, + ), + 'serialized non-empty object' => array( + 'data' => serialize( + (object) array( + 'test' => true, + '1', + 2, + ) + ), + 'expected' => true, + ), + 'serialized null' => array( + 'data' => serialize( null ), + 'expected' => true, + ), + 'serialized boolean true' => array( + 'data' => serialize( true ), + 'expected' => true, + ), + 'serialized boolean false' => array( + 'data' => serialize( false ), + 'expected' => true, + ), + 'serialized integer -1' => array( + 'data' => serialize( -1 ), + 'expected' => true, + ), + 'serialized integer 1' => array( + 'data' => serialize( -1 ), + 'expected' => true, + ), + 'serialized float 1.1' => array( + 'data' => serialize( 1.1 ), + 'expected' => true, + ), + 'serialized string' => array( + 'data' => serialize( 'this string will be serialized' ), + 'expected' => true, + ), + 'serialized string with line break' => array( + 'data' => serialize( "a\nb" ), + 'expected' => true, + ), + 'serialized string with leading and trailing spaces' => array( + 'data' => ' s:25:"this string is serialized"; ', + 'expected' => true, + ), + ); + } + + /** + * Data provider for `test_maybe_serialize()`. + * + * @return array + */ + public function data_is_not_serialized() { + return array( + 'an empty array' => array( + 'data' => array(), + 'expected' => false, + ), + 'a non-empty array' => array( + 'data' => array( 1, 1, 2, 3, 5, 8, 13 ), + 'expected' => false, + ), + 'an empty object' => array( + 'data' => new stdClass(), + 'expected' => false, + ), + 'a non-empty object' => array( + 'data' => (object) array( + 'test' => true, + '1', + 2, + ), + 'expected' => false, + ), + 'null' => array( + 'data' => null, + 'expected' => false, + ), + 'a boolean true' => array( + 'data' => true, + 'expected' => false, + ), + 'a boolean false' => array( + 'data' => false, + 'expected' => false, + ), + 'an integer -1' => array( + 'data' => -1, + 'expected' => false, + ), + 'an integer 0' => array( + 'data' => 0, + 'expected' => false, + ), + 'an integer 1' => array( + 'data' => 1, + 'expected' => false, + ), + 'a float 0.0' => array( + 'data' => 0.0, + 'expected' => false, + ), + 'a float 1.1' => array( + 'data' => 1.1, + 'expected' => false, + ), + 'a string' => array( + 'data' => 'a string', + 'expected' => false, + ), + 'a string with line break' => array( + 'data' => "a\nb", + 'expected' => false, + ), + 'a string with leading and trailing garbage' => array( + 'data' => 'garbage:a:0:garbage;', + 'expected' => false, + ), + 'a string with missing double quotes' => array( + 'data' => 's:4:test;', + 'expected' => false, + ), + 'a string that is too short' => array( + 'data' => 's:3', + 'expected' => false, + ), + 'not a colon in second position' => array( + 'data' => 's!3:"foo";', + 'expected' => false, + ), + 'no trailing semicolon (strict check)' => array( + 'data' => 's:3:"foo"', + 'expected' => false, + ), + ); + } + + /** + * @dataProvider data_serialize_deserialize_objects + */ + public function test_deserialize_request_utility_filtered_iterator_objects( $value ) { + $serialized = maybe_serialize( $value ); + + if ( get_class( $value ) === 'Requests_Utility_FilteredIterator' ) { + $new_value = unserialize( $serialized ); + $property = ( new ReflectionClass( 'Requests_Utility_FilteredIterator' ) )->getProperty( 'callback' ); + $property->setAccessible( true ); + $callback_value = $property->getValue( $new_value ); + + $this->assertSame( null, $callback_value ); + } else { + $this->assertSame( $value->count(), unserialize( $serialized )->count() ); + } + } + + /** + * Data provider for test_deserialize_request_utility_filtered_iterator_objects(). + * + * @return array + */ + public function data_serialize_deserialize_objects() { + return array( + 'filtered iterator using md5' => array( + new Requests_Utility_FilteredIterator( array( 1 ), 'md5' ), + ), + 'filtered iterator using sha1' => array( + new Requests_Utility_FilteredIterator( array( 1, 2 ), 'sha1' ), + ), + 'array iterator' => array( + new ArrayIterator( array( 1, 2, 3 ) ), + ), + ); + } +}