Completed
Push — master ( 2d69df...961a56 )
by mw
17:40
created

getPermittedSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
3
namespace SMW\Scribunto\Integration\JSONScript;
4
5
use SMW\DIWikiPage;
6
use SMW\Scribunto\HookRegistry;
7
use SMW\Tests\JsonTestCaseFileHandler;
8
use SMW\Tests\JsonTestCaseScriptRunner;
9
use SMW\Tests\Utils\Validators\SemanticDataValidator;
10
use SMW\Tests\Utils\Validators\StringValidator;
11
12
13
/**
14
 * @see https://github.com/SemanticMediaWiki/SemanticMediaWiki/tree/master/tests#write-integration-tests-using-json-script
15
 *
16
 * `JsonTestCaseScriptRunner` provisioned by SMW is a base class allowing to use a JSON
17
 * format to create test definitions with the objective to compose "real" content
18
 * and test integration with MediaWiki, Semantic MediaWiki, and Scribunto.
19
 *
20
 * The focus is on describing test definitions with its content and specify assertions
21
 * to control the expected base line.
22
 *
23
 * `JsonTestCaseScriptRunner` will handle the tearDown process and ensures that no test
24
 * data are leaked into a production system but requires an active DB connection.
25
 *
26
 * @group semantic-scribunto
27
 * @group medium
28
 *
29
 * @license GNU GPL v2+
30
 * @since 1.0
31
 *
32
 * @author mwjames
33
 */
