Skip to content

Commit 48c2ae3

Browse files
committed
Ruleset::setSniffProperty(): add BC-layer for old format property values
This commit adds a BC layer to handle property values passed to `Ruleset::setSniffProperty()` in the old (mixed) format. This BC-layer will never be hit when PHPCS is used from the CLI/with a ruleset. This BC-layer is only in place for integrations with PHPCS which may call the `Ruleset::setSniffProperty()` method directly. The `Ruleset::setSniffProperty()` will still handle properties passed in the old format correctly, but will also throw a deprecation notice to allow the maintainers of the integration to update their code. Includes dedicated tests to ensure this BC-layer works as intended. Note: this commit should **NOT** be ported to PHPCS 4.x.
1 parent 3b093de commit 48c2ae3

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

src/Ruleset.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,34 @@ public function setSniffProperty($sniffClass, $name, $settings)
13191319
$propertyName = substr($propertyName, 0, -2);
13201320
}
13211321

1322+
/*
1323+
* BC-compatibility layer for $settings using the pre-PHPCS 3.8.0 format.
1324+
*
1325+
* Prior to PHPCS 3.8.0, `$settings` was expected to only contain the new _value_
1326+
* for the property (which could be an array).
1327+
* Since PHPCS 3.8.0, `$settings` is expected to be an array with two keys: 'scope'
1328+
* and 'value', where 'scope' indicates whether the property should be set to the given 'value'
1329+
* for one individual sniff or for all sniffs in a standard.
1330+
*
1331+
* This BC-layer is only for integrations with PHPCS which may call this method directly
1332+
* and will be removed in PHPCS 4.0.0.
1333+
*/
1334+
1335+
if (is_array($settings) === false
1336+
|| isset($settings['scope'], $settings['value']) === false
1337+
) {
1338+
// This will be an "old" format value.
1339+
$settings = [
1340+
'value' => $settings,
1341+
'scope' => 'standard',
1342+
];
1343+
1344+
trigger_error(
1345+
__FUNCTION__.': the format of the $settings parameter has changed from (mixed) $value to array(\'scope\' => \'sniff|standard\', \'value\' => $value). Please update your integration code. See PR #3629 for more information.',
1346+
E_USER_DEPRECATED
1347+
);
1348+
}
1349+
13221350
$isSettable = false;
13231351
$sniffObject = $this->sniffs[$sniffClass];
13241352
if (property_exists($sniffObject, $propertyName) === true

tests/Core/Ruleset/SetSniffPropertyTest.php

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,184 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCateg
230230
}//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory()
231231

232232

