1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-02 17:52:45 +01:00
psalm/tests/Loop/DoTest.php

432 lines
14 KiB
PHP
Raw Normal View History

<?php
2023-10-19 13:12:06 +02:00
declare(strict_types=1);
namespace Psalm\Tests\Loop;
2021-12-03 20:11:20 +01:00
use Psalm\Tests\TestCase;
2021-12-04 21:55:53 +01:00
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
2021-06-08 04:55:21 +02:00
use const DIRECTORY_SEPARATOR;
2021-12-03 20:11:20 +01:00
class DoTest extends TestCase
{
2021-12-04 21:55:53 +01:00
use InvalidCodeAnalysisTestTrait;
use ValidCodeAnalysisTestTrait;
public function providerValidCodeParse(): iterable
{
return [
2022-12-18 18:19:22 +01:00
'doWhileTrue' => [
'code' => '<?php
function ret(): int {
do {
return 1;
} while (true);
2022-12-18 17:15:15 +01:00
}',
2022-12-18 18:19:22 +01:00
],
'doWhileVar' => [
'code' => '<?php
$worked = false;
do {
$worked = true;
}
while (rand(0,100) === 10);',
'assertions' => [
2018-11-10 20:06:31 +01:00
'$worked' => 'true',
],
],
'doWhileVarWithPossibleBreak' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
$a = false;
do {
if (rand(0, 1)) {
break;
}
if (rand(0, 1)) {
$a = true;
break;
}
$a = true;
}
while (rand(0,100) === 10);',
'assertions' => [
'$a' => 'bool',
],
],
'SKIPPED-doWhileVarWithPossibleBreakThatSetsToTrue' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
$a = false;
$b = false;
do {
$b = true;
if (rand(0, 1)) {
$a = true;
break;
}
$a = true;
}
while (rand(0,1));',
'assertions' => [
'$a' => 'true',
'$b' => 'true',
],
],
'doWhileVarWithPossibleBreakThatMaybeSetsToTrue' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
$a = false;
do {
if (rand(0, 1)) {
if (rand(0, 1)) {
$a = true;
}
break;
}
$a = true;
}
while (rand(0,1));',
'assertions' => [
'$a' => 'bool',
],
],
'doWhileVarWithPossibleInitialisingBreakNoInitialDefinition' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
do {
if (rand(0, 1)) {
$worked = true;
break;
}
$worked = true;
}
while (rand(0,100) === 10);',
'assertions' => [
'$worked' => 'true',
],
],
'doWhileUndefinedVar' => [
'code' => '<?php
do {
2018-11-10 20:06:31 +01:00
$result = (bool) rand(0,1);
} while (!$result);',
2018-11-10 20:06:31 +01:00
'assertions' => [
'$result' => 'true',
],
],
'doWhileVarAndBreak' => [
'code' => '<?php
/** @return void */
function foo(string $b) {}
do {
if (null === ($a = rand(0, 1) ? "hello" : null)) {
break;
}
/** @psalm-suppress MixedArgument */
foo($a);
}
while (rand(0,100) === 10);',
],
'doWhileWithNotEmptyCheck' => [
'code' => '<?php
class A {
/** @var A|null */
public $a;
public function __construct() {
$this->a = rand(0, 1) ? new A : null;
}
}
function takesA(A $a): void {}
$a = new A();
do {
takesA($a);
$a = $a->a;
} while ($a);',
'assertions' => [
'$a' => 'null',
],
],
'doWhileWithMethodCall' => [
'code' => '<?php
class A {
public function getParent(): ?A {
return rand(0, 1) ? new A() : null;
}
}
$a = new A();
do {
$a = $a->getParent();
} while ($a);',
'assertions' => [
'$a' => 'null',
],
],
'doWhileFirstGood' => [
'code' => '<?php
do {
$done = rand(0, 1) > 0;
} while (!$done);',
],
'doWhileWithIfException' => [
'code' => '<?php
class A
{
/**
* @var null|A
*/
public $parent;
public static function foo(A $a) : void
{
do {
if ($a->parent === null) {
throw new \Exception("bad");
}
$a = $a->parent;
} while (rand(0,1));
}
}',
],
'doWhileWithIfExceptionOutside' => [
'code' => '<?php
class A
{
/**
* @var null|A
*/
public $parent;
public static function foo(A $a) : void
{
if ($a->parent === null) {
throw new \Exception("bad");
}
do {
$a = $a->parent;
} while ($a->parent && rand(0, 1));
}
}',
],
'doWhileDefinedVar' => [
'code' => '<?php
$value = null;
do {
$count = rand(0, 1);
$value = 6;
} while ($count);',
],
2018-11-10 20:06:31 +01:00
'doWhileDefinedVarWithPossibleBreak' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
$value = null;
do {
if (rand(0, 1)) {
break;
}
$count = rand(0, 1);
$value = 6;
} while ($count);',
],
'invalidateBothByRefAssignmentsInDo' => [
'code' => '<?php
function foo(?string &$i) : void {}
function bar(?string &$i) : void {}
$c = null;
do {
2024-01-12 23:37:45 +01:00
if ($c === null || $c === "" || $c === "0") {
foo($c);
} else {
bar($c);
}
} while (rand(0, 1));',
],
'doParentCall' => [
'code' => '<?php
class A {
/** @return A|false */
public function getParent() {
return rand(0, 1) ? new A : false;
}
}
$a = new A();
do {
$a = $a->getParent();
} while ($a !== false);',
],
2019-01-07 07:15:30 +01:00
'doCallInWhile' => [
'code' => '<?php
2019-01-07 07:15:30 +01:00
class A {
public function getParent() : ?A {
return rand(0, 1) ? new A : null;
}
}
$a = new A();
$i = 0;
do {
$i++;
2019-03-23 19:27:54 +01:00
} while ($a = $a->getParent());',
2019-01-07 07:15:30 +01:00
],
'doWithContinue' => [
'code' => '<?php
do {
if (rand(0, 1)) {
continue;
}
} while (rand(0, 1));',
],
'noEmptyArrayAccessComplaintInsideDo' => [
'code' => '<?php
$foo = [];
do {
if (isset($foo["bar"])) {}
$foo["bar"] = "bat";
} while (rand(0, 1));',
],
2018-11-10 20:06:31 +01:00
'noRedundantConditionAfterDoWhile' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
$i = 5;
do {} while (--$i > 0);
echo $i === 0;',
],
'doWhileNonInfinite' => [
'code' => '<?php
function foo(): int {
do {
$value = mt_rand(0, 10);
if ($value > 5) continue;
break;
} while (true);
return $value;
}',
],
'doNoRedundant' => [
'code' => '<?php
class Event {}
function fetchEvent(): ?Event {
return rand(0, 1) ? new Event() : null;
}
function nextEvent(bool $c): void {
do {
$e = fetchEvent();
} while ($c && $e);
}',
],
'doConditionInWhileAndIfWithSingleVar' => [
'code' => '<?php
$b = !!rand(0, 1);
do {
if (!$b) {
$b = !rand(0, 1);
}
} while (!$b);',
'assertions' => [
2022-12-18 17:15:15 +01:00
'$b' => 'true',
],
],
'doConditionInWhileAndIfWithTwoVars' => [
'code' => '<?php
$b = !!rand(0, 1);
do {
$s = rand(0, 1);
if (!$b && $s) {}
} while (!$b && $s);
2022-12-18 17:15:15 +01:00
if ($b) {}',
],
'regularAssignmentInsideDo' => [
'code' => '<?php
do {
$code = rand(0, 1);
echo "here";
2022-12-18 17:15:15 +01:00
} while ($code === 1);',
],
'destructuringAssignmentInsideDo' => [
'code' => '<?php
do {
[$code] = [rand(0, 1)];
echo "here";
2022-12-18 17:15:15 +01:00
} while ($code === 1);',
],
2018-11-10 20:06:31 +01:00
];
}
public function providerInvalidCodeParse(): iterable
2018-11-10 20:06:31 +01:00
{
return [
'doWhileVarWithPossibleBreakWithoutDefining' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
do {
if (rand(0, 1)) {
break;
}
$worked = true;
}
while (rand(0,1));
echo $worked;',
'error_message' => 'PossiblyUndefinedGlobalVariable',
],
'doWhileVarWithPossibleBreakThatMaybeSetsToTrueWithoutDefining' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
do {
if (rand(0, 1)) {
if (rand(0, 1)) {
$a = true;
}
break;
}
$a = true;
}
while (rand(0,1));
echo $a;',
'error_message' => 'PossiblyUndefinedGlobalVariable',
],
'SKIPPED-doWhileVarWithPossibleContinueWithoutDefining' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
do {
if (rand(0, 1)) {
continue;
}
$worked = true;
}
while (rand(0,1));
echo $worked;',
'error_message' => 'PossiblyUndefinedGlobalVariable',
],
'possiblyUndefinedArrayInDo' => [
'code' => '<?php
2018-11-10 20:06:31 +01:00
do {
$array[] = "hello";
} while (rand(0, 1));',
2019-02-27 22:00:44 +01:00
'error_message' => 'PossiblyUndefinedGlobalVariable - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:25 - Possibly undefined ' .
2018-11-10 20:06:31 +01:00
'global variable $array, first seen on line 3',
],
];
}
}