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
This commit is contained in:
Sergey Biryukov 2022-08-13 12:09:41 +00:00
parent c45ea397da
commit d1e22dbad8
4 changed files with 419 additions and 198 deletions

View File

@ -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
*/

View File

@ -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:{}}' ) );
}
}

View File

@ -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,
),

View File

@ -0,0 +1,246 @@
<?php
/**
* Tests for `maybe_serialize()` and `maybe_unserialize()`.
*
* @group functions.php
* @covers ::maybe_serialize
* @covers ::maybe_unserialize
*/
class Tests_Functions_MaybeSerialize extends WP_UnitTestCase {
/**
* @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 ) );
}
}
/**
* 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 ) ),
),
);
}
}