<commit_before><?php
/**
 * Compare our Schemas against the official definition to detect any improper nesting.
 *
 * @package Schemify
 */

namespace Test\Schemas;

use ReflectionMethod;
use WP_UnitTestCase;

/**
 * Test Schemify's Schema definitions against the official specification.
 *
 * @group schemaDefinitions
 */
class SchemaInheritanceTest extends WP_UnitTestCase {

	/**
	 * Log the names of any missing Schema definitions.
	 *
	 * @var array
	 */
	protected static $missingSchemas = [];

	/**
	 * Defines how long data should be cached before being updated (90 days).
	 *
	 * The cache can manually be purged by emptying the tests/data/ directory.
	 *
	 * @var int
	 */
	const CACHE_LIFETIME = 7776000;

	/**
	 * Verify that a Schema has the appropriate *direct* parent.
	 *
	 * @dataProvider schemaInheritanceProvider
	 *
	 * @param string      $schema The schema name.
	 * @param string|null $parent The schema's direct parent name, or NULL in the case of "Thing".
	 */
	public function testSchemaInheritance( $schema, $parent ) {

		// Verify that the Schema exists first, otherwise skip the test.
		if ( ! class_exists( 'Schemify\\Schemas\\' . $schema ) ) {
			self::$missingSchemas[] = $schema;
			$this->markTestSkipped( sprintf( 'The %s Schema is not defined.', $schema ) );
		}

		// Ensure the Schema's direct parent matches $parent.
		if ( null !== $parent ) {
			$this->assertEquals(
				'Schemify\\Schemas\\' . $parent,
				get_parent_class( '\\Schemify\\Schemas\\' . $schema ),
				sprintf( 'According to the specification, %1$s should extend %2$s.', $schema, $parent )
			);
		}
	}

	/**
	 * Compile an array of all known Schemas, along with their direct parent.
	 *
	 * Each entry in the array will have the format:
	 *
	 *     $schema => [ $schema, $parent ]
	 *
	 * @return array
	 */
	public function schemaInheritanceProvider() {
		$definitions = $this->getData( 'schema-definitions.json', 'https://schema.org/docs/tree.jsonld' );

		$schemas = array_reduce( $definitions->children, [ $this, 'getDirectParent' ], [
			'Thing' => [ 'Thing', null ],
		] );

		ksort( $schemas );

		return $schemas;
	}

