diff --git a/.gitignore b/.gitignore
index 4b8618d..6d5bb10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ util/
mybuild
mytest
myrun
+.phpunit.result.cache
diff --git a/VariableAnalysis/Tests/Constraint/ArrayMatchesMessages.php b/VariableAnalysis/Tests/Constraint/ArrayMatchesMessages.php
new file mode 100644
index 0000000..b143cd4
--- /dev/null
+++ b/VariableAnalysis/Tests/Constraint/ArrayMatchesMessages.php
@@ -0,0 +1,161 @@
+
+ * $line = 2;
+ * $column = 10;
+ * [
+ * $line => [
+ * $column => [
+ * [
+ * 'message' => 'Unused function parameter $foo.',
+ * 'source' => 'VariableAnalysis.VariableAnalysis.VariableAnalysis.UnusedVariable',
+ * 'listener' => 'VariableAnalysis\Sniffs\VariableAnalysis\VariableAnalysisSniff',
+ * 'severity' => 5,
+ * 'fixable' => false
+ * ],
+ * ]
+ * ]
+ * ]
+ *
+ */
+class ArrayMatchesMessages extends \PHPUnit\Framework\Constraint\Constraint
+{
+ /**
+ * Expected messages as a list of [line, column, message]
+ *
+ * e.g.:
+ *
+ *
+ * $line = 2;
+ * $column = 10;
+ * [
+ * [$line, $column, 'Unused function parameter $foo.'],
+ * ]
+ *
+ *
+ * @var array Expected messages
+ */
+ private $messages;
+
+ /**
+ * Constructor
+ *
+ * @param array $messages Expected list of messages as [line, column, message]
+ */
+ public function __construct($messages)
+ {
+ parent::__construct();
+ $this->messages = $this->normaliseExpectedMessages($messages);
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @return string
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return 'matches expected messages' . PHP_EOL . $this->exporter->export($this->messages);
+ }
+
+ /**
+ * Evaluates the constraint for parameter $actual.
+ *
+ * @param array $actual PHPCodeSniffer warnings or errors list.
+ *
+ * @return bool True if all messages match, false otherwise.
+ */
+ protected function matches($actual): bool
+ {
+ if (!\is_array($actual)) {
+ return false;
+ }
+
+ $actualMessages = $this->extractMessages($actual);
+
+ if (\array_keys($actualMessages) != \array_keys($this->messages)) {
+ return false;
+ }
+ foreach ($actualMessages as $line => $actualLine) {
+ $expectedLine = $this->messages[$line];
+ if (\array_keys($actualLine) != \array_keys($expectedLine)) {
+ return false;
+ }
+
+ foreach ($actualLine as $column => $actualColumn) {
+ $expectedColumn = $expectedLine[$column];
+ if ($actualColumn != $expectedColumn) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the description of the failure
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $actual Evaluated warnings or errors from a PHPCodeSniffer file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($actual): string
+ {
+ $actualMessages = $this->extractMessages($actual);
+ return $this->exporter->export($actualMessages) . ' ' . $this->toString();
+ }
+
+ private function extractMessages($actual)
+ {
+ $extractedMessages = [];
+ foreach ($actual as $line => $lineMessages) {
+ $extractedMessages[$line] = [];
+ foreach ($lineMessages as $column => $columnMessages) {
+ $sortedMessages = array_map(
+ function ($item) {
+ return $item['message'];
+ },
+ $columnMessages
+ );
+ sort($sortedMessages);
+ $extractedMessages[$line][$column] = $sortedMessages;
+ }
+ }
+ return $extractedMessages;
+ }
+
+ private function normaliseExpectedMessages($messages) {
+ $result = [];
+ foreach ($messages as $line => $lineMessages) {
+ $result[$line] = [];
+ foreach ($lineMessages as $column => $columnMessages) {
+ $sortedMessages = array_values($columnMessages);
+ sort($sortedMessages);
+ $result[$line][$column] = $sortedMessages;
+ }
+ }
+ return $result;
+ }
+}
diff --git a/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.inc b/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.inc
deleted file mode 100644
index 253a0ea..0000000
--- a/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.inc
+++ /dev/null
@@ -1,466 +0,0 @@
- $value1) {
- echo "$key1 => $value1\n";
- }
- echo "$key1 => $value1\n";
- foreach ($array as $key2 => &$value2) {
- echo "$key2 => $value2\n";
- }
- echo "$key2 => $value2\n";
- foreach ($array as $element3) {
- }
- foreach ($array as &$element4) {
- }
- foreach ($array as $key3 => $value3) {
- }
- foreach ($array as $key4 => &$value4) {
- }
-}
-
-function function_with_defined_foreach() {
- $array = array();
- foreach ($array as $element1) {
- echo $element1;
- }
- echo $element1;
- foreach ($array as &$element2) {
- echo $element2;
- }
- echo $element2;
- foreach ($array as $key1 => $value1) {
- echo "$key1 => $value1\n";
- }
- echo "$key1 => $value1\n";
- foreach ($array as $key2 => &$value2) {
- echo "$key2 => $value2\n";
- }
- echo "$key2 => $value2\n";
- foreach ($array as $element3) {
- }
- foreach ($array as &$element4) {
- }
- foreach ($array as $key3 => $value3) {
- }
- foreach ($array as $key4 => &$value4) {
- }
-}
-
-class ClassWithoutMembers {
- function method_without_param() {
- echo $var;
- echo "xxx $var xxx";
- echo "xxx {$var} xxx";
- echo "xxx $var $var2 xxx";
- echo "xxx {$var} {$var2} xxx";
- func($var);
- func(12, $var);
- func($var, 12);
- func(12, $var, 12);
- $var = 'set the var';
- echo $var;
- echo "xxx $var xxx";
- echo "xxx {$var} xxx";
- echo "xxx $var $var2 xxx";
- echo "xxx {$var} {$var2} xxx";
- func($var);
- func(12, $var);
- func($var, 12);
- func(12, $var, 12);
- $this->method_with_member_var();
- return $var;
- }
-
- function method_with_param($param) {
- echo $param;
- echo "xxx $param xxx";
- echo "xxx {$param} xxx";
- $param = 'set the param';
- echo $param;
- echo "xxx $param xxx";
- echo "xxx {$param} xxx";
- $this->method_with_member_var();
- return $param;
- }
-
- function method_with_member_var() {
- echo $this->member_var;
- echo self::$static_member_var;
- }
-}
-
-class ClassWithMembers {
- public $member_var;
- static $static_member_var;
-
- function method_with_member_var() {
- echo $this->member_var;
- echo $this->no_such_member_var;
- echo self::$static_member_var;
- echo self::$no_such_static_member_var;
- echo SomeOtherClass::$external_static_member_var;
- }
-}
-
-function function_with_this_outside_class() {
- return $this->whatever();
-}
-
-function function_with_static_members_outside_class() {
- echo SomeOtherClass::$external_static_member_var;
- return self::$whatever;
-}
-
-function function_with_late_static_binding_outside_class() {
- echo static::$whatever;
-}
-
-function function_with_closure($outer_param) {
- $outer_var = 1;
- $outer_var2 = 2;
- array_map(function ($inner_param) {
- $inner_var = 1;
- echo $outer_param;
- echo $inner_param;
- echo $outer_var;
- echo $outer_var2;
- echo $inner_var;
- }, array());
- array_map(function () use ($outer_var, $outer_var3, &$outer_param) {
- $inner_var2 = 2;
- echo $outer_param;
- echo $inner_param;
- echo $outer_var;
- echo $outer_var2;
- echo $outer_var3;
- echo $inner_var;
- echo $inner_var2;
- }, array());
- echo $outer_var;
- echo $outer_var2;
- echo $outer_var3;
- echo $inner_param;
- echo $inner_var;
- echo $inner_var2;
-}
-
-function &function_with_return_by_reference_and_param($param) {
- echo $param;
- return $param;
-}
-
-function function_with_static_var() {
- static $static1, $static_num = 12, $static_neg_num = -1.5, $static_string = 'abc', $static_string2 = "def", $static_define = MYDEFINE, $static_constant = MyClass::CONSTANT, $static2;
- static $static_heredoc = <<$property = 'some value';
- $this -> $property = 'some value';
- $this->$undefined_property = 'some value';
- $this -> $undefined_property = 'some value';
- }
- }
-
- function method_with_symbolic_ref_method() {
- $methods = array('method_with_symbolic_ref_property');
- foreach ($methods as $method) {
- $this->$method();
- $this -> $method();
- $this->$undefined_method();
- $this -> $undefined_method();
- }
- }
-}
-
-function function_with_pass_by_ref_assign_only_arg(&$return_value) {
- $return_value = 42;
-}
-
-class ClassWithLateStaticBinding {
- static function method_with_late_static_binding($param) {
- static::some_method($param);
- static::some_method($var);
- static::some_method(static::CONSTANT, $param);
- }
-}
-
-function function_with_literal_compact($param1, $param2, $param3, $param4) {
- $var1 = 'value1';
- $var2 = 'value2';
- $var4 = 'value4';
- $squish = compact('var1');
- $squish = compact('var3');
- $squish = compact('param1');
- $squish = compact('var2', 'param3');
- $squish = compact(array('var4'), array('param4', 'var5'));
- echo $squish;
-}
-
-function function_with_expression_compact($param1, $param2, $param3, $param4) {
- $var1 = "value1";
- $var2 = "value2";
- $var4 = "value4";
- $var6 = "value6";
- $var7 = "value7";
- $var8 = "value8";
- $var9 = "value9";
- $squish = compact("var1");
- $squish = compact("var3");
- $squish = compact("param1");
- $squish = compact("var2", "param3");
- $squish = compact(array("var4"), array("param4", "var5"));
- $squish = compact($var6);
- $squish = compact("var" . "7");
- $squish = compact("blah $var8");
- $squish = compact("$var9");
- echo $squish;
-}
diff --git a/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.php b/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.php
index 2be4db9..18acabc 100644
--- a/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.php
+++ b/VariableAnalysis/Tests/VariableAnalysis/VariableAnalysisUnitTest.php
@@ -2,7 +2,15 @@
namespace VariableAnalysis\Tests\VariableAnalysis;
-use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;
+use VariableAnalysis\Tests\Constraint\ArrayMatchesMessages;
+use VariableAnalysis\Tests\Constraint\ContainsMessage;
+use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Exceptions\RuntimeException;
+use PHP_CodeSniffer\Files\DummyFile;
+use PHP_CodeSniffer\Files\File;
+use PHP_CodeSniffer\Ruleset;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Util\InvalidArgumentHelper;
/**
* Unit test class for the VariableAnalysis sniff.
@@ -20,267 +28,1395 @@
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
-class VariableAnalysisUnitTest extends AbstractSniffUnitTest
+class VariableAnalysisUnitTest extends TestCase
{
- private function _getWarningAndErrorList()
- {
- // This is a maintainence nightmare.
- // Value of a line is either:
- // - an int: the number of warnings.
- // - an array: the number of warnings and number of errors.
- // This is chosen because we mostly warn and because maintaining _two_
- // separate lists of line numbers would drive me insane.
- //
- // All the fiddling with $base is to make each line number relative
- // to the line number of the function the line is in, which in turn
- // is relative to the line number of the previous function.
- //
- // This makes adding new tests only moderately painful rather than
- // a total clusterfuck of alterations.
- $base = 0;
- return [
- // function_without_param() line (+3)
- ($base += 3) => [0, 0],
- ($base + 1) => [0, 1], // $var
- ($base + 2) => [0, 1], // $var
- ($base + 3) => [0, 1], // {$var}
- ($base + 4) => [0, 1], // ${var}
- ($base + 5) => [0, 2], // $var $var2
- ($base + 6) => [0, 2], // $var $var2
- ($base + 7) => [0, 1], // $var
- ($base + 8) => [0, 1], // $var
- ($base + 9) => [0, 1], // $var
- ($base + 10) => [0, 1], // $var
- ($base + 15) => [0, 1], // $var2
- ($base + 16) => [0, 1], // $var2
- // function_with_param() line (+24)
- // no warnings.
- ($base += 24) => 0,
- // function_with_default_defined_param() line (+11)
- ($base += 11) => 0,
- ($base + 0) => 1, // $unused
- // function_with_default_null_param() line (+11)
- ($base += 11) => 0,
- ($base + 0) => 1, // $unused
- // function_with_global_var() line (+11)
- ($base += 11) => 0,
- ($base + 1) => 1, // $unused
- ($base + 4) => [0,1], // $var3
- // function_with_undefined_foreach() line (+8)
- ($base += 8) => 0,
- ($base + 1) => [0, 1], // $array
- ($base + 5) => [0, 1], // $array
- ($base + 9) => [0, 1], // $array
- ($base + 13) => [0, 1], // $array
- ($base + 17) => [1, 1], // $array, $element3
- ($base + 19) => [1, 1], // $array, $element4
- ($base + 21) => [2, 1], // $array, $key3, $value4
- ($base + 23) => [2, 1], // $array, $key4, $value4
- // function_with_defined_foreach() line (+27)
- ($base += 27) => 0,
- ($base + 18) => 1, // $element3
- ($base + 20) => 1, // $element4
- ($base + 22) => 2, // $key3, $value4
- ($base + 24) => 2, // $key4, $value4
- // ClassWithoutMembers->method_without_param() line (+29)
- ($base += 29) => 0,
- ($base + 1) => [0, 1], // $var
- ($base + 2) => [0, 1], // $var
- ($base + 3) => [0, 1], // $var
- ($base + 4) => [0, 2], // $var $var2
- ($base + 5) => [0, 2], // $var $var2
- ($base + 6) => [0, 1], // $var
- ($base + 7) => [0, 1], // $var
- ($base + 8) => [0, 1], // $var
- ($base + 9) => [0, 1], // $var
- ($base + 14) => [0, 1], // $var2
- ($base + 15) => [0, 1], // $var2
- // ClassWithoutMembers->method_with_param() line (+24)
- // no warnings.
- ($base += 24) => 0,
- // ClassWithoutMembers->method_with_member_var() line (+12)
- // no warnings.
- // We can't/don't inspect the class inheritence so we can't
- // determine that these are undeclared:
- // $this->member_var
- // self::$static_member_var
- ($base += 12) => 0,
- ($base + 1) => [0, 1], // $this->member_var
- //FIXME: should we check that
- //($base + 1) => [0, 1], // self::$static_member_var
- // ClassWithMembers->method_with_member_var() line (+10)
- // no warnings.
- // We can't/don't inspect the class inheritence so we can't
- // determine that these are undeclared:
- // $this->no_such_member_var
- // self::$no_such_static_member_var
- ($base += 10) => 0,
- //FIXME: Static meber var is actually used?
- //($base + 1) => [0, 1], // static $static_member_var;
- ($base + 2) => [0, 1], // $this->no_such_member_var
- // function_with_this_outside_class() line (+9)
- ($base += 9) => 0,
- ($base + 1) => [0, 1], // $this
- // function_with_static_members_outside_class() line (+4)
- ($base += 4) => 0,
- ($base + 2) => array(0, 1), // self::$whatever
- // function_with_late_static_binding_outside_class() line (+5)
- ($base += 5) => 0,
- ($base + 1) => array(0, 1), // static::$whatever
- // function_with_closure() line (+4)
- ($base += 4) => 0,
- ($base + 5) => [0, 1], // $outer_param
- ($base + 7) => [0, 1], // $outer_var
- ($base + 8) => [0, 1], // $outer_var2
- ($base + 11) => [0, 1], // $outer_var3
- ($base + 14) => [0, 1], // $inner_param
- ($base + 16) => [0, 1], // $outer_var2
- ($base + 17) => [0, 1], // $outer_var3
- ($base + 18) => [0, 1], // $inner_var
- ($base + 23) => [0, 1], // $outer_var3
- ($base + 24) => [0, 1], // $inner_param
- ($base + 25) => [0, 1], // $inner_var
- ($base + 26) => [0, 1], // $inner_var2
- // function_with_return_by_reference_and_param() line (+29)
- // no warnings.
- ($base += 29) => 0,
- // function_with_static_var() line (+5)
- ($base += 5) => 0,
- ($base + 1) => 5, // $static_neg_num, $static_string, $static_string2,
- // $static_define, $static_constant
- ($base + 13) => [0, 1], // $var
- // function_with_pass_by_reference_param() line (+20)
- // no warnings.
- ($base += 20) => 0,
- // function_with_pass_by_reference_calls() line (+4)
- ($base += 4) => 0,
- ($base + 1) => [0, 1], // $matches
- ($base + 2) => [0, 1], // $needle
- ($base + 3) => [0, 1], // $haystack
- ($base + 5) => [0, 1], // $needle
- ($base + 6) => [0, 1], // $haystack
- ($base + 8) => [0, 1], // $needle
- ($base + 9) => [0, 1], // $haystack
- ($base + 15) => [0, 1], // $var3
- // function_with_try_catch() line (+22)
- ($base += 22) => 0,
- ($base + 1) => [0, 1], // $e
- ($base + 5) => [0, 1], // $e
- // ClassWithThisInsideClosure->method_with_this_inside_closure() line (+16)
- ($base += 16) => 0,
- ($base + 3) => 1, // $inner_param
- ($base + 4) => 0, // $this - fine with ongoing PHP
- ($base + 5) => 0, // $this - fine with ongoing PHP
- // ClassWithSelfInsideClosure->method_with_self_inside_closure() line (+15)
- ($base += 15) => 0,
- ($base + 3) => 0, // $self::$static_member
- // function_with_inline_assigns() line (+9)
- ($base += 9) => 0,
- ($base + 1) => [0, 1], // $var
- ($base + 4) => [0, 1], // $var2
- // function_with_global_redeclarations() line (+11)
- ($base += 11) => 0,
- ($base + 5) => 1, // $bound
- ($base + 12) => 1, // $param
- ($base + 13) => 1, // $static
- ($base + 14) => 1, // $bound
- ($base + 15) => 1, // $local
- ($base + 16) => 1, // $e
- // function_with_static_redeclarations() line (+19)
- ($base += 19) => 0,
- ($base + 2) => 1, // $static
- ($base + 5) => 1, // $bound
- ($base + 12) => 1, // $param
- ($base + 13) => 1, // $static
- ($base + 14) => 1, // $bound
- ($base + 15) => 1, // $local
- ($base + 16) => 1, // $e
- // function_with_catch_redeclarations() line (+19)
- // no warnings.
- ($base += 19) => 0,
- // function_with_superglobals() line (+11)
- ($base += 11) => 0,
- ($base + 11) => [0, 1], // $var
- // function_with_heredoc() line (+14)
- ($base += 14) => 0,
- ($base + 6) => [0, 1], // $var2
- ($base + 7) => [0, 1], // {$var2}
- ($base + 8) => [0, 1], // ${var2}
- ($base + 10) => [0, 1], // \\$var2
- // method_with_symbolic_ref_property() line (+17)
- ($base += 17) => 0,
- ($base + 5) => [0, 1], // $undefined_property
- ($base + 6) => [0, 1], // $undefined_property
- // method_with_symbolic_ref_method() line (+8)
- ($base += 10) => 0,
- ($base + 5) => [0, 1], // $undefined_method
- ($base + 6) => [0, 1], // $undefined_method
- // function_with_pass_by_ref_assign_only_arg() line (+11)
- // no warnings.
- ($base += 11) => 0,
- // method_with_late_static_binding() line (+5)
- ($base += 5) => 0,
- ($base + 2) => [0, 1], // $var
- // function_with_single_quoted_compact() line (+7)
- ($base += 7) => 0,
- ($base + 0) => 1, // unused $param2
- ($base + 5) => [0, 1], // undefined $var3
- ($base + 8) => [0, 1], // undefined $var5
- // function_with_expression_compact() line (+12)
- ($base += 12) => 0,
- ($base + 0) => 1, // unused $param2
- ($base + 5) => 1, // unused $var7
- ($base + 9) => [0, 1], // undefined $var3
- ($base + 12) => [0, 1], // undefined $var5
- ];
+ // FIXME: These static variables are used but not detected.
+ // phpcs:disable VariableAnalysis.VariableAnalysis.VariableAnalysis.UnusedVariable
+ private static Config $config;
+ private static array $savedConfigSettings;
+ // phpcs:enable
+
+ /**
+ * Setup config for this sniff.
+ *
+ * @beforeClass
+ *
+ * @return void
+ */
+ public static function setUpBeforeClass() {
+ $config = new Config();
+ $config->standards = ['VariableAnalysis'];
+ $config->sniffs = ['VariableAnalysis.VariableAnalysis.VariableAnalysis'];
+ self::$config = $config;
}
/**
- * Returns the lines where errors should occur.
+ * Setup per test case.
*
- * The key of the array should represent the line number and the value
- * should represent the number of errors that should occur on that line.
+ * @before
*
- * @return array(int => int)
- */
- public function getErrorList()
- {
- $errorList = array();
- foreach ($this->_getWarningAndErrorList() as $line => $incidents) {
- $errors = null;
- if (is_array($incidents)) {
- list ($warnings, $errors) = $incidents;
- }
- if (!empty($errors)) {
- $errorList[$line] = $errors;
- }
+ * @return void
+ */
+ public function setUp() {
+ self::$savedConfigSettings = self::$config->getSettings();
+ }
+
+ /**
+ * Teardown per test.
+ *
+ * @after
+ *
+ * @return void
+ */
+ public function tearDown() {
+ self::$config->setSettings(self::$savedConfigSettings);
+ }
+
+ /**
+ * Create a dummy file for code under test
+ *
+ * @param string $contents Contents of code snippet under test.
+ *
+ * @return PHPCodeSniffer\Files\DummyFile
+ */
+ private function dummyFile($contents) {
+ $ruleset = new Ruleset(self::$config);
+ $dummyFile = new DummyFile($contents, $ruleset, self::$config);
+ try {
+ $dummyFile->process();
+ } catch (RuntimeException $e) {
+ $this->fail('Error processing dummy file: ' . $e->getMessage());
}
- return $errorList;
+ return $dummyFile;
}
/**
- * Returns the lines where warnings should occur.
+ * Insert code before and after assignment to variable(s)
*
- * The key of the array should represent the line number and the value
- * should represent the number of warnings that should occur on that line.
+ * @param string $template Surrounding code to insert into. BEFORE and
+ * AFTER markers show where to insert $code such
+ * that it is before and after the assignment
+ * respectively.
+ * @param string $code The code to insert in place of the BEFORE and
+ * AFTER markers.
*
- * @return array(int => int)
- */
- public function getWarningList()
- {
- $warningList = array();
- foreach ($this->_getWarningAndErrorList() as $line => $incidents) {
- $warnings = null;
- if (is_array($incidents)) {
- list ($warnings, $errors) = $incidents;
- } else {
- $warnings = $incidents;
- }
- if (!empty($warnings)) {
- $warningList[$line] = $warnings;
+ * @return [string] The result of inserting $code before and after
+ * respectively, i.e. [$before, $after]
+ */
+ private function insertBeforeAndAfter($template, $code) {
+ $beforeAssign = str_replace(
+ 'AFTER', '', str_replace('BEFORE', $code, $template)
+ );
+ $afterAssign = str_replace(
+ 'AFTER', $code, str_replace('BEFORE', '', $template)
+ );
+
+ return [$beforeAssign, $afterAssign];
+ }
+
+ /**
+ * Assert file warnings match the expected messages on given lines.
+ *
+ * @param PHPCodeSniffer\Files\File $file File under test.
+ * @param array $expected Expected warnings, each as [line, column, message]
+ * @param string $desc Additional description for the assertion.
+ */
+ private function assertWarningsMatch(File $file, $expected, $desc = '') {
+ $desc = $desc == '' ? $desc : ' ' . $desc;
+ if (!\is_array($expected)) {
+ throw InvalidArgumentHelper::factory(2, 'array');
+ }
+
+ $constraint = new ArrayMatchesMessages($expected);
+ $this->assertThat($file->getWarnings(), $constraint, 'warnings' . $desc);
+ }
+
+ /**
+ * Assert file errors match the expected messages on given lines.
+ *
+ * @param PHPCodeSniffer\Files\File $file File under test.
+ * @param array $expected Expected errors, each as [line, column, message]
+ * @param string $desc Additional description for the assertion.
+ */
+ private function assertErrorsMatch(File $file, $expected, $desc = '') {
+ $desc = $desc == '' ? $desc : ' ' . $desc;
+ if (!\is_array($expected)) {
+ throw InvalidArgumentHelper::factory(2, 'array');
+ }
+
+ $constraint = new ArrayMatchesMessages($expected);
+ $this->assertThat($file->getErrors(), $constraint, 'errors' . $desc);
+ }
+
+ /**
+ * Add line and column offset to expected messages.
+ *
+ * @param array $expectedMessages List of expected messages
+ * @param int $line Offset to code line.
+ * @param int $column Offset to code column.
+ *
+ * @return array expectedMessages with offsets applied.
+ */
+ private function offset($expectedMessages, $line, $column) {
+ $result = [];
+ foreach ($expectedMessages as $y => $lineMessages) {
+ $result[$y + $line] = [];
+ foreach ($lineMessages as $x => $columnMessages) {
+ $result[$y + $line][$x + $column] = $columnMessages;
}
}
- return $warningList;
+ return $result;
+ }
+
+ /**
+ * Test checks for use of undefined variables in function with no parameters.
+ *
+ * @param string $code Code snippet under test
+ * @param array $errorsBefore Expected errors before $var is assigned.
+ * @param array $errorsAfter Optional. Expected errors after $var is
+ * assigned. Defaults to []
+ *
+ * @dataProvider dataUndefinedVar
+ *
+ * @return void
+ */
+ public function testFunctionNoParams($code, $errorsBefore, $errorsAfter = []) {
+ $template = <<<'CODE'
+insertBeforeAndAfter($template, $code);
+
+ $beforeFile = $this->dummyFile($beforeAssign);
+ $this->assertWarningsMatch($beforeFile, [], 'before assign');
+ $this->assertErrorsMatch($beforeFile, $this->offset($errorsBefore, 2, 4), 'before assign');
+
+ $afterFile = $this->dummyFile($afterAssign);
+ $this->assertWarningsMatch($afterFile, [], 'after assign');
+ $this->assertErrorsMatch($afterFile, $this->offset($errorsAfter, 4, 4), 'after assign');
+ }
+
+ /**
+ * Data provider for undefined variable sniff in function without param.
+ *
+ * @see testFunctionNoParams()
+ * @see testClassNoMembersMethodNoParams()
+ *
+ * @return array
+ */
+ public function dataUndefinedVar() {
+ return [
+ [
+ 'echo $var;',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'echo "xxx $var xxx";',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'echo "xxx {$var} xxx";',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'echo "xxx ${var} xxx";',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'echo "xxx $var $var2 xxx";',
+ [
+ 1 => [
+ 6 => [
+ 'Variable $var is undefined.',
+ 'Variable $var2 is undefined.'
+ ],
+ ],
+ ],
+ [
+ 1 => [ 6 => ['Variable $var2 is undefined.'] ],
+ ],
+ ],
+ [
+ 'echo "xxx {$var} {$var2} xxx";',
+ [
+ 1 => [
+ 6 => [
+ 'Variable $var is undefined.',
+ 'Variable $var2 is undefined.'
+ ],
+ ],
+ ],
+ [
+ 1 => [ 6 => ['Variable $var2 is undefined.'] ],
+ ],
+ ],
+ [
+ 'func($var);',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'func(12, $var);',
+ [
+ 1 => [ 10 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'func($var, 12);',
+ [
+ 1 => [ 6 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ [
+ 'func(12, $var, 12);',
+ [
+ 1 => [ 10 => ['Variable $var is undefined.'] ],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Test checks for use of undefined variables in function with parameter.
+ *
+ * @return void
+ */
+ public function testFunctionWithParam() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks for unused variables in function with default param.
+ *
+ * @return void
+ */
+ public function testFunctionWithDefaultDefinedParam() {
+ $code = <<<'CODE'
+dummyFile($code);
+
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 2 => [ 46 => ['Unused function parameter $unused.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for unused variables in function with default null param.
+ *
+ * @return void
+ */
+ public function testFunctionWithDefaultNullParam() {
+ $code = <<<'CODE'
+dummyFile($code);
+
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 2 => [ 43 => ['Unused function parameter $unused.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for unused / undefined variables in function with global vars.
+ *
+ * @return void
+ */
+ public function testFunctionWithGlobalVars() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 3 => [ 25 => ['Unused global variable $unused.'] ],
+ ]
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 6 => [ 10 => ['Variable $var3 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for unused and undefined variables in function with foreach.
+ *
+ * @return void
+ */
+ public function testFunctionWithUndefinedForeach() {
+ $code = <<<'CODE'
+ $value1) {
+ echo "$key1 => $value1\n";
+ }
+ echo "$key1 => $value1\n";
+ foreach ($array as $key2 => &$value2) {
+ echo "$key2 => $value2\n";
+ }
+ echo "$key2 => $value2\n";
+ foreach ($array as $element3) {
+ }
+ foreach ($array as &$element4) {
+ }
+ foreach ($array as $key3 => $value3) {
+ }
+ foreach ($array as $key4 => &$value4) {
+ }
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 19 => [
+ 24 => ['Unused variable $element3.']
+ ],
+ 21 => [
+ 25 => ['Unused variable $element4.']
+ ],
+ 23 => [
+ 24 => ['Unused variable $key3.'],
+ 33 => ['Unused variable $value3.'],
+ ],
+ 25 => [
+ 24 => ['Unused variable $key4.'],
+ 34 => ['Unused variable $value4.']
+ ],
+ ]
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 14 => ['Variable $array is undefined.'] ],
+ 7 => [ 14 => ['Variable $array is undefined.'] ],
+ 11 => [ 14 => ['Variable $array is undefined.'] ],
+ 15 => [ 14 => ['Variable $array is undefined.'] ],
+ 19 => [ 14 => ['Variable $array is undefined.'] ],
+ 21 => [ 14 => ['Variable $array is undefined.'] ],
+ 23 => [ 14 => ['Variable $array is undefined.'] ],
+ 25 => [ 14 => ['Variable $array is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for unused variables in function with foreach, all defined.
+ *
+ * @return void
+ */
+ public function testFunctionWithDefinedForeach() {
+ $code = <<<'CODE'
+ $value1) {
+ echo "$key1 => $value1\n";
+ }
+ echo "$key1 => $value1\n";
+ foreach ($array as $key2 => &$value2) {
+ echo "$key2 => $value2\n";
+ }
+ echo "$key2 => $value2\n";
+ foreach ($array as $element3) {
+ }
+ foreach ($array as &$element4) {
+ }
+ foreach ($array as $key3 => $value3) {
+ }
+ foreach ($array as $key4 => &$value4) {
+ }
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 20 => [
+ 24 => ['Unused variable $element3.']
+ ],
+ 22 => [
+ 25 => ['Unused variable $element4.']
+ ],
+ 24 => [
+ 24 => ['Unused variable $key3.'],
+ 33 => ['Unused variable $value3.']
+ ],
+ 26 => [
+ 24 => ['Unused variable $key4.'],
+ 34 => ['Unused variable $value4.']
+ ],
+ ]
+ );
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks for use of undefined variables in class method without params.
+ *
+ * @param string $code Code snippet under test
+ * @param array $errorsBefore Expected errors before $var is assigned.
+ * @param array $errorsAfter Optional. Expected errors after $var is
+ * assigned. Defaults to []
+ *
+ * @dataProvider dataUndefinedVar
+ *
+ * @return void
+ */
+ public function testClassNoMembersMethodNoParams($code, $errorsBefore, $errorsAfter = []) {
+ $template = <<<'CODE'
+other_method();
+ return $var;
+ }
+
+ function other_method() {
+ }
+}
+CODE;
+
+ list(
+ $beforeAssign, $afterAssign
+ ) = $this->insertBeforeAndAfter($template, $code);
+
+ $beforeFile = $this->dummyFile($beforeAssign);
+ $this->assertWarningsMatch($beforeFile, [], 'before assign');
+ $this->assertErrorsMatch($beforeFile, $this->offset($errorsBefore, 3, 8), 'before assign');
+
+ $afterFile = $this->dummyFile($afterAssign);
+ $this->assertWarningsMatch($afterFile, [], 'after assign');
+ $this->assertErrorsMatch($afterFile, $this->offset($errorsAfter, 5, 8), 'after assign');
+ }
+
+ /**
+ * Test checks for use of undefined variables in class method with param.
+ *
+ * @return void
+ */
+ public function testClassNoMembersMethodWithParam() {
+ $code = <<<'CODE'
+other_method():
+ return $param;
+ }
+
+ function other_method() {
+ }
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks for use of undefined variables in class method using member var.
+ *
+ * @return void
+ */
+ public function testClassNoMembersMethodWithMemberVar() {
+ $code = <<<'CODE'
+member_var;
+ echo self::$static_member_var;
+ }
+}
+CODE;
+ $file = $this->dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+
+ // NOTE: We don't inspect class inheritance so we can't determine that
+ // member variables are undeclared.
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 4 => [ 21 => ['Variable $member_var is undefined.'] ],
+ ]
+ );
+
+ $this->markTestIncomplete(
+ 'FIXME: Should we report that self::$static_member_var is undefined?'
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 4 => [ 21 => ['Variable $member_var is undefined.'] ],
+ 5 => [ 21 => ['Variable $static_member_var is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for use of undefined variables in class with member vars.
+ */
+ public function testClassWithMembersMethodWithMemberVar() {
+ $code = <<<'CODE'
+member_var;
+ echo $this->no_such_member_var;
+ echo self::$static_member_var;
+ echo self::$no_such_static_member_var;
+ echo SomeOtherClass::$external_static_member_var;
+ }
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 8 => [ 21 => ['Variable $no_such_member_var is undefined.'] ],
+ ]
+ );
+
+ $this->markTestIncomplete(
+ 'FIXME: $static_member_var is actually used and we should add ' .
+ 'checks for static variable use.'
+ );
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 8 => [ 21 => ['Variable $no_such_member_var is undefined.'] ],
+ 10 => [ 21 => ['Variable $no_such_static_member_var is undefined.'] ],
+ 11 => [ 21 => ['Variable $external_static_member_var is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for use of $this outside of a class.
+ */
+ public function testThisOutsideClass() {
+ $code = <<<'CODE'
+whatever();
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 12 => ['Variable $this is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for use of static members outside of a class.
+ */
+ public function testStaticMembersOutsideClass() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 4 => [ 18 => ['Use of self::$whatever outside class definition.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for use of late static binding outside of a class.
+ */
+ public function testLateStaticBindingOutsideClass() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 18 => ['Use of static::$whatever outside class definition.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks for use of variables defined in outer scope of closure.
+ */
+ public function testFunctionWithClosure() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 7 => [ 18 => ['Variable $outer_param is undefined.'] ],
+ 9 => [ 18 => ['Variable $outer_var is undefined.'] ],
+ 10 => [ 18 => ['Variable $outer_var2 is undefined.'] ],
+ 13 => [ 44 => ['Variable $outer_var3 is undefined.'] ],
+ 16 => [ 18 => ['Variable $inner_param is undefined.'] ],
+ 18 => [ 18 => ['Variable $outer_var2 is undefined.'] ],
+ 19 => [ 18 => ['Variable $outer_var3 is undefined.'] ],
+ 20 => [ 18 => ['Variable $inner_var is undefined.'] ],
+ 25 => [ 10 => ['Variable $outer_var3 is undefined.'] ],
+ 26 => [ 10 => ['Variable $inner_param is undefined.'] ],
+ 27 => [ 10 => ['Variable $inner_var is undefined.'] ],
+ 28 => [ 10 => ['Variable $inner_var2 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with return by reference.
+ */
+ public function testFunctionWithReturnByRefAndParam() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks function with unused static variables.
+ */
+ public function testFunctionWithStaticVar() {
+ // phpcs:disable Generic.Files.LineLength.TooLong
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 3 => [
+ 40 => ['Unused variable $static_neg_num.'],
+ 64 => ['Unused variable $static_string.'],
+ 88 => ['Unused variable $static_string2.'],
+ 113 => ['Unused variable $static_define.'],
+ 140 => ['Unused variable $static_constant.']
+ ],
+ ]
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 15 => [ 10 => ['Variable $var is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with pass by reference param.
+ */
+ public function testFunctionWithPassByRefParam() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks use of undefined vars in function with pass by reference calls.
+ */
+ public function testFunctionWithPassByReferenceCalls() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 10 => ['Variable $matches is undefined.'] ],
+ 4 => [ 10 => ['Variable $needle is undefined.'] ],
+ 5 => [ 10 => ['Variable $haystack is undefined.'] ],
+ 7 => [ 16 => ['Variable $needle is undefined.'] ],
+ 8 => [ 27 => ['Variable $haystack is undefined.'] ],
+ 10 => [ 10 => ['Variable $needle is undefined.'] ],
+ 11 => [ 10 => ['Variable $haystack is undefined.'] ],
+ 17 => [ 10 => ['Variable $var3 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with try ... catch.
+ */
+ public function testFunctionWithTryCatch() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 10 => ['Variable $e is undefined.'] ],
+ 7 => [ 14 => ['Variable $e is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks $this usage in a closure within a class.
+ */
+ public function testClassWithThisInsideClosure() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 6 => [ 29 => ['Unused function parameter $inner_param.'] ],
+ ]
+ );
+ // NOTE: $this is automatically passed to anonymous functions since
+ // PHP 5.4.0 so no errors for that.
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks self usage in a closure within a class.
+ */
+ public function testClassWithSelfInsideClosure() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertErrorsMatch($file, []);
+
+ $this->markTestIncomplete('FIXME: static variable $static_member is used.');
+ $this->assertWarningsMatch($file, []);
+ }
+
+ /**
+ * Test checks function with inline assignments.
+ */
+ public function testFunctionWithInlineAssigns() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 3 => [ 10 => ['Variable $var is undefined.'] ],
+ 6 => [ 10 => ['Variable $var2 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with redeclarations as globals.
+ */
+ public function testFunctionWithGlobalRedeclarations() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 7 => [ 20 => ['Redeclaration of bound variable $bound as global variable.'] ],
+ 14 => [ 12 => ['Redeclaration of function parameter $param as global variable.'] ],
+ 15 => [ 12 => ['Redeclaration of static variable $static as global variable.'] ],
+ 16 => [ 12 => ['Redeclaration of variable $bound as global variable.'] ],
+ 17 => [ 12 => ['Redeclaration of variable $local as global variable.'] ],
+ 18 => [ 12 => ['Redeclaration of variable $e as global variable.'] ],
+ ]
+ );
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks function with redeclarations as static variables.
+ */
+ public function testFunctionWithStaticRedeclarations() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 4 => [ 21 => ['Redeclaration of static variable $static as static variable.'] ],
+ 7 => [ 19 => ['Redeclaration of bound variable $bound as static variable.'] ],
+ 14 => [ 12 => ['Redeclaration of function parameter $param as static variable.'] ],
+ 15 => [ 12 => ['Redeclaration of static variable $static as static variable.'] ],
+ 16 => [ 12 => ['Redeclaration of variable $bound as static variable.'] ],
+ 17 => [ 12 => ['Redeclaration of variable $local as static variable.'] ],
+ 18 => [ 12 => ['Redeclaration of variable $e as static variable.'] ],
+ ]
+ );
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks function with redeclarations in catch declarations.
+ */
+ public function testFunctionWithCatchRedeclarations() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks function with superglobals
+ */
+ public function testFunctionWithSuperglobals() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 13 => [ 10 => ['Variable $var is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with heredoc
+ */
+ public function testFunctionWithHeredoc() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 8 => [ 1 => ['Variable $var2 is undefined.'] ],
+ 9 => [ 1 => ['Variable $var2 is undefined.'] ],
+ 10 => [ 1 => ['Variable $var2 is undefined.'] ],
+ 12 => [ 1 => ['Variable $var2 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks variable property names.
+ */
+ public function testClassWithSymbolicRefProperty() {
+ $code = <<<'CODE'
+$property = 'some value';
+ $this -> $property = 'some value';
+ $this->$undefined_property = 'some value';
+ $this -> $undefined_property = 'some value';
+ }
+ }
+
+ function method_with_symbolic_ref_method() {
+ $methods = array('method_with_symbolic_ref_property');
+ foreach ($methods as $method) {
+ $this->$method();
+ $this -> $method();
+ $this->$undefined_method();
+ $this -> $undefined_method();
+ }
+ }
+}
+CODE;
+
+ $file = $this->dummyFile($code);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ // FIXME: $this->$property refers to defined property.
+ 8 => [ 20 => ['Variable $property is undefined.'] ],
+ 9 => [ 22 => ['Variable $property is undefined.'] ],
+
+ 10 => [ 20 => ['Variable $undefined_property is undefined.'] ],
+ 11 => [ 22 => ['Variable $undefined_property is undefined.'] ],
+
+ 20 => [ 20 => ['Variable $undefined_method is undefined.'] ],
+ 21 => [ 22 => ['Variable $undefined_method is undefined.'] ],
+ ]
+ );
+
+ $this->markTestIncomplete('FIXME: property $my_property is used + defined.');
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 10 => [ 20 => ['Variable $undefined_property is undefined.'] ],
+ 11 => [ 22 => ['Variable $undefined_property is undefined.'] ],
+
+ 20 => [ 20 => ['Variable $undefined_method is undefined.'] ],
+ 21 => [ 22 => ['Variable $undefined_method is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with only assign to pass by reference parameter.
+ */
+ public function testFunctionWithPassByRefAssignOnlyArg() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch($file, []);
+ }
+
+ /**
+ * Test checks class with late static binding.
+ */
+ public function testClassWithLateStaticBinding() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch($file, []);
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 5 => [ 29 => ['Variable $var is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with single quoted compact.
+ */
+ public function testFunctionWithSingleQuotedCompact() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 2 => [ 49 => ['Unused function parameter $param2.'] ],
+ ]
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 7 => [ 23 => ['Variable $var3 is undefined.'] ],
+ 10 => [ 54 => ['Variable $var5 is undefined.'] ],
+ ]
+ );
+ }
+
+ /**
+ * Test checks function with double quoted expression compact.
+ */
+ public function testFunctionWithExpressionCompact() {
+ $code = <<<'CODE'
+dummyFile($code);
+ $this->assertWarningsMatch(
+ $file,
+ [
+ 2 => [ 52 => ['Unused function parameter $param2.'] ],
+ 7 => [ 5 => ['Unused variable $var7.'] ],
+ ]
+ );
+ $this->assertErrorsMatch(
+ $file,
+ [
+ 11 => [ 23 => ['Variable $var3 is undefined.'] ],
+ 14 => [ 54 => ['Variable $var5 is undefined.'] ],
+ ]
+ );
}
}
diff --git a/composer.json b/composer.json
index 63342be..516a761 100644
--- a/composer.json
+++ b/composer.json
@@ -9,7 +9,7 @@
"phpcompatibility/php-compatibility": "*"
},
"require-dev": {
- "phpunit/phpunit": "~4.0"
+ "phpunit/phpunit": "~7.0"
},
"license": "BSD",
"minimum-stability": "dev",
diff --git a/composer.lock b/composer.lock
index ddcef53..f6c9409 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "6ef964c03350fb19e3af98a69a2e096c",
+ "content-hash": "f4d89abc00baecffa69bc2de467e169f",
"packages": [
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
@@ -248,6 +248,162 @@
],
"time": "2020-11-10T18:47:58+00:00"
},
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.10.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-11-13T09:40:50+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "phar-io/version": "^2.0",
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "time": "2018-07-08T19:23:20+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "time": "2018-07-08T19:19:57+00:00"
+ },
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
@@ -398,33 +554,33 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.10.3",
+ "version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "451c3cd1418cf640de218914901e51b064abb093"
+ "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
- "reference": "451c3cd1418cf640de218914901e51b064abb093",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
+ "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.2",
- "php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
- "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
- "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
+ "doctrine/instantiator": "^1.2",
+ "php": "^7.2 || ~8.0, <8.2",
+ "phpdocumentor/reflection-docblock": "^5.2",
+ "sebastian/comparator": "^3.0 || ^4.0",
+ "sebastian/recursion-context": "^3.0 || ^4.0"
},
"require-dev": {
- "phpspec/phpspec": "^2.5 || ^3.2",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ "phpspec/phpspec": "^6.0 || ^7.0",
+ "phpunit/phpunit": "^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.10.x-dev"
+ "dev-master": "1.x-dev"
}
},
"autoload": {
@@ -457,43 +613,44 @@
"spy",
"stub"
],
- "time": "2020-03-05T15:02:03+00:00"
+ "time": "2021-09-10T09:02:12+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "2.2.4",
+ "version": "6.1.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
- "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "phpunit/php-file-iterator": "~1.3",
- "phpunit/php-text-template": "~1.2",
- "phpunit/php-token-stream": "~1.3",
- "sebastian/environment": "^1.3.2",
- "sebastian/version": "~1.0"
+ "ext-dom": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.1",
+ "phpunit/php-file-iterator": "^2.0",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-token-stream": "^3.0",
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
+ "sebastian/environment": "^3.1 || ^4.0",
+ "sebastian/version": "^2.0.1",
+ "theseer/tokenizer": "^1.1"
},
"require-dev": {
- "ext-xdebug": ">=2.1.4",
- "phpunit/phpunit": "~4"
+ "phpunit/phpunit": "^7.0"
},
"suggest": {
- "ext-dom": "*",
- "ext-xdebug": ">=2.2.1",
- "ext-xmlwriter": "*"
+ "ext-xdebug": "^2.6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2.x-dev"
+ "dev-master": "6.1-dev"
}
},
"autoload": {
@@ -508,7 +665,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -519,29 +676,32 @@
"testing",
"xunit"
],
- "time": "2015-10-06T15:47:00+00:00"
+ "time": "2018-10-31T16:06:48+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.4.5",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
+ "reference": "28af674ff175d0768a5a978e6de83f697d4a7f05"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
- "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/28af674ff175d0768a5a978e6de83f697d4a7f05",
+ "reference": "28af674ff175d0768a5a978e6de83f697d4a7f05",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -556,7 +716,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -566,7 +726,13 @@
"filesystem",
"iterator"
],
- "time": "2017-11-27T13:52:08+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-07-19T06:46:01+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -611,28 +777,28 @@
},
{
"name": "phpunit/php-timer",
- "version": "1.0.9",
+ "version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+ "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
- "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662",
+ "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662",
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.0"
+ "php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ "phpunit/phpunit": "^8.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "2.1-dev"
}
},
"autoload": {
@@ -647,7 +813,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
+ "email": "sebastian@phpunit.de",
"role": "lead"
}
],
@@ -656,33 +822,39 @@
"keywords": [
"timer"
],
- "time": "2017-02-26T11:10:40+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T08:20:02+00:00"
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.12",
+ "version": "3.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
+ "reference": "9c1da83261628cb24b6a6df371b6e312b3954768"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
- "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9c1da83261628cb24b6a6df371b6e312b3954768",
+ "reference": "9c1da83261628cb24b6a6df371b6e312b3954768",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
- "php": ">=5.3.3"
+ "php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "~4.2"
+ "phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -705,46 +877,64 @@
"keywords": [
"tokenizer"
],
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
"abandoned": true,
- "time": "2017-12-04T08:55:13+00:00"
+ "time": "2021-07-26T12:15:06+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "4.8.36",
+ "version": "7.5.20",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
- "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c",
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c",
"shasum": ""
},
"require": {
+ "doctrine/instantiator": "^1.1",
"ext-dom": "*",
"ext-json": "*",
- "ext-pcre": "*",
- "ext-reflection": "*",
- "ext-spl": "*",
- "php": ">=5.3.3",
- "phpspec/prophecy": "^1.3.1",
- "phpunit/php-code-coverage": "~2.1",
- "phpunit/php-file-iterator": "~1.4",
- "phpunit/php-text-template": "~1.2",
- "phpunit/php-timer": "^1.0.6",
- "phpunit/phpunit-mock-objects": "~2.3",
- "sebastian/comparator": "~1.2.2",
- "sebastian/diff": "~1.2",
- "sebastian/environment": "~1.3",
- "sebastian/exporter": "~1.2",
- "sebastian/global-state": "~1.0",
- "sebastian/version": "~1.0",
- "symfony/yaml": "~2.1|~3.0"
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "myclabs/deep-copy": "^1.7",
+ "phar-io/manifest": "^1.0.2",
+ "phar-io/version": "^2.0",
+ "php": "^7.1",
+ "phpspec/prophecy": "^1.7",
+ "phpunit/php-code-coverage": "^6.0.7",
+ "phpunit/php-file-iterator": "^2.0.1",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-timer": "^2.1",
+ "sebastian/comparator": "^3.0",
+ "sebastian/diff": "^3.0",
+ "sebastian/environment": "^4.0",
+ "sebastian/exporter": "^3.1",
+ "sebastian/global-state": "^2.0",
+ "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/resource-operations": "^2.0",
+ "sebastian/version": "^2.0.1"
+ },
+ "conflict": {
+ "phpunit/phpunit-mock-objects": "*"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
},
"suggest": {
- "phpunit/php-invoker": "~1.1"
+ "ext-soap": "*",
+ "ext-xdebug": "*",
+ "phpunit/php-invoker": "^2.0"
},
"bin": [
"phpunit"
@@ -752,7 +942,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.8.x-dev"
+ "dev-master": "7.5-dev"
}
},
"autoload": {
@@ -778,38 +968,32 @@
"testing",
"xunit"
],
- "time": "2017-06-21T08:07:12+00:00"
+ "time": "2020-01-08T08:45:45+00:00"
},
{
- "name": "phpunit/phpunit-mock-objects",
- "version": "2.3.8",
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
- "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619",
+ "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.2",
- "php": ">=5.3.3",
- "phpunit/php-text-template": "~1.2",
- "sebastian/exporter": "~1.2"
+ "php": ">=5.6"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
- },
- "suggest": {
- "ext-soap": "*"
+ "phpunit/phpunit": "^8.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3.x-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
@@ -824,45 +1008,45 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.de",
- "role": "lead"
+ "email": "sebastian@phpunit.de"
}
],
- "description": "Mock Object library for PHPUnit",
- "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
- "keywords": [
- "mock",
- "xunit"
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "abandoned": true,
- "time": "2015-10-02T06:51:40+00:00"
+ "time": "2020-11-30T08:15:22+00:00"
},
{
"name": "sebastian/comparator",
- "version": "1.2.4",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
+ "reference": "1071dfcef776a57013124ff35e1fc41ccd294758"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
- "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758",
+ "reference": "1071dfcef776a57013124ff35e1fc41ccd294758",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "sebastian/diff": "~1.2",
- "sebastian/exporter": "~1.2 || ~2.0"
+ "php": ">=7.1",
+ "sebastian/diff": "^3.0",
+ "sebastian/exporter": "^3.1"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^8.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2.x-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -875,6 +1059,10 @@
"BSD-3-Clause"
],
"authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
@@ -886,45 +1074,48 @@
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
}
],
"description": "Provides the functionality to compare PHP values for equality",
- "homepage": "http://www.github.com/sebastianbergmann/comparator",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
- "time": "2017-01-29T09:50:25+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T08:04:30+00:00"
},
{
"name": "sebastian/diff",
- "version": "1.4.3",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
+ "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
- "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
+ "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.0"
+ "php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ "phpunit/phpunit": "^7.5 || ^8.0",
+ "symfony/process": "^2 || ^3.3 || ^4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -937,46 +1128,58 @@
"BSD-3-Clause"
],
"authors": [
- {
- "name": "Kore Nordmann",
- "email": "mail@kore-nordmann.de"
- },
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
}
],
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [
- "diff"
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
],
- "time": "2017-05-22T07:24:03+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:59:04+00:00"
},
{
"name": "sebastian/environment",
- "version": "1.3.8",
+ "version": "4.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
+ "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
- "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
+ "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.0"
+ "php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "^4.8 || ^5.0"
+ "phpunit/phpunit": "^7.5"
+ },
+ "suggest": {
+ "ext-posix": "*"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3.x-dev"
+ "dev-master": "4.2-dev"
}
},
"autoload": {
@@ -1001,34 +1204,40 @@
"environment",
"hhvm"
],
- "time": "2016-08-18T05:49:44+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:53:42+00:00"
},
{
"name": "sebastian/exporter",
- "version": "1.2.2",
+ "version": "3.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
+ "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
- "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e",
+ "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "sebastian/recursion-context": "~1.0"
+ "php": ">=7.0",
+ "sebastian/recursion-context": "^3.0"
},
"require-dev": {
"ext-mbstring": "*",
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3.x-dev"
+ "dev-master": "3.1.x-dev"
}
},
"autoload": {
@@ -1041,6 +1250,10 @@
"BSD-3-Clause"
],
"authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
@@ -1049,17 +1262,13 @@
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
@@ -1068,27 +1277,33 @@
"export",
"exporter"
],
- "time": "2016-06-17T09:04:28+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:47:53+00:00"
},
{
"name": "sebastian/global-state",
- "version": "1.1.1",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
- "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.2"
+ "phpunit/phpunit": "^6.0"
},
"suggest": {
"ext-uopz": "*"
@@ -1096,7 +1311,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -1119,32 +1334,136 @@
"keywords": [
"global state"
],
- "time": "2015-10-12T03:26:01+00:00"
+ "time": "2017-04-27T15:39:26+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "3.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
+ "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:40:27+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
+ "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:37:18+00:00"
},
{
"name": "sebastian/recursion-context",
- "version": "1.0.5",
+ "version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
+ "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
- "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb",
+ "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "3.0.x-dev"
}
},
"autoload": {
@@ -1157,14 +1476,14 @@
"BSD-3-Clause"
],
"authors": [
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
@@ -1172,23 +1491,85 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2016-10-03T07:41:43+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:34:24+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3",
+ "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-30T07:30:19+00:00"
},
{
"name": "sebastian/version",
- "version": "1.0.6",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
- "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
"shasum": ""
},
+ "require": {
+ "php": ">=5.6"
+ },
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -1207,7 +1588,7 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2015-06-21T13:59:46+00:00"
+ "time": "2016-10-03T07:35:21+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -1286,72 +1667,50 @@
"time": "2021-02-19T12:13:01+00:00"
},
{
- "name": "symfony/yaml",
- "version": "v3.4.47",
+ "name": "theseer/tokenizer",
+ "version": "1.2.1",
"source": {
"type": "git",
- "url": "https://github.com/symfony/yaml.git",
- "reference": "88289caa3c166321883f67fe5130188ebbb47094"
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094",
- "reference": "88289caa3c166321883f67fe5130188ebbb47094",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
- "symfony/polyfill-ctype": "~1.8"
- },
- "conflict": {
- "symfony/console": "<3.4"
- },
- "require-dev": {
- "symfony/console": "~3.4|~4.0"
- },
- "suggest": {
- "symfony/console": "For validating YAML files using the lint command"
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"autoload": {
- "psr-4": {
- "Symfony\\Component\\Yaml\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
+ "classmap": [
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
}
],
- "description": "Symfony Yaml Component",
- "homepage": "https://symfony.com",
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"funding": [
{
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
+ "url": "https://github.com/theseer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
}
],
- "time": "2020-10-24T10:57:07+00:00"
+ "time": "2021-07-28T10:34:58+00:00"
},
{
"name": "webmozart/assert",
diff --git a/phpunit.xml b/phpunit.xml
index 34ad71c..016a868 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,8 +1,8 @@
-
+
- vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php
+ VariableAnalysis/Tests/VariableAnalysis