Completed
Push — master ( c7e919...48c1e9 )
by mw
07:53
created

runTestCaseFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 10
rs 9.4285
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 array();
89
	}
90
91
	/**
92
	 * @see JsonTestCaseScriptRunner::runTestCaseFile
93
	 *
94
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
95
	 */
96
	protected function runTestCaseFile( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
97
98
		$this->checkEnvironmentToSkipCurrentTest( $jsonTestCaseFileHandler );
99
100
		// Setup
101
		$this->prepareTest( $jsonTestCaseFileHandler );
102
103
		// Run test cases
104
		$this->doRunParserTests( $jsonTestCaseFileHandler );
105
	}
106
107
	/**
108
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
109
	 */
110
	private function doRunParserTests( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
111
112
		foreach ( $jsonTestCaseFileHandler->findTestCasesByType( 'parser' ) as $case ) {
113
114
			if ( !isset( $case['subject'] ) ) {
115
				break;
116
			}
117
118
			// Assert function are defined individually by each TestCaseRunner
119
			// to ensure a wide range of scenarios can be supported.
120
			$this->assertSemanticDataForCase( $case, $jsonTestCaseFileHandler->getDebugMode() );
121
			$this->assertParserOutputForCase( $case );
122
		}
123
	}
124
125
	/**
126
	 * Prepares the test case: setting of global configuration changes (json section "settings",
127
	 * creation of defined pages (json section "setup")
128
	 *
129
	 * @param JsonTestCaseFileHandler $jsonTestCaseFileHandler
130
	 */
131
	private function prepareTest( JsonTestCaseFileHandler $jsonTestCaseFileHandler ) {
132
133
		// Defines settings that can be altered during a test run with each test
134
		// having the possibility to change those values, settings will be reset to
135
		// the original value (from before the test) after the test has finished.
136
		$permittedSettings = array(
137
			'smwgNamespacesWithSemanticLinks',
138
			'smwgPageSpecialProperties',
139
			'smwgMaxNonExpNumber',
140
			'wgLanguageCode',
141
			'wgContLang',
142
			'wgLang'
143
		);
144
145
		foreach ( $permittedSettings as $key ) {
146
			$this->changeGlobalSettingTo(
147
				$key,
148
				$jsonTestCaseFileHandler->getSettingsFor( $key )
149
			);
150
		}
151
152
		$this->createPagesFrom(
153
			$jsonTestCaseFileHandler->getPageCreationSetupList(),
154
			NS_MAIN
155
		);
156
	}
157
158
	/**
159
	 * Assert the SemanticData object if available after a entity/page has been
160
	 * created.
161
	 *
162
	 * ```
163
	 * "assert-store": {
164
	 *    "semantic-data": {
165
	 *        "strictPropertyValueMatch": false,
166
	 *        "propertyCount": 4,
167
	 *        "propertyKeys": [
168
	 *            "Testproperty1",
169
	 *            "Testproperty2",
170
	 *            "_SKEY",
171
	 *            "_MDAT"
172
	 *        ],
173
	 *        "propertyValues": [
174
	 *            "200"
175
	 *        ],
176
	 *     "inproperty-keys": [
177
	 *         "roperty1",
178
	 *         "EY",
179
	 *     ],
180
	 *     "inproperty-values": [
181
	 *         "Test Ca",
182
	 *         "00",
183
	 *     ]
184
	 * }
185
	 * ```
186
	 * @param array $case
187
	 * @param bool $debugMode
188
	 */