	/**
	 * Iterate through each Schema and verify that all properties are accounted for.
	 *
	 * @dataProvider definedSchemaNameProvider()
	 *
	 * @param string $schema The schema name.
	 */
	public function testSchemaProperties( $schema ) {
		$definition = $this->getData( $schema . '.json', 'https://schema.org/' . $schema . '.jsonld' );

		// Return early if there's no @graph definition.
		if ( ! isset( $definition->{'@graph'} ) ) {
			$this->markTestSkipped( sprintf( 'There are no properties defined for the %s schema.', $schema ) );
		}

		// Iterate through the properties defined in the Schema definition.
		$props = array_reduce( $definition->{'@graph'}, function ( $props, $entry ) {
			if (
				isset( $entry->{'@type'}, $entry->{'rdfs:label'} )
				&& 'rdf:Property' === $entry->{'@type'}
				&& ! isset( $entry->{'schema:isPartOf'} )
			) {
				$props[] = is_object( $entry->{'rdfs:label'} ) ? $entry->{'rdfs:label'}->{'@value'} : $entry->{'rdfs:label'};
			}

			return $props;
		}, [] );

		// Construct an instance of the Schema to work against.
		$class    = 'Schemify\\Schemas\\' . $schema;
		$instance = new $class( 1, true );
		$propList = new ReflectionMethod( $instance, 'getPropertyList' );
		$propList->setAccessible( true );

		// Compare the specification against what the Schema class is reporting.<commit_msg>Don't warn about missing properties that have been superseded<commit_after><?php
/**
 * Compare our Schemas against the official definition to detect any improper nesting.
 *
 * @package Schemify
 */

namespace Test\Schemas;

use ReflectionMethod;
use WP_UnitTestCase;

/**
 * Test Schemify's Schema definitions against the official specification.
 *
 * @group schemaDefinitions
 */
class SchemaInheritanceTest extends WP_UnitTestCase {

	/**
	 * Log the names of any missing Schema definitions.
	 *
	 * @var array
	 */
	protected static $missingSchemas = [];

	/**
	 * Defines how long data should be cached before being updated (90 days).
	 *
	 * The cache can manually be purged by emptying the tests/data/ directory.
	 *
	 * @var int
	 */
	const CACHE_LIFETIME = 7776000;

	/**
	 * Verify that a Schema has the appropriate *direct* parent.
	 *
	 * @dataProvider schemaInheritanceProvider
	 *
	 * @param string      $schema The schema name.
	 * @param string|null $parent The schema's direct parent name, or NULL in the case of "Thing".
	 */
	public function testSchemaInheritance( $schema, $parent ) {

		// Verify that the Schema exists first, otherwise skip the test.
		if ( ! class_exists( 'Schemify\\Schemas\\' . $schema ) ) {
			self::$missingSchemas[] = $schema;
			$this->markTestSkipped( sprintf( 'The %s Schema is not defined.', $schema ) );
		}

		// Ensure the Schema's direct parent matches $parent.
		if ( null !== $parent ) {
			$this->assertEquals(
				'Schemify\\Schemas\\' . $parent,
				get_parent_class( '\\Schemify\\Schemas\\' . $schema ),
				sprintf( 'According to the specification, %1$s should extend %2$s.', $schema, $parent )
			);
		}
	}

	/**
	 * Compile an array of all known Schemas, along with their direct parent.
	 *
	 * Each entry in the array will have the format:
	 *
	 *     $schema => [ $schema, $parent ]
	 *
	 * @return array
	 */
	public function schemaInheritanceProvider() {
		$definitions = $this->getData( 'schema-definitions.json', 'https://schema.org/docs/tree.jsonld' );

		$schemas = array_reduce( $definitions->children, [ $this, 'getDirectParent' ], [
			'Thing' => [ 'Thing', null ],
		] );

		ksort( $schemas );

		return $schemas;
	}

	/**
	 * Iterate through each Schema and verify that all properties are accounted for.
	 *
	 * @dataProvider definedSchemaNameProvider()
	 *
	 * @param string $schema The schema name.
	 */
	public function testSchemaProperties( $schema ) {
		$definition = $this->getData( $schema . '.json', 'https://schema.org/' . $schema . '.jsonld' );

		// Return early if there's no @graph definition.
		if ( ! isset( $definition->{'@graph'} ) ) {
			$this->markTestSkipped( sprintf( 'There are no properties defined for the %s schema.', $schema ) );
		}

		// Iterate through the properties defined in the Schema definition.
		$props = array_reduce( $definition->{'@graph'}, function ( $props, $entry ) {
			if (
				isset( $entry->{'@type'}, $entry->{'rdfs:label'} )
				&& 'rdf:Property' === $entry->{'@type'}
				&& empty( $entry->{'schema:isPartOf'} )
				&& empty( $entry->{'schema:supersededBy'} )
			) {
				$props[] = is_object( $entry->{'rdfs:label'} ) ? $entry->{'rdfs:label'}->{'@value'} : $entry->{'rdfs:label'};
			}

			return $props;
		}, [] );

		// Construct an instance of the Schema to work against.
		$class    = 'Schemify\\Schemas\\' . $schema;
		$instance = new $class( 1, true );
		$propList = new ReflectionMethod( $instance, 'getPropertyList' );
		$propList->setAccessible( true );

		// Compare the specification against what the Schema class is reporting.
{'fraction_non_alphanumeric': 0.14955928348023884, 'fraction_numerical': 0.0034119988626670457, 'mean_word_length': 3.416195856873823, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 42, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2220306', 'n_tokens_mistral': 2382, 'n_tokens_neox': 2130, 'n_words': 663}