create(ParserFactory::PREFER_PHP7); $config = Config::getInstance(); $config->throw_exception = true; $config->use_docblock_types = true; } public function setUp() { FileChecker::clearCache(); } public function testNotNull() { $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('!null', Type::parseString('MyObject')) ); $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('!null', Type::parseString('MyObject|null')) ); $this->assertEquals( 'MyObject|false', (string) TypeChecker::reconcileTypes('!null', Type::parseString('MyObject|false')) ); $this->assertEquals( 'mixed', (string) TypeChecker::reconcileTypes('!null', Type::parseString('mixed')) ); } public function testNotEmpty() { $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('!empty', Type::parseString('MyObject')) ); $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('!empty', Type::parseString('MyObject|null')) ); $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('!empty', Type::parseString('MyObject|false')) ); $this->assertEquals( 'mixed', (string) TypeChecker::reconcileTypes('!empty', Type::parseString('mixed')) ); // @todo in the future this should also work /* $this->assertEquals( 'MyObject|true', (string) TypeChecker::reconcileTypes('!empty', Type::parseString('MyObject|bool')) ); */ } public function testNull() { $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('null', Type::parseString('MyObject|null')) ); $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('null', Type::parseString('MyObject')) ); $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('null', Type::parseString('MyObject|false')) ); $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('null', Type::parseString('mixed')) ); } public function testEmpty() { $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('empty', Type::parseString('MyObject')) ); $this->assertEquals( 'false', (string) TypeChecker::reconcileTypes('empty', Type::parseString('MyObject|false')) ); $this->assertEquals( 'false', (string) TypeChecker::reconcileTypes('empty', Type::parseString('MyObject|bool')) ); $this->assertEquals( 'mixed', (string) TypeChecker::reconcileTypes('empty', Type::parseString('mixed')) ); $reconciled = TypeChecker::reconcileTypes('empty', Type::parseString('bool')); $this->assertEquals('false', (string) $reconciled); $this->assertInstanceOf('Psalm\Type\Atomic', $reconciled->types['false']); } public function testNotMyObject() { $this->assertEquals( 'bool', (string) TypeChecker::reconcileTypes('!MyObject', Type::parseString('MyObject|bool')) ); $this->assertEquals( 'null', (string) TypeChecker::reconcileTypes('!MyObject', Type::parseString('MyObject|null')) ); $this->assertEquals( 'MyObjectB', (string) TypeChecker::reconcileTypes('!MyObjectA', Type::parseString('MyObjectA|MyObjectB')) ); } public function testMyObject() { $this->assertEquals( 'MyObject', (string) TypeChecker::reconcileTypes('MyObject', Type::parseString('MyObject|bool')) ); $this->assertEquals( 'MyObjectA', (string) TypeChecker::reconcileTypes('MyObjectA', Type::parseString('MyObjectA|MyObjectB')) ); } public function testAllMixed() { $this->assertEquals( 'mixed', (string) TypeChecker::reconcileTypes('mixed', Type::parseString('mixed')) ); } public function testNotInstanceOf() { $stmts = self::$parser->parse('vars_in_scope['$a'] = Type::parseString('A'); $file_checker->check(true, true, $context); $this->assertEquals('null|A', (string) $context->vars_in_scope['$out']); } public function testNotInstanceOfProperty() { $stmts = self::$parser->parse('foo instanceof C) { // do something } else { $out = $a->foo; } '); $file_checker = new FileChecker('somefile.php', $stmts); $context = new Context('somefile.php'); $context->vars_in_scope['$a'] = Type::parseString('A'); $file_checker->check(true, true, $context); $this->assertEquals('null|B', (string) $context->vars_in_scope['$out']); } public function testNotInstanceOfPropertyElseif() { $stmts = self::$parser->parse('foo)) { } elseif ($a->foo instanceof C) { // do something } else { $out = $a->foo; } '); $file_checker = new FileChecker('somefile.php', $stmts); $context = new Context('somefile.php'); $context->vars_in_scope['$a'] = Type::parseString('A'); $file_checker->check(true, true, $context); $this->assertEquals('null|B', (string) $context->vars_in_scope['$out']); } public function testTypeArguments() { $stmts = self::$parser->parse('check(true, true, $context); $this->assertEquals('mixed', (string) $context->vars_in_scope['$a']); $this->assertEquals('mixed', (string) $context->vars_in_scope['$b']); } }