34
class SemanticScribuntoJsonTestCaseScriptRunnerTest extends JsonTestCaseScriptRunner {
35
36
	/**
37
	 * @var SemanticDataValidator
38
	 */
39
	private $semanticDataValidator;
40
41
	/**
42
	 * @var StringValidator
43
	 */
44
	private $stringValidator;
45
46
	/**
47
	 * @var HookRegistry
48
	 */
49
	private $hookRegistry;
50
51
	protected function setUp() {
52
		parent::setUp();
53
54
		$validatorFactory = $this->testEnvironment->getUtilityFactory()->newValidatorFactory();
55
56
		$this->semanticDataValidator = $validatorFactory->newSemanticDataValidator();
57
		$this->stringValidator = $validatorFactory->newStringValidator();
58
59
		$this->hookRegistry = new HookRegistry();
60
61
		$this->hookRegistry->clear();
62
		$this->hookRegistry->register();
63
	}
64
65
	/**
66
	 * @see JsonTestCaseScriptRunner::getRequiredJsonTestCaseMinVersion
67
	 * @return string
68
	 */
69
	protected function getRequiredJsonTestCaseMinVersion() {
70
		return '1';
71
	}
72
73
	/**
74
	 * @see JsonTestCaseScriptRunner::getTestCaseLocation
75
	 * @return string
76
	 */
77
	protected function getTestCaseLocation() {
78
		return __DIR__ . '/TestCases';
79
	}
80
81
	/**
82
	 * Returns a list of files, an empty list is a sign to run all registered
83
	 * tests.
84
	 *
85
	 * @see JsonTestCaseScriptRunner::getListOfAllowedTestCaseFiles
86
	 */
87
	protected function getAllowedTestCaseFiles() {
88
		return [];
89
	}
90
91
	/**
92
	 * @see JsonTestCaseScriptRunner::getPermittedSettings
93
	 */
94
	protected function getPermittedSettings() {
95
		parent::getPermittedSettings();
96
97
		return [
98
			'smwgNamespacesWithSemanticLinks',
99
			'smwgPageSpecialProperties',
100
			'smwgMaxNonExpNumber',
101
			'wgLanguageCode',
102
			'wgContLang',
103
			'wgLang'
104
		];
105
	}
106
107
	/**
108
	 * @see JsonTestCaseScriptRunner::runTestCaseFile
109
	 *
110
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
111
	 */
112
	protected function runTestCaseFile( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
113
114
		$this->checkEnvironmentToSkipCurrentTest( $jsonTestCaseFileHandler );
115
116
		// Setup
117
		$this->prepareTest( $jsonTestCaseFileHandler );
118
119
		// Run test cases
120
		$this->doRunParserTests( $jsonTestCaseFileHandler );
121
	}
122
123
	/**
124
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
125
	 */
126
	private function doRunParserTests( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
127
128
		foreach ( $jsonTestCaseFileHandler->findTestCasesByType( 'parser' ) as $case ) {
129
130
			if ( !isset( $case['subject'] ) ) {
131
				break;
132
			}
133
134
			// Assert function are defined individually by each TestCaseRunner
135
			// to ensure a wide range of scenarios can be supported.
136
			$this->assertSemanticDataForCase( $case, $jsonTestCaseFileHandler->getDebugMode() );
137
			$this->assertParserOutputForCase( $case );
138
		}
139
	}
140
141
	/**
142
	 * Prepares the test case: setting of global configuration changes (json section "settings",
143
	 * creation of defined pages (json section "setup")
144
	 *
145
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
146
	 */
147
	private function prepareTest( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
148
149
		// Defines settings that can be altered during a test run with each test
150
		// having the possibility to change those values, settings will be reset to
151
		// the original value (from before the test) after the test has finished.
152
		foreach ( $this->getPermittedSettings() as $key ) {
153
			$this->changeGlobalSettingTo(
154
				$key,
155
				$jsonTestCaseFileHandler->getSettingsFor( $key, $this->getConfigValueCallback( $key ) )
156
			);
157
		}
158
159
		$this->createPagesFrom(
160
			$jsonTestCaseFileHandler->getPageCreationSetupList(),
161
			NS_MAIN
162
		);
163
	}
164
165
	/**
166
	 * Assert the SemanticData object if available after a entity/page has been
167
	 * created.
168
	 *
169
	 * ```
170
	 * "assert-store": {
171
	 *    "semantic-data": {
172
	 *        "strictPropertyValueMatch": false,
173
	 *        "propertyCount": 4,
174
	 *        "propertyKeys": [
175
	 *            "Testproperty1",
176
	 *            "Testproperty2",
177
	 *            "_SKEY",
178
	 *            "_MDAT"
179
	 *        ],
180
	 *        "propertyValues": [
181
	 *            "200"
182
	 *        ],
183
	 *     "inproperty-keys": [
184
	 *         "roperty1",
185
	 *         "EY",
186
	 *     ],
187
	 *     "inproperty-values": [
188
	 *         "Test Ca",
189
	 *         "00",
190
	 *     ]
191
	 * }
192
	 * ```
193
	 * @param array $case
194
	 * @param bool $debugMode
195
	 */
196
	private function assertSemanticDataForCase( array $case, $debugMode ) {
197
198
		// Allows for data to be re-read from the DB instead of being fetched
199
		// from the store-id-cache
200
		if ( isset( $case['store']['clear-cache'] ) && $case['store']['clear-cache'] ) {
201
			$this->getStore()->clear();
202
		}
203
204
		if ( !isset( $case['assert-store'] ) || !isset( $case['assert-store']['semantic-data'] ) ) {
205
			return;
206
		}
207
208
		$subject = DIWikiPage::newFromText(
209
			$case['subject'],
210
			isset( $case['namespace'] ) ? constant( $case['namespace'] ) : NS_MAIN
211
		);
212
213
		/** @var \SMW\SemanticData $semanticData */
214
		$semanticData = $this->getStore()->getSemanticData( $subject );
215
216
		if ( $debugMode ) {
217
			print_r( $semanticData );
218
		}
219
220
		if ( isset( $case['errors'] ) && $case['errors'] !== [] ) {
221
			$this->assertNotEmpty(
222
				$semanticData->getErrors()
223
			);
224
		}
225
226
		$this->semanticDataValidator->assertThatPropertiesAreSet(
227
			$case['assert-store']['semantic-data'],
228
			$semanticData,
229
			$case['about']
230
		);
231
232
		$this->assertInProperties(
233
			$subject,
234
			$case['assert-store']['semantic-data'],
235
			$case['about']
236
		);
237
	}
238
239
	/**
240
	 * Assert the text content if available from the parse process and
241
	 * accessible using the ParserOutput object.
242
	 *
243
	 * ```
244
	 * "assert-output": {
245
	 * 	"to-contain": [
246
	 * 		"Foo"
247
	 * 	],
248
	 * 	"not-contain": [
249
	 * 		"Bar"
250
	 * 	]
251
	 * }
252
	 * ```
253
	 * @param array $case
254
	 */
255
	private function assertParserOutputForCase( array $case ) {
256
257
		if ( !isset( $case['assert-output'] ) ) {
258
			return;
259
		}
260
261
		$subject = DIWikiPage::newFromText(
262
			$case['subject'],
263
			isset( $case['namespace'] ) ? constant( $case['namespace'] ) : NS_MAIN
264
		);
265
266
		/** @var \ParserOutput $parserOutput */
267
		$parserOutput = $this->testEnvironment->getUtilityFactory()->newPageReader()->getEditInfo( $subject->getTitle() )->output;
0 ignored issues
show
Bug introduced by
It seems like $subject->getTitle() can be null; however, getEditInfo() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
268
269
		if ( isset( $case['assert-output']['to-contain'] ) ) {
270
			$this->stringValidator->assertThatStringContains(
271
				$case['assert-output']['to-contain'],
272
				$parserOutput->getText(),
273
				$case['about']
274
			);
275
		}
276
277
		if ( isset( $case['assert-output']['not-contain'] ) ) {
278
			$this->stringValidator->assertThatStringNotContains(
279
				$case['assert-output']['not-contain'],
280
				$parserOutput->getText(),
281
				$case['about']
282
			);
283
		}
284
	}
285
286
	/**
287
	 * @param DIWikiPage $subject
288
	 * @param array $semanticdata
289
	 * @param string $about
290
	 */
291
	private function assertInProperties( DIWikiPage $subject, array $semanticdata, $about ) {
292
293
		if ( !isset( $semanticdata['inproperty-keys'] ) ) {
294
			return;
295
		}
296
297
		$inProperties = $this->getStore()->getInProperties( $subject );
298
299
		$this->assertCount(
300
			count( $semanticdata['inproperty-keys'] ),
301
			$inProperties,
302
			'Failed asserting count for "inproperty-keys" in ' . $about . ' ' . implode( ',', $inProperties )
303
		);
304
305
		$inpropertyValues = [];
306
307
		/** @var \SMW\DIProperty $property */
308
		foreach ( $inProperties as $property ) {
309
310
			$this->assertContains(
311
				$property->getKey(),
312
				$semanticdata['inproperty-keys'],
313
				'Failed asserting key for "inproperty-keys" in ' . $about
314
			);
315
316
			if ( !isset( $semanticdata['inproperty-values'] ) ) {
317
				continue;
318
			}
319
320
			$values = $this->getStore()->getPropertySubjects( $property, $subject );
321
322
			foreach ( $values as $value ) {
323
				$inpropertyValues[] = $value->getSerialization();
324
			}
325
		}
326
327
		foreach ( $inpropertyValues as $value ) {
328
			$this->assertContains(
329
				$value,
330
				$semanticdata['inproperty-values'],
331
				'Failed asserting values for "inproperty-values" in ' . $about
332
			);
333
		}
334
	}}
335