Passed
Pull Request — master (#33)
by Stephan
02:03
created

ProcessorTest::testValidateRawParameters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 2
nc 2
nop 5
1
<?php
2
3
namespace ParamProcessor\Tests;
4
5
use ParamProcessor\ProcessingError;
6
use ParamProcessor\ProcessingResult;
7
use ParamProcessor\Processor;
8
use ParamProcessor\Options;
9
10
/**
11
 * @covers ParamProcessor\Processor
12
 *
13
 * @licence GNU GPL v2+
14
 * @author Jeroen De Dauw < [email protected] >
15
 */
16
class ProcessorTest extends \PHPUnit_Framework_TestCase {
17
18
	public function testNewDefault() {
19
		$this->assertInstanceOf( 'ParamProcessor\Processor', Processor::newDefault() );
20
	}
21
22
	public function newFromOptionsProvider() {
23
		$options = [];
24
25
		$option = new Options();
26
27
		$options[] = clone $option;
28
29
		$option->setName( 'foobar' );
30
		$option->setLowercaseNames( false );
31
32
		$options[] = clone $option;
33
34
		return $this->arrayWrap( $options );
35
	}
36
37
	private function arrayWrap( array $elements ) {
38
		return array_map(
39
			function( $element ) {
40
				return [ $element ];
41
			},
42
			$elements
43
		);
44
	}
45
46
	public function testNewFromOptions() {
47
		$options = new Options();
48
		$validator = Processor::newFromOptions( clone $options );
49
		$this->assertInstanceOf( '\ParamProcessor\Processor', $validator );
50
		$this->assertEquals( $options, $validator->getOptions() );
51
	}
52
53
	/**
54
	 * Simple parameter definitions and values that should all pass.
55
	 *
56
	 * @return array
57
	 */
58
	private function getSimpleParams() {
59
		$params = [
60
			'awesome' => 'yes',
61
			'Howmuch ' => '9001',
62
			'FLOAT' => '4.2',
63
			' page' => 'Ohi there!',
64
			' text     ' => 'foo bar baz o_O',
65
		];
66
67
		$definitions = [
68
			'awesome' => [
69
				'type' => 'boolean',
70
			],
71
			'howmuch' => [
72
				'type' => 'integer',
73
			],
74
			'float' => [
75
				'type' => 'float',
76
			],
77
			'page' => [
78
				'type' => 'string',
79
				'hastoexist' => false,
80
			],
81
			'text' => [],
82
		];
83
84
		$options = new Options();
85
86
		$expected = [
87
			'awesome' => true,
88
			'howmuch' => 9001,
89
			'float' => 4.2,
90
			'page' => 'Ohi there!',
91
			'text' => 'foo bar baz o_O',
92
		];
93
94
		return [ $params, $definitions, $options, $expected ];
95
	}
96
97
	/**
98
	 * Simple parameter definitions with defaults and values
99
	 * that are invalid or missing and therefore default.
100
	 *
101
	 * @return array
102
	 */
103
	private function getDefaultingParams() {
104
		$params = [
105
			'awesome' => 'omg!',
106
			'howmuch' => 'omg!',
107
			'float' => 'omg!',
108
			'page' => 42,
109
			'whot?' => 'O_o',
110
			'integerr' => ' 9001 ',
111
		];
112
113
		$definitions = [
114
			'awesome' => [
115
				'type' => 'boolean',
116
				'default' => true,
117
			],
118
			'howmuch' => [
119
				'type' => 'integer',
120
				'default' => 9001,
121
			],
122
			'float' => [
123
				'type' => 'float',
124
				'default' => 4.2,
125
			],
126
			'page' => [
127
				'type' => 'string',
128
				'hastoexist' => false,
129
				'default' => 'Ohi there!',
130
			],
131
			'text' => [
132
				'default' => 'foo bar baz o_O',
133
			],
134
			'integerr' => [
135
				'type' => 'integer',
136
				'default' => 42,
137
			],
138
		];
139
140
		$options = new Options();
141
		$options->setTrimValues( false );
142
143
		$expected = [
144
			'awesome' => true,
145
			'howmuch' => 9001,
146
			'float' => 4.2,
147
			'page' => 'Ohi there!',
148
			'text' => 'foo bar baz o_O',
149
			'integerr' => 42,
150
		];
151
152
		return [ $params, $definitions, $options, $expected ];
153
	}
154
155
	/**
156
	 * Values and definitions in-system parameter handling.
157
	 * Options set to expect non-raw values.
158
	 *
159
	 * @return array
160
	 */
161
	private function getTypedParams() {
162
		$params = [
163
			'awesome' => true,
164
			'howmuch' => '42',
165
			'float' => 4.2,
166
			'page' => 'Ohi there!',
167
			'Text' => 'foo bar baz o_O',
168
			'text1 ' => 'foo bar baz o_O',
169
			' text2' => 'foo bar baz o_O',
170
		];
171
172
		$definitions = [
173
			'awesome' => [
174
				'type' => 'boolean',
175
			],
176
			'howmuch' => [
177
				'type' => 'integer',
178
				'default' => 9001,
179
			],
180
			'float' => [
181
				'type' => 'float',
182
				'lowerbound' => 9001,
183
				'default' => 9000.1
184
			],
185
			'page' => [
186
				'type' => 'string',
187
				'hastoexist' => false,
188
			],
189
			'text' => [
190
				'default' => 'some text',
191
			],
192
			'text1' => [
193
				'default' => 'some text',
194
			],
195
			'text2' => [
196
				'default' => 'some text',
197
			],
198
		];
199
200
		$options = new Options();
201
		$options->setRawStringInputs( false );
202
		$options->setLowercaseNames( false );
203
		$options->setTrimNames( false );
204
205
		$expected = [
206
			'awesome' => true,
207
			'howmuch' => 9001,
208
			'float' => 9000.1,
209
			'page' => 'Ohi there!',
210
			'text' => 'some text',
211
			'text1' => 'some text',
212
			'text2' => 'some text',
213
		];
214
215
		return [ $params, $definitions, $options, $expected ];
216
	}
217
218
	/**
219
	 * Values with capitalization and preceding/tailing spaces to test
220
	 * of the clean options work.
221
	 *
222
	 * @return array
223
	 */
224
	private function getUncleanParams() {
225
		$params = [
226
			'awesome' => ' yes ',
227
			'text' => ' FOO  bar  ',
228
			'integerr' => ' 9001 ',
229
		];
230
231
		$definitions = [
232
			'awesome' => [
233
				'type' => 'boolean',
234
			],
235
			'text' => [
236
				'default' => 'bar',
237
			],
238
			'integerr' => [
239
				'type' => 'integer',
240
				'default' => 42,
241
			],
242
		];
243
244
		$options = new Options();
245
		$options->setLowercaseValues( true );
246
		$options->setTrimValues( true );
247
248
		$expected = [
249
			'awesome' => true,
250
			'text' => 'foo  bar',
251
			'integerr' => 9001,
252
		];
253
254
		return [ $params, $definitions, $options, $expected ];
255
	}
256
257
	/**
258
	 * List parameters to test if list handling works correctly.
259
	 *
260
	 * @return array
261
	 */
262
	private function getListParams() {
263
		$params = [
264
			'awesome' => ' yes, no, on, off ',
265
			'float' => ' 9001 ; 42 ; 4.2;0',
266
		];
267
268
		$definitions = [
269
			'awesome' => [
270
				'type' => 'boolean',
271
				'islist' => true,
272
			],
273
			'text' => [
274
				'default' => [ 'bar' ],
275
				'islist' => true,
276
			],
277
			'float' => [
278
				'type' => 'float',
279
				'islist' => true,
280
				'delimiter' => ';'
281
			],
282
		];
283
284
		$options = new Options();
285
		$options->setLowercaseValues( true );
286
		$options->setTrimValues( true );
287
288
		$expected = [
289
			'awesome' => [ true, false, true, false ],
290
			'text' => [ 'bar' ],
291
			'float' => [ 9001.0, 42.0, 4.2, 0.0 ],
292
		];
293
294
		return [ $params, $definitions, $options, $expected ];
295
	}
296
297
	/**
298
	 * List parameters to test if list handling works correctly.
299
	 *
300
	 * @return array
301
	 */
302
	private function getPositionalParams() {
303
		$params = [
304
			' foobar ',
305
			' <span class="warning">Foobar!</span>',
306
		];
307
308
		$definitions = [
309
			'hugo' => [
310
				'type' => 'string',
311
			],
312
			'benno' => [
313
				'type' => 'string',
314
			],
315
		];
316
317
		$options = new Options();
318
		$options->setTrimValues( true );
319
320
		$expected = [
321
			'hugo' => 'foobar',
322
			'benno' => '<span class="warning">Foobar!</span>'
323
		];
324
325
		$defaultParams = [ 'hugo', 'benno' ];
326
327
		return [ $params, $definitions, $options, $expected, $defaultParams ];
328
	}
329
330
331
	protected function normalizeArgLists( &$argLists ) {
332
333
		foreach ( $argLists as &$argList ) {
334
			foreach ( $argList[ 1 ] as $key => &$definition ) {
335
				$definition[ 'message' ] = 'test-' . $key;
336
			}
337
338
			if ( !array_key_exists( 2, $argList ) ) {
339
				$argList[ 2 ] = new Options();
340
			}
341
		}
342
	}
343
344
	public function parameterProvider() {
345
		// $params, $definitions [, $options]
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
346
		$argLists = [];
347
348
		$argLists[] = $this->getSimpleParams();
349
350
		$argLists[] = $this->getDefaultingParams();
351
352
		$argLists[] = $this->getTypedParams();
353
354
		$argLists[] = $this->getUncleanParams();
355
356
		$argLists[] = $this->getListParams();
357
358
		$this->normalizeArgLists( $argLists );
359
360
		return $argLists;
361
	}
362
363
	public function rawParameterProvider() {
364
365
		$argLists = [];
366
367
		$argLists[] = $this->getSimpleParams();
368
369
		//$argLists[] = $this->getDefaultingParams();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
370
371
		//$argLists[] = $this->getTypedParams();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
372
373
		$argLists[] = $this->getUncleanParams();
374
375
		$argLists[] = $this->getListParams();
376
377
		$argLists[] = $this->getPositionalParams();
378
379
		// transform into raw parameters
380
		foreach ( $argLists as $i => $argList ) {
381
			$rawParams = [];
382
			foreach ( $argList[0] as $paramName => $paramValue ) {
383
				$rawParams[] = is_string( $paramName )? "$paramName=$paramValue" : $paramValue;
384
			}
385
			$argLists[ $i ][ 0 ] = $rawParams;
386
		}
387
388
		$this->normalizeArgLists( $argLists );
389
390
		return $argLists;
391
	}
392
393
	/**
394
	 * @dataProvider parameterProvider
395
	 */
396
	public function testSetParameters( array $params, array $definitions, Options $options ) {
397
		$validator = Processor::newFromOptions( $options );
398
399
		$validator->setParameters( $params, $definitions );
400
401
		$this->assertTrue( true ); // TODO
402
	}
403
404
	/**
405
	 * @dataProvider parameterProvider
406
	 */
407
	public function testValidateParameters( array $params, array $definitions, Options $options, array $expected = [] ) {
408
		$validator = Processor::newFromOptions( $options );
409
410
		$validator->setParameters( $params, $definitions );
411
412
		$processingResult = $validator->processParameters();
413
414
		$actualValues = [];
415
416
		foreach ( $processingResult->getParameters() as $param ) {
417
			$actualValues[$param->getName()] = $param->getValue();
418
		}
419
420
		$this->assertEquals( $expected, $actualValues );
421
422
423
	}
424
425
	/**
426
	 * @dataProvider rawParameterProvider
427
	 */
428
	public function testValidateRawParameters( array $params, array $definitions, Options $options, array $expected = [],  array $defaultParams = [] ) {
429
		$validator = Processor::newFromOptions( $options );
430
431
		$validator->setFunctionParams( $params, $definitions, $defaultParams );
432
433
		$processingResult = $validator->processParameters();
434
435
		$actualValues = [];
436
437
		foreach ( $processingResult->getParameters() as $param ) {
438
			$actualValues[$param->getName()] = $param->getValue();
439
		}
440
441
		$this->assertEquals( $expected, $actualValues );
442
443
444
	}
445
446
	public function testProcessParametersOnEmptyOptions() {
447
		$processor = Processor::newDefault();
448
449
		$this->assertInstanceOf(
450
			ProcessingResult::class,
451
			$processor->processParameters()
452
		);
453
	}
454
455
	public function testErrorsCanBeRetrievedAfterProcessing() {
456
		$processor = Processor::newDefault();
457
458
		$this->processWithOneError( $processor );
459
460
		$this->assertCount( 1, $processor->getErrors() );
461
	}
462
463
	private function processWithOneError( Processor $processor ) {
464
		$processor->setParameters(
465
			[],
466
			[
0 ignored issues
show
Documentation introduced by
array('awesome' => array...ge' => 'test-awesome')) is of type array<string,array<strin...ssage\":\"string\"}>"}>, but the function expects a array<integer,object<Par...ssor\IParamDefinition>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
467
				'awesome' => [
468
					'type' => 'boolean',
469
					'message' => 'test-awesome'
470
				],
471
			]
472
		);
473
474
		// There should be a single "missing required parameter" error.
475
		$processor->processParameters();
476
	}
477
478
	public function testErrorsAreClearedBetweenProcessingRuns() {
479
		$processor = Processor::newDefault();
480
481
		$this->processWithOneError( $processor );
482
		$processor->setParameters( [], [] );
483
		$processor->processParameters();
484
485
		$this->assertEmpty( $processor->getErrors() );
486
	}
487
488
}
489