189
	private function assertSemanticDataForCase( array $case, $debugMode ) {
190
191
		// Allows for data to be re-read from the DB instead of being fetched
192
		// from the store-id-cache
193
		if ( isset( $case['store']['clear-cache'] ) && $case['store']['clear-cache'] ) {
194
			$this->getStore()->clear();
195
		}
196
197
		if ( !isset( $case['assert-store'] ) || !isset( $case['assert-store']['semantic-data'] ) ) {
198
			return;
199
		}
200
201
		$subject = DIWikiPage::newFromText(
202
			$case['subject'],
203
			isset( $case['namespace'] ) ? constant( $case['namespace'] ) : NS_MAIN
204
		);
205
206
		/** @var \SMW\SemanticData $semanticData */
207
		$semanticData = $this->getStore()->getSemanticData( $subject );
208
209
		if ( $debugMode ) {
210
			print_r( $semanticData );
211
		}
212
213
		if ( isset( $case['errors'] ) && $case['errors'] !== array() ) {
214
			$this->assertNotEmpty(
215
				$semanticData->getErrors()
216
			);
217
		}
218
219
		$this->semanticDataValidator->assertThatPropertiesAreSet(
220
			$case['assert-store']['semantic-data'],
221
			$semanticData,
222
			$case['about']
223
		);
224
225
		$this->assertInProperties(
226
			$subject,
227
			$case['assert-store']['semantic-data'],
228
			$case['about']
229
		);
230
	}
231
232
	/**
233
	 * Assert the text content if available from the parse process and
234
	 * accessible using the ParserOutput object.
235
	 *
236
	 * ```
237
	 * "assert-output": {
238
	 * 	"to-contain": [
239
	 * 		"Foo"
240
	 * 	],
241
	 * 	"not-contain": [
242
	 * 		"Bar"
243
	 * 	]
244
	 * }
245
	 * ```
246
	 * @param array $case
247
	 */
248
	private function assertParserOutputForCase( array $case ) {
249
250
		if ( !isset( $case['assert-output'] ) ) {
251
			return;
252
		}
253
254
		$subject = DIWikiPage::newFromText(
255
			$case['subject'],
256
			isset( $case['namespace'] ) ? constant( $case['namespace'] ) : NS_MAIN
257
		);
258
259
		/** @var \ParserOutput $parserOutput */
260
		$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...
261
262
		if ( isset( $case['assert-output']['to-contain'] ) ) {
263
			$this->stringValidator->assertThatStringContains(
264
				$case['assert-output']['to-contain'],
265
				$parserOutput->getText(),
266
				$case['about']
267
			);
268
		}
269
270
		if ( isset( $case['assert-output']['not-contain'] ) ) {
271
			$this->stringValidator->assertThatStringNotContains(
272
				$case['assert-output']['not-contain'],
273
				$parserOutput->getText(),
274
				$case['about']
275
			);
276
		}
277
	}
278
279
	/**
280
	 * @param DIWikiPage $subject
281
	 * @param array $semanticdata
282
	 * @param string $about
283
	 */
284
	private function assertInProperties( DIWikiPage $subject, array $semanticdata, $about ) {
285
286
		if ( !isset( $semanticdata['inproperty-keys'] ) ) {
287
			return;
288
		}
289
290
		$inProperties = $this->getStore()->getInProperties( $subject );
291
292
		$this->assertCount(
293
			count( $semanticdata['inproperty-keys'] ),
294
			$inProperties,
295
			'Failed asserting count for "inproperty-keys" in ' . $about . ' ' . implode( ',', $inProperties )
296
		);
297
298
		$inpropertyValues = array();
299
300
		/** @var \SMW\DIProperty $property */
301
		foreach ( $inProperties as $property ) {
302
303
			$this->assertContains(
304
				$property->getKey(),
305
				$semanticdata['inproperty-keys'],
306
				'Failed asserting key for "inproperty-keys" in ' . $about
307
			);
308
309
			if ( !isset( $semanticdata['inproperty-values'] ) ) {
310
				continue;
311
			}
312
313
			$values = $this->getStore()->getPropertySubjects( $property, $subject );
314
315
			foreach ( $values as $value ) {
316
				$inpropertyValues[] = $value->getSerialization();
317
			}
318
		}
319
320
		foreach ( $inpropertyValues as $value ) {
321
			$this->assertContains(
322
				$value,
323
				$semanticdata['inproperty-values'],
324
				'Failed asserting values for "inproperty-values" in ' . $about
325
			);
326
		}
327
	}}
328