233+
/**
234+
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
235+
* sets the property correctly when using the new $settings array format.
236+
*
237+
* @return void
238+
*/
239+
public function testDirectCallWithNewArrayFormatSetsProperty()
240+
{
241+
$name = 'SetPropertyAllowedAsDeclared';
242+
$sniffCode = "Fixtures.Category.{$name}";
243+
$sniffClass = 'Fixtures\Sniffs\Category\\'.$name.'Sniff';
244+
245+
// Set up the ruleset.
246+
$standard = __DIR__."/{$name}Test.xml";
247+
$config = new Config(["--standard=$standard"]);
248+
$ruleset = new Ruleset($config);
249+
250+
$propertyName = 'arbitrarystring';
251+
$propertyValue = 'new value';
252+
253+
$ruleset->setSniffProperty(
254+
$sniffClass,
255+
$propertyName,
256+
[
257+
'scope' => 'sniff',
258+
'value' => $propertyValue,
259+
]
260+
);
261+
262+
// Verify that the sniff has been registered.
263+
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
264+
265+
// Verify that our target sniff has been registered.
266+
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered');
267+
$this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class');
268+
269+
// Test that the property as declared in the ruleset has been set on the sniff.
270+
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs');
271+
272+
$sniffObject = $ruleset->sniffs[$sniffClass];
273+
$this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value');
274+
275+
}//end testDirectCallWithNewArrayFormatSetsProperty()
276+
277+
278+
/**
279+
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
280+
* sets the property correctly when using the old $settings array format.
281+
*
282+
* Tested by silencing the deprecation notice as otherwise the test would fail on the deprecation notice.
283+
*
284+
* @param mixed $propertyValue Value for the property to set.
285+
*
286+
* @dataProvider dataDirectCallWithOldArrayFormatSetsProperty
287+
*
288+
* @return void
289+
*/
290+
public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue)
291+
{
292+
$name = 'SetPropertyAllowedAsDeclared';
293+
$sniffCode = "Fixtures.Category.{$name}";
294+
$sniffClass = 'Fixtures\Sniffs\Category\\'.$name.'Sniff';
295+
296+
// Set up the ruleset.
297+
$standard = __DIR__."/{$name}Test.xml";
298+
$config = new Config(["--standard=$standard"]);
299+
$ruleset = new Ruleset($config);
300+
301+
$propertyName = 'arbitrarystring';
302+
303+
@$ruleset->setSniffProperty(
304+
$sniffClass,
305+
$propertyName,
306+
$propertyValue
307+
);
308+
309+
// Verify that the sniff has been registered.
310+
$this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered');
311+
312+
// Verify that our target sniff has been registered.
313+
$this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered');
314+
$this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class');
315+
316+
// Test that the property as declared in the ruleset has been set on the sniff.
317+
$this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs');
318+
319+
$sniffObject = $ruleset->sniffs[$sniffClass];
320+
$this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value');
321+
322+
}//end testDirectCallWithOldArrayFormatSetsProperty()
323+
324+
325+
/**
326+
* Data provider.
327+
*
328+
* @see self::testDirectCallWithOldArrayFormatSetsProperty()
329+
*
330+
* @return array
331+
*/
332+
public function dataDirectCallWithOldArrayFormatSetsProperty()
333+
{
334+
return [
335+
'Property value is not an array (boolean)' => [false],
336+
'Property value is not an array (string)' => ['a string'],
337+
'Property value is an empty array' => [[]],
338+
'Property value is an array without keys' => [
339+
[
340+
'value',
341+
false,
342+
],
343+
],
344+
'Property value is an array without the "scope" or "value" keys' => [
345+
[
346+
'key1' => 'value',
347+
'key2' => false,
348+
],
349+
],
350+
'Property value is an array without the "scope" key' => [
351+
[
352+
'key1' => 'value',
353+
'value' => true,
354+
],
355+
],
356+
'Property value is an array without the "value" key' => [
357+
[
358+
'scope' => 'value',
359+
'key2' => 1234,
360+
],
361+
],
362+
];
363+
364+
}//end dataDirectCallWithOldArrayFormatSetsProperty()
365+
366+
367+
/**
368+
* Test that setting a property via a direct call to the Ruleset::setSniffProperty() method
369+
* throws a deprecation notice when using the old $settings array format.
370+
*
371+
* Note: as PHPUnit stops as soon as it sees the deprecation notice, the setting of the property
372+
* value is not tested here.
373+
*
374+
* @return void
375+
*/
376+
public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice()
377+
{
378+
$exceptionClass = 'PHPUnit\Framework\Error\Deprecated';
379+
if (class_exists($exceptionClass) === false) {
380+
$exceptionClass = 'PHPUnit_Framework_Error_Deprecated';
381+
}
382+
383+
$exceptionMsg = 'the format of the $settings parameter has changed from (mixed) $value to array(\'scope\' => \'sniff|standard\', \'value\' => $value). Please update your integration code. See PR #3629 for more information.';
384+
385+
if (method_exists($this, 'expectException') === true) {
386+
$this->expectException($exceptionClass);
387+
$this->expectExceptionMessage($exceptionMsg);
388+
} else {
389+
// PHPUnit < 5.2.0.
390+
$this->setExpectedException($exceptionClass, $exceptionMsg);
391+
}
392+
393+
$name = 'SetPropertyAllowedAsDeclared';
394+
$sniffCode = "Fixtures.Category.{$name}";
395+
$sniffClass = 'Fixtures\Sniffs\Category\\'.$name.'Sniff';
396+
397+
// Set up the ruleset.
398+
$standard = __DIR__."/{$name}Test.xml";
399+
$config = new Config(["--standard=$standard"]);
400+
$ruleset = new Ruleset($config);
401+
402+
$propertyName = 'arbitrarystring';
403+
404+
$ruleset->setSniffProperty(
405+
$sniffClass,
406+
'arbitrarystring',
407+
['key' => 'value']
408+
);
409+
410+
}//end testDirectCallWithOldArrayFormatThrowsDeprecationNotice()
411+
412+
233413
}//end class

0 commit comments

Comments
 (0)