Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / structure / AbstractSchemaTestBase.php
blobf1c6638c34c3ecb274e0a8463704fb97bc90d04b
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
19 namespace MediaWiki\Tests\Structure;
21 use Doctrine\SqlFormatter\NullHighlighter;
22 use Doctrine\SqlFormatter\SqlFormatter;
23 use Generator;
24 use MediaWiki\DB\AbstractSchemaValidationError;
25 use MediaWiki\DB\AbstractSchemaValidator;
26 use MediaWiki\Maintenance\SchemaGenerator;
27 use MediaWikiIntegrationTestCase;
29 /**
30 * Validates all abstract schemas against the abstract-schema schemas in the docs/ folder, and makes sure that
31 * they match the autogenerated output.
33 * Extensions can extend this class, implementing its abstract methods, to validate their DB schemas.
35 abstract class AbstractSchemaTestBase extends MediaWikiIntegrationTestCase {
36 private AbstractSchemaValidator $validator;
38 protected function setUp(): void {
39 parent::setUp();
41 $this->validator = new AbstractSchemaValidator();
44 /**
45 * @dataProvider provideSchemas
46 * @param string $path Path to tables.json file
48 public function testSchemaIsValid( string $path ): void {
49 try {
50 $this->validator->validate( $path );
51 // All good
52 $this->addToAssertionCount( 1 );
53 } catch ( AbstractSchemaValidationError $e ) {
54 $this->fail( "The abstract schema in $path is not valid: " . $e->getMessage() );
58 /**
59 * @dataProvider provideSchemaChanges
60 * @param string $path Path to the schema change JSON file
62 public function testSchemaChangesAreValid( string $path ): void {
63 try {
64 $this->validator->validate( $path );
65 // All good
66 $this->addToAssertionCount( 1 );
67 } catch ( AbstractSchemaValidationError $e ) {
68 $this->fail( "The abstract schema change in $path is not valid: " . $e->getMessage() );
72 /**
73 * @dataProvider provideSchemas
75 public function testSchemasHaveAutoGeneratedFiles( string $jsonPath ) {
76 $jsonName = basename( $jsonPath );
77 // Same as SchemaMaintenance::getSqlPathWithFileName()
78 $nameReplacement = str_starts_with( $jsonName, 'tables' ) ? '-generated.sql' : '.sql';
79 $expectedSQLName = str_replace( '.json', $nameReplacement, $jsonName );
81 foreach ( static::getSchemaSQLDirs() as $platform => $dir ) {
82 $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
83 $realSQLPath = realpath( $expectedSQLPath );
84 $this->assertFileExists(
85 $expectedSQLPath,
86 "Schema file $realSQLPath for $platform not found. Generate it using generateSchemaSql.php."
88 $actualSQL = file_get_contents( $expectedSQLPath );
89 $expectedSQL = ( new SchemaGenerator() )->generateSchema( $platform, $jsonPath );
90 $this->assertSQLSame(
91 $expectedSQL,
92 $actualSQL,
93 "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
94 "using generateSchemaSql.php."
99 /**
100 * @dataProvider provideSchemaChanges
102 public function testSchemaChangesHaveAutoGeneratedFiles( string $jsonPath ) {
103 $expectedSQLName = str_replace( '.json', '.sql', basename( $jsonPath ) );
105 $foundOne = false;
106 foreach ( static::getSchemaChangesSQLDirs() as $platform => $dir ) {
107 $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
108 if ( !file_exists( $expectedSQLPath ) ) {
109 // Schema changes don't necessarily have to exist for all platforms. One is enough.
110 continue;
112 $foundOne = true;
113 $actualSQL = file_get_contents( $expectedSQLPath );
114 $expectedSQL = ( new SchemaGenerator() )->generateSchemaChange( $platform, $jsonPath );
115 $realSQLPath = realpath( $expectedSQLPath );
116 $this->assertSQLSame(
117 $expectedSQL,
118 $actualSQL,
119 "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
120 "using generateSchemaChangeSql.php."
123 $realJSONPath = realpath( $jsonPath );
124 $this->assertTrue(
125 $foundOne,
126 "Did not find SQL files for any platforms for schema change $realJSONPath. Generate them using " .
127 "generateSchemaChangeSql.php."
132 * Asserts that two SQL strings are identical, modulo formatting (whitespace) differences. We can't just compare
133 * the raw output, otherwise changing the format would be massively painful due to test failures everywhere.
135 private function assertSQLSame( string $expected, string $actual, string $message ): void {
136 $formatter = new SqlFormatter( new NullHighlighter() );
137 $this->assertSame(
138 $formatter->format( $expected ),
139 $formatter->format( $actual ),
140 $message
144 final public static function provideSchemas(): Generator {
145 $schemaDir = rtrim( static::getSchemasDirectory(), '/' ) . '/';
146 foreach ( glob( $schemaDir . '*.json' ) as $schemaFile ) {
147 yield basename( $schemaFile ) => [ $schemaFile ];
151 final public static function provideSchemaChanges(): Generator {
152 $schemaChangesDir = rtrim( static::getSchemaChangesDirectory(), '/' ) . '/';
153 foreach ( glob( $schemaChangesDir . '*.json' ) as $schemaChange ) {
154 yield basename( $schemaChange ) => [ $schemaChange ];
159 * Returns the path to a directory with JSON files for the schema. All JSON files in this directory are assumed
160 * to be schema files and tested accordingly.
162 abstract protected static function getSchemasDirectory(): string;
165 * Returns the path to a directory with schema change JSON files. All JSON files in this directory are assumed
166 * to be schema change files and tested accordingly.
168 abstract protected static function getSchemaChangesDirectory(): string;
171 * Returns a map of supported DB types to the path of a directory with the .sql files for that DB type's schema.
173 abstract protected static function getSchemaSQLDirs(): array;
176 * Returns a map of supported DB types to the path of a directory with the .sql schema change files for that DB
177 * type. Uses the same directory as {@see self::getSchemaSQLDirs} by default.
179 protected static function getSchemaChangesSQLDirs(): array {
180 return static::getSchemaSQLDirs();