Best Gherkin-php code snippet using AstNode
UriTemplateParserTest.php
Source:UriTemplateParserTest.php
...11use Aphiria\Routing\UriTemplates\Lexers\Token;12use Aphiria\Routing\UriTemplates\Lexers\TokenStream;13use Aphiria\Routing\UriTemplates\Lexers\TokenType;14use Aphiria\Routing\UriTemplates\Lexers\UnexpectedTokenException;15use Aphiria\Routing\UriTemplates\Parsers\AstNode;16use Aphiria\Routing\UriTemplates\Parsers\AstNodeType;17use Aphiria\Routing\UriTemplates\Parsers\UriTemplateParser;18use PHPUnit\Framework\TestCase;19class UriTemplateParserTest extends TestCase20{21 private UriTemplateParser $parser;22 protected function setUp(): void23 {24 $this->parser = new UriTemplateParser();25 }26 public function testParsingClosingBracketWhenNotParsingOptionalRoutePartTreatsBracketAsText(): void27 {28 $tokens = new TokenStream([29 new Token(TokenType::Punctuation, '/'),30 new Token(TokenType::Punctuation, ']')31 ]);32 $pathNode = new AstNode(AstNodeType::Path);33 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));34 $pathNode->addChild(new AstNode(AstNodeType::Text, ']'));35 $expectedAst = new AstNode(AstNodeType::Root);36 $expectedAst->addChild($pathNode);37 $this->assertEquals($expectedAst, $this->parser->parse($tokens));38 }39 public function testParsingInvalidBracketInMiddleOfConstraintThrowsException(): void40 {41 $this->expectException(UnexpectedTokenException::class);42 $this->expectExceptionMessage("Expected optional path part to start with '/', got " . TokenType::Variable->name);43 $tokens = new TokenStream([44 new Token(TokenType::Punctuation, '/'),45 new Token(TokenType::Punctuation, '['),46 new Token(TokenType::Variable, 'foo'),47 new Token(TokenType::Punctuation, '('),48 new Token(TokenType::Punctuation, ']'),49 ]);50 $this->parser->parse($tokens);51 }52 public function testParsingNestedOptionalPathParts(): void53 {54 $tokens = new TokenStream([55 new Token(TokenType::Punctuation, '/'),56 new Token(TokenType::Punctuation, '['),57 new Token(TokenType::Punctuation, '/'),58 new Token(TokenType::Text, 'foo'),59 new Token(TokenType::Punctuation, '['),60 new Token(TokenType::Punctuation, '/'),61 new Token(TokenType::Text, 'bar'),62 new Token(TokenType::Punctuation, ']'),63 new Token(TokenType::Punctuation, ']')64 ]);65 $innerOptionalRoutePartNode = new AstNode(AstNodeType::OptionalRoutePart, '[');66 $innerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));67 $innerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::Text, 'bar'));68 $outerOptionalRoutePartNode = new AstNode(AstNodeType::OptionalRoutePart, '[');69 $outerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));70 $outerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::Text, 'foo'));71 $outerOptionalRoutePartNode->addChild($innerOptionalRoutePartNode);72 $pathNode = new AstNode(AstNodeType::Path, null);73 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));74 $pathNode->addChild($outerOptionalRoutePartNode);75 $expectedAst = new AstNode(AstNodeType::Root, null);76 $expectedAst->addChild($pathNode);77 $this->assertEquals($expectedAst, $this->parser->parse($tokens));78 }79 public function testParsingNestedOptionalHostPartCreatesNestedOptionalPartNodes(): void80 {81 $tokens = new TokenStream([82 new Token(TokenType::Punctuation, '['),83 new Token(TokenType::Text, 'foo'),84 new Token(TokenType::Punctuation, '.'),85 new Token(TokenType::Punctuation, '['),86 new Token(TokenType::Text, 'bar'),87 new Token(TokenType::Punctuation, '.'),88 new Token(TokenType::Punctuation, ']'),89 new Token(TokenType::Punctuation, ']'),90 new Token(TokenType::Text, 'example'),91 new Token(TokenType::Punctuation, '.'),92 new Token(TokenType::Text, 'com'),93 new Token(TokenType::Punctuation, '/'),94 new Token(TokenType::Text, 'foo')95 ]);96 $expectedAst = new AstNode(AstNodeType::Root, null);97 $hostNode = new AstNode(AstNodeType::Host, null);98 $expectedAst->addChild($hostNode);99 $innerOptionalRoutePartNode = new AstNode(AstNodeType::OptionalRoutePart, '[');100 $innerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::Text, 'bar'));101 $innerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'));102 $outerOptionalRoutePartNode = new AstNode(AstNodeType::OptionalRoutePart, '[');103 $outerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::Text, 'foo'));104 $outerOptionalRoutePartNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'));105 $outerOptionalRoutePartNode->addChild($innerOptionalRoutePartNode);106 $hostNode->addChild($outerOptionalRoutePartNode);107 $hostNode->addChild(new AstNode(AstNodeType::Text, 'example'));108 $hostNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'));109 $hostNode->addChild(new AstNode(AstNodeType::Text, 'com'));110 $pathNode = new AstNode(AstNodeType::Path, null);111 $expectedAst->addChild($pathNode);112 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));113 $pathNode->addChild(new AstNode(AstNodeType::Text, 'foo'));114 $this->assertEquals($expectedAst, $this->parser->parse($tokens));115 }116 public function testParsingNestedOptionalHostPartThatDoesEndWithPeriodThrowsException(): void117 {118 $this->expectException(UnexpectedTokenException::class);119 $this->expectExceptionMessage("Expected optional host part to end with '.'");120 $tokens = new TokenStream([121 new Token(TokenType::Punctuation, '['),122 new Token(TokenType::Text, 'foo'),123 new Token(TokenType::Punctuation, '.'),124 new Token(TokenType::Punctuation, '['),125 new Token(TokenType::Text, 'bar'),126 new Token(TokenType::Punctuation, ']'),127 new Token(TokenType::Punctuation, ']'),128 new Token(TokenType::Text, 'example'),129 new Token(TokenType::Punctuation, '.'),130 new Token(TokenType::Text, 'com'),131 new Token(TokenType::Punctuation, '/'),132 new Token(TokenType::Text, 'foo')133 ]);134 $this->parser->parse($tokens);135 }136 public function testParsingNonStandardPunctuationJustGetsTreatedAsText(): void137 {138 $tokens = new TokenStream([139 new Token(TokenType::Punctuation, '/'),140 new Token(TokenType::Punctuation, '!')141 ]);142 $pathNode = new AstNode(AstNodeType::Path);143 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));144 $pathNode->addChild(new AstNode(AstNodeType::Text, '!'));145 $expectedAst = new AstNode(AstNodeType::Root);146 $expectedAst->addChild($pathNode);147 $this->assertEquals($expectedAst, $this->parser->parse($tokens));148 }149 public function testParsingOptionalHostPartThatDoesEndWithPeriodThrowsException(): void150 {151 $this->expectException(UnexpectedTokenException::class);152 $this->expectExceptionMessage("Expected optional host part to end with '.'");153 $tokens = new TokenStream([154 new Token(TokenType::Punctuation, '['),155 new Token(TokenType::Text, 'api'),156 new Token(TokenType::Punctuation, ']'),157 new Token(TokenType::Text, 'example'),158 new Token(TokenType::Punctuation, '.'),159 new Token(TokenType::Text, 'com'),160 new Token(TokenType::Punctuation, '/'),161 new Token(TokenType::Text, 'foo')162 ]);163 $this->parser->parse($tokens);164 }165 public function testParsingOptionalPathPartCreatesCorrectNodes(): void166 {167 $tokens = new TokenStream([168 new Token(TokenType::Punctuation, '/'),169 new Token(TokenType::Text, 'foo'),170 new Token(TokenType::Punctuation, '['),171 new Token(TokenType::Punctuation, '/'),172 new Token(TokenType::Text, 'bar'),173 new Token(TokenType::Punctuation, ']')174 ]);175 $expectedAst = new AstNode(AstNodeType::Root, null);176 $pathNode = new AstNode(AstNodeType::Path, null);177 $expectedAst->addChild($pathNode);178 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));179 $pathNode->addChild(new AstNode(AstNodeType::Text, 'foo'));180 $optionalRoutePartNode = new AstNode(AstNodeType::OptionalRoutePart, '[');181 $optionalRoutePartNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));182 $optionalRoutePartNode->addChild(new AstNode(AstNodeType::Text, 'bar'));183 $pathNode->addChild($optionalRoutePartNode);184 $this->assertEquals($expectedAst, $this->parser->parse($tokens));185 }186 public function testParsingOptionalPathPartThatDoesNotBeginWithSlashThrowsException(): void187 {188 $this->expectException(UnexpectedTokenException::class);189 $this->expectExceptionMessage("Expected optional path part to start with '/', got " . TokenType::Text->name);190 $tokens = new TokenStream([191 new Token(TokenType::Punctuation, '/'),192 new Token(TokenType::Text, 'foo'),193 new Token(TokenType::Punctuation, '['),194 new Token(TokenType::Text, 'bar'),195 new Token(TokenType::Punctuation, ']')196 ]);197 $this->parser->parse($tokens);198 }199 public function testParsingTextOnlyPathCreatesSingleTextNode(): void200 {201 $tokens = new TokenStream([202 new Token(TokenType::Punctuation, '/'),203 new Token(TokenType::Text, 'foo')204 ]);205 $expectedAst = new AstNode(AstNodeType::Root, null);206 $pathNode = new AstNode(AstNodeType::Path, null);207 $expectedAst->addChild($pathNode);208 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));209 $pathNode->addChild(new AstNode(AstNodeType::Text, 'foo'));210 $this->assertEquals($expectedAst, $this->parser->parse($tokens));211 }212 public function testParsingNumberOnlyPathCreatesSingleNumber(): void213 {214 $tokens = new TokenStream([215 new Token(TokenType::Punctuation, '/'),216 new Token(TokenType::Number, 12345)217 ]);218 $expectedAst = new AstNode(AstNodeType::Root, null);219 $pathNode = new AstNode(AstNodeType::Path, null);220 $expectedAst->addChild($pathNode);221 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));222 $pathNode->addChild(new AstNode(AstNodeType::Text, 12345));223 $this->assertEquals($expectedAst, $this->parser->parse($tokens));224 }225 public function testParsingPeriodInPathCreatesTextNode(): void226 {227 $tokens = new TokenStream([228 new Token(TokenType::Text, 'example'),229 new Token(TokenType::Punctuation, '.'),230 new Token(TokenType::Text, 'com'),231 new Token(TokenType::Punctuation, '/'),232 new Token(TokenType::Text, 'foo'),233 new Token(TokenType::Punctuation, '.'),234 new Token(TokenType::Text, 'bar'),235 ]);236 $expectedAst = new AstNode(AstNodeType::Root, null);237 $hostNode = new AstNode(AstNodeType::Host, null);238 $pathNode = new AstNode(AstNodeType::Path, null);239 $expectedAst->addChild($hostNode);240 $expectedAst->addChild($pathNode);241 $hostNode->addChild(new AstNode(AstNodeType::Text, 'example'));242 $hostNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'));243 $hostNode->addChild(new AstNode(AstNodeType::Text, 'com'));244 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));245 $pathNode->addChild(new AstNode(AstNodeType::Text, 'foo'));246 $pathNode->addChild(new AstNode(AstNodeType::Text, '.'));247 $pathNode->addChild(new AstNode(AstNodeType::Text, 'bar'));248 $this->assertEquals($expectedAst, $this->parser->parse($tokens));249 }250 public function testParsingQuotedStringOnlyPathCreatesSingleString(): void251 {252 $tokens = new TokenStream([253 new Token(TokenType::Punctuation, '/'),254 new Token(TokenType::QuotedString, '"12345"')255 ]);256 $expectedAst = new AstNode(AstNodeType::Root, null);257 $pathNode = new AstNode(AstNodeType::Path, null);258 $expectedAst->addChild($pathNode);259 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));260 $pathNode->addChild(new AstNode(AstNodeType::Text, '"12345"'));261 $this->assertEquals($expectedAst, $this->parser->parse($tokens));262 }263 public function testParsingSequentialVariablesThrowsException(): void264 {265 $this->expectException(UnexpectedTokenException::class);266 $this->expectExceptionMessage('Cannot have consecutive variables without a delimiter');267 $tokens = new TokenStream([268 new Token(TokenType::Punctuation, '/'),269 new Token(TokenType::Variable, 'foo'),270 new Token(TokenType::Variable, 'foo')271 ]);272 $this->parser->parse($tokens);273 }274 public function testParsingUnclosedConstraintParenthesisThrowsException(): void275 {276 $this->expectException(UnexpectedTokenException::class);277 $this->expectExceptionMessage('Expected closing parenthesis after constraints, got ' . TokenType::Eof->name);278 $tokens = new TokenStream([279 new Token(TokenType::Punctuation, '/'),280 new Token(TokenType::Variable, 'foo'),281 new Token(TokenType::Punctuation, '('),282 new Token(TokenType::Text, 'bar'),283 ]);284 $this->parser->parse($tokens);285 }286 public function testParsingVariableInPathCreatesVariableNameNode(): void287 {288 $tokens = new TokenStream([289 new Token(TokenType::Punctuation, '/'),290 new Token(TokenType::Variable, 'foo')291 ]);292 $expectedAst = new AstNode(AstNodeType::Root, null);293 $pathNode = new AstNode(AstNodeType::Path, null);294 $expectedAst->addChild($pathNode);295 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));296 $pathNode->addChild(new AstNode(AstNodeType::Variable, 'foo'));297 $this->assertEquals($expectedAst, $this->parser->parse($tokens));298 }299 public function testParsingVariableInPathWithConstraintWithMultipleParametersCreatesCorrectNodes(): void300 {301 $tokens = new TokenStream([302 new Token(TokenType::Punctuation, '/'),303 new Token(TokenType::Variable, 'foo'),304 new Token(TokenType::Punctuation, '('),305 new Token(TokenType::Text, 'bar'),306 new Token(TokenType::Punctuation, '('),307 new Token(TokenType::QuotedString, 'baz'),308 new Token(TokenType::Punctuation, ','),309 new Token(TokenType::Text, 'blah'),310 new Token(TokenType::Punctuation, ')'),311 new Token(TokenType::Punctuation, ')')312 ]);313 $expectedAst = new AstNode(AstNodeType::Root, null);314 $pathNode = new AstNode(AstNodeType::Path, null);315 $expectedAst->addChild($pathNode);316 $variableConstraintNode = new AstNode(AstNodeType::VariableConstraint, 'bar');317 $variableConstraintNode->addChild(new AstNode(AstNodeType::VariableConstraintParameters, ['baz', 'blah']));318 $variableNode = new AstNode(AstNodeType::Variable, 'foo');319 $variableNode->addChild($variableConstraintNode);320 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));321 $pathNode->addChild($variableNode);322 $this->assertEquals($expectedAst, $this->parser->parse($tokens));323 }324 public function testParsingVariableInPathWithConstraintWithNoParametersCreatesCorrectNodes(): void325 {326 $tokens = new TokenStream([327 new Token(TokenType::Punctuation, '/'),328 new Token(TokenType::Variable, 'foo'),329 new Token(TokenType::Punctuation, '('),330 new Token(TokenType::Text, 'bar'),331 new Token(TokenType::Punctuation, ')')332 ]);333 $expectedAst = new AstNode(AstNodeType::Root, null);334 $pathNode = new AstNode(AstNodeType::Path, null);335 $expectedAst->addChild($pathNode);336 $variableConstraintNode = new AstNode(AstNodeType::VariableConstraint, 'bar');337 $variableNode = new AstNode(AstNodeType::Variable, 'foo');338 $variableNode->addChild($variableConstraintNode);339 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));340 $pathNode->addChild($variableNode);341 $this->assertEquals($expectedAst, $this->parser->parse($tokens));342 }343 public function testParsingVariableInPathWithConstraintWithSingleParameterCreatesCorrectNodes(): void344 {345 $tokens = new TokenStream([346 new Token(TokenType::Punctuation, '/'),347 new Token(TokenType::Variable, 'foo'),348 new Token(TokenType::Punctuation, '('),349 new Token(TokenType::Text, 'bar'),350 new Token(TokenType::Punctuation, '('),351 new Token(TokenType::QuotedString, 'baz'),352 new Token(TokenType::Punctuation, ')'),353 new Token(TokenType::Punctuation, ')')354 ]);355 $expectedAst = new AstNode(AstNodeType::Root, null);356 $pathNode = new AstNode(AstNodeType::Path, null);357 $expectedAst->addChild($pathNode);358 $variableConstraintNode = new AstNode(AstNodeType::VariableConstraint, 'bar');359 $variableConstraintNode->addChild(new AstNode(AstNodeType::VariableConstraintParameters, ['baz']));360 $variableNode = new AstNode(AstNodeType::Variable, 'foo');361 $variableNode->addChild($variableConstraintNode);362 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));363 $pathNode->addChild($variableNode);364 $this->assertEquals($expectedAst, $this->parser->parse($tokens));365 }366 public function testParsingVariableInPathWithConstraintButWithNoSlugThrowsException(): void367 {368 $this->expectException(UnexpectedTokenException::class);369 $this->expectExceptionMessage('Expected constraint name, got ' . TokenType::Punctuation->name);370 $tokens = new TokenStream([371 new Token(TokenType::Punctuation, '/'),372 new Token(TokenType::Variable, 'foo'),373 new Token(TokenType::Punctuation, '('),374 new Token(TokenType::Punctuation, ')')375 ]);376 $this->parser->parse($tokens);377 }378 public function testParsingVariableInPathWithConstraintWithTrailingCommaDoesNotThrowException(): void379 {380 $tokens = new TokenStream([381 new Token(TokenType::Punctuation, '/'),382 new Token(TokenType::Variable, 'foo'),383 new Token(TokenType::Punctuation, '('),384 new Token(TokenType::Text, 'bar'),385 new Token(TokenType::Punctuation, '('),386 new Token(TokenType::QuotedString, 'baz'),387 new Token(TokenType::Punctuation, ','),388 new Token(TokenType::Punctuation, ')'),389 new Token(TokenType::Punctuation, ')')390 ]);391 $expectedAst = new AstNode(AstNodeType::Root, null);392 $pathNode = new AstNode(AstNodeType::Path, null);393 $expectedAst->addChild($pathNode);394 $variableConstraintNode = new AstNode(AstNodeType::VariableConstraint, 'bar');395 $variableConstraintNode->addChild(new AstNode(AstNodeType::VariableConstraintParameters, ['baz']));396 $variableNode = new AstNode(AstNodeType::Variable, 'foo');397 $variableNode->addChild($variableConstraintNode);398 $pathNode->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));399 $pathNode->addChild($variableNode);400 $this->assertEquals($expectedAst, $this->parser->parse($tokens));401 }402}...
TrieCompilerTest.php
Source:TrieCompilerTest.php
...22use Aphiria\Routing\UriTemplates\Lexers\IUriTemplateLexer;23use Aphiria\Routing\UriTemplates\Lexers\LexingException;24use Aphiria\Routing\UriTemplates\Lexers\TokenStream;25use Aphiria\Routing\UriTemplates\Lexers\UnexpectedTokenException;26use Aphiria\Routing\UriTemplates\Parsers\AstNode;27use Aphiria\Routing\UriTemplates\Parsers\AstNodeType;28use Aphiria\Routing\UriTemplates\Parsers\IUriTemplateParser;29use Aphiria\Routing\UriTemplates\UriTemplate;30use PHPUnit\Framework\MockObject\MockObject;31use PHPUnit\Framework\TestCase;32class TrieCompilerTest extends TestCase33{34 private TrieCompiler $compiler;35 private RouteVariableConstraintFactory $constraintFactory;36 private IUriTemplateParser&MockObject $parser;37 private IUriTemplateLexer&MockObject $lexer;38 private AstNode $ast;39 private RootTrieNode $expectedTrie;40 protected function setUp(): void41 {42 $this->constraintFactory = new RouteVariableConstraintFactory();43 $this->parser = $this->createMock(IUriTemplateParser::class);44 $this->lexer = $this->createMock(IUriTemplateLexer::class);45 $this->ast = new AstNode(AstNodeType::Root, null);46 $this->parser->method('parse')47 ->willReturn($this->ast);48 $this->compiler = new TrieCompiler($this->constraintFactory, $this->parser, $this->lexer);49 $this->expectedTrie = new RootTrieNode();50 }51 public function testCompilingEmptyPathPrependsWithSlash(): void52 {53 $pathAst = (new AstNode(AstNodeType::Path, null))54 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'));55 $this->ast->addChild($pathAst);56 $expectedRoute = $this->createRoute('');57 $this->expectedTrie->addChild(new LiteralTrieNode(58 '',59 [],60 $expectedRoute61 ));62 $this->lexer->expects($this->once())63 ->method('lex')64 ->with('/')65 ->willReturn(new TokenStream([]));66 $this->assertEquals(67 $this->expectedTrie,68 $this->compiler->compile($expectedRoute)69 );70 }71 public function testCompilingHostAddsTrieNodeToLastPathNodeAndOptionalNodes(): void72 {73 $hostAst = (new AstNode(AstNodeType::Host, null))74 ->addChild(new AstNode(AstNodeType::Text, 'example'))75 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'))76 ->addChild(new AstNode(AstNodeType::Text, 'com'));77 $this->ast->addChild($hostAst);78 $pathAst = (new AstNode(AstNodeType::Path, null))79 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))80 ->addChild(new AstNode(AstNodeType::Text, 'foo'))81 ->addChild(82 (new AstNode(AstNodeType::OptionalRoutePart, '['))83 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))84 ->addChild(new AstNode(AstNodeType::Text, 'bar'))85 );86 $this->ast->addChild($pathAst);87 $hostTemplate = 'example.com';88 $pathTemplate = '/foo[/bar]';89 $expectedRoute = $this->createRoute($pathTemplate, $hostTemplate);90 $expectedHostTrie = new RootTrieNode([91 new LiteralTrieNode(92 'com',93 [94 new LiteralTrieNode(95 'example',96 [],97 $expectedRoute98 )99 ]100 )101 ]);102 $this->expectedTrie->addChild(new LiteralTrieNode(103 'foo',104 [105 new LiteralTrieNode('bar', [], [], $expectedHostTrie)106 ],107 [],108 $expectedHostTrie109 ));110 $this->lexer->expects($this->once())111 ->method('lex')112 ->with($hostTemplate . $pathTemplate)113 ->willReturn(new TokenStream([]));114 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));115 }116 public function testCompilingHostWithOptionalPartAddsRouteToItAndLastNonOptionalHostPart(): void117 {118 $hostAst = (new AstNode(AstNodeType::Host, null))119 ->addChild(120 (new AstNode(AstNodeType::OptionalRoutePart, '['))121 ->addChild(new AstNode(AstNodeType::Text, 'api'))122 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'))123 )124 ->addChild(new AstNode(AstNodeType::Text, 'example'))125 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '.'))126 ->addChild(new AstNode(AstNodeType::Text, 'com'));127 $this->ast->addChild($hostAst);128 $pathAst = (new AstNode(AstNodeType::Path, null))129 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))130 ->addChild(new AstNode(AstNodeType::Text, 'foo'));131 $this->ast->addChild($pathAst);132 $hostTemplate = 'example.com';133 $pathTemplate = '/foo';134 $expectedRoute = $this->createRoute($pathTemplate, $hostTemplate);135 $this->expectedTrie->addChild(new LiteralTrieNode(136 'foo',137 [],138 [],139 new RootTrieNode([140 new LiteralTrieNode(141 'com',142 [143 new LiteralTrieNode(144 'example',145 [146 new LiteralTrieNode(147 'api',148 [],149 $expectedRoute150 )151 ],152 $expectedRoute153 )154 ]155 )156 ])157 ));158 $this->lexer->expects($this->once())159 ->method('lex')160 ->with($hostTemplate . $pathTemplate)161 ->willReturn(new TokenStream([]));162 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));163 }164 public function testCompilingInvalidVariableNodeThrowsException(): void165 {166 $this->expectException(InvalidUriTemplateException::class);167 $this->expectExceptionMessage('Unexpected node type ' . AstNodeType::Path->name);168 $variableNode = new AstNode(AstNodeType::Variable, 'foo');169 // Add an invalid child to the variable node170 $variableNode->addChild(new AstNode(AstNodeType::Path, null));171 $pathAst = (new AstNode(AstNodeType::Path, null))172 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))173 ->addChild($variableNode);174 $this->ast->addChild($pathAst);175 $pathTemplate = '/:foo';176 $expectedRoute = $this->createRoute($pathTemplate);177 $this->expectedTrie->addChild(new VariableTrieNode(178 new RouteVariable('foo'),179 [],180 $expectedRoute181 ));182 $this->lexer->expects($this->once())183 ->method('lex')184 ->with($pathTemplate)185 ->willReturn(new TokenStream([]));186 $this->compiler->compile($expectedRoute);187 }188 public function testCompilingPathVariableCreatesVariableNodeWithRouteVariable(): void189 {190 $pathAst = (new AstNode(AstNodeType::Path, null))191 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))192 ->addChild(new AstNode(AstNodeType::Variable, 'foo'));193 $this->ast->addChild($pathAst);194 $pathTemplate = '/:foo';195 $expectedRoute = $this->createRoute($pathTemplate);196 $this->expectedTrie->addChild(new VariableTrieNode(197 new RouteVariable('foo'),198 [],199 $expectedRoute200 ));201 $this->lexer->expects($this->once())202 ->method('lex')203 ->with($pathTemplate)204 ->willReturn(new TokenStream([]));205 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));206 }207 public function testCompilingPathVariableWithMultipleConstraintsAndParamsCreatesVariableNodeWithConstraints(): void208 {209 // Set up AST210 $constraint1Node = (new AstNode(AstNodeType::VariableConstraint, 'r1'))211 ->addChild(new AstNode(AstNodeType::VariableConstraintParameters, ['p1', 'p2']));212 $constraint2Node = (new AstNode(AstNodeType::VariableConstraint, 'r2'))213 ->addChild(new AstNode(AstNodeType::VariableConstraintParameters, ['p3', 'p4']));214 $variableNode = (new AstNode(AstNodeType::Variable, 'foo'))215 ->addChild($constraint1Node)216 ->addChild($constraint2Node);217 $pathAst = (new AstNode(AstNodeType::Path, null))218 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))219 ->addChild($variableNode);220 $this->ast->addChild($pathAst);221 // Set up constraint factory222 /** @var IRouteVariableConstraint&MockObject $constraint1 */223 $constraint1 = $this->createMock(IRouteVariableConstraint::class);224 /** @var IRouteVariableConstraint&MockObject $constraint2 */225 $constraint2 = $this->createMock(IRouteVariableConstraint::class);226 $this->constraintFactory->registerConstraintFactory('r1', fn (string $p1, string $p2) => $constraint1);227 $this->constraintFactory->registerConstraintFactory('r2', fn (string $p1, string $p2) => $constraint1);228 // Test compiling229 $pathTemplate = '/:foo(r1(p1,p2),r2(p3,p4))';230 $expectedRoute = $this->createRoute($pathTemplate);231 $this->expectedTrie->addChild(new VariableTrieNode(232 new RouteVariable('foo', [$constraint1, $constraint2]),233 [],234 $expectedRoute235 ));236 $this->lexer->expects($this->once())237 ->method('lex')238 ->with($pathTemplate)239 ->willReturn(new TokenStream([]));240 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));241 }242 public function testCompilingPathVariableWithNonConstraintChildThrowsException(): void243 {244 $this->expectException(InvalidUriTemplateException::class);245 $constraintNode = (new AstNode(AstNodeType::VariableConstraint, 'foo'))246 ->addChild(new AstNode(AstNodeType::Text, 'bar'));247 $pathAst = (new AstNode(AstNodeType::Path, null))248 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))249 ->addChild($constraintNode);250 $this->ast->addChild($pathAst);251 $pathTemplate = '/:foo';252 $this->lexer->expects($this->once())253 ->method('lex')254 ->with($pathTemplate)255 ->willReturn(new TokenStream([]));256 $this->compiler->compile($this->createRoute($pathTemplate));257 }258 public function testCompilingPathVariableWithConstraintsCreatesVariableNodeWithConstraints(): void259 {260 // Set up AST261 $variableNode = (new AstNode(AstNodeType::Variable, 'foo'))262 ->addChild(new AstNode(AstNodeType::VariableConstraint, 'r1'));263 $pathAst = (new AstNode(AstNodeType::Path, null))264 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))265 ->addChild($variableNode);266 $this->ast->addChild($pathAst);267 // Set up constraint factory268 /** @var IRouteVariableConstraint&MockObject $constraint */269 $constraint = $this->createMock(IRouteVariableConstraint::class);270 $this->constraintFactory->registerConstraintFactory('r1', fn () => $constraint);271 // Test compiling272 $pathTemplate = '/:foo(r1)';273 $expectedRoute = $this->createRoute($pathTemplate);274 $this->expectedTrie->addChild(new VariableTrieNode(275 new RouteVariable('foo', [$constraint]),276 [],277 $expectedRoute278 ));279 $this->lexer->expects($this->once())280 ->method('lex')281 ->with($pathTemplate)282 ->willReturn(new TokenStream([]));283 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));284 }285 public function testCompilingRequiredAndOptionalPathSegmentsCreatesNodesWithSameRoute(): void286 {287 $optionalNode = (new AstNode(AstNodeType::OptionalRoutePart))288 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))289 ->addChild(new AstNode(AstNodeType::Text, 'bar'));290 $pathAst = (new AstNode(AstNodeType::Path, null))291 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))292 ->addChild(new AstNode(AstNodeType::Text, 'foo'))293 ->addChild($optionalNode);294 $this->ast->addChild($pathAst);295 $pathTemplate = '/foo[/bar]';296 $expectedRoute = $this->createRoute($pathTemplate);297 $this->expectedTrie->addChild(new LiteralTrieNode(298 'foo',299 [300 new LiteralTrieNode(301 'bar',302 [],303 $expectedRoute304 )305 ],306 $expectedRoute307 ));308 $this->lexer->expects($this->once())309 ->method('lex')310 ->with($pathTemplate)311 ->willReturn(new TokenStream([]));312 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));313 }314 public function testCompilingTextOnlyPathAstAddsRouteToNode(): void315 {316 $pathAst = (new AstNode(AstNodeType::Path, null))317 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))318 ->addChild(new AstNode(AstNodeType::Text, 'foo'));319 $this->ast->addChild($pathAst);320 $pathTemplate = '/foo';321 $expectedRoute = $this->createRoute($pathTemplate);322 $this->expectedTrie->addChild(new LiteralTrieNode(323 'foo',324 [],325 $expectedRoute326 ));327 $this->lexer->expects($this->once())328 ->method('lex')329 ->with($pathTemplate)330 ->willReturn(new TokenStream([]));331 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));332 }333 public function testCompilingVariableOnlyPathAstAddsRouteToNode(): void334 {335 $pathAst = (new AstNode(AstNodeType::Path, null))336 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))337 ->addChild(new AstNode(AstNodeType::Variable, 'foo'));338 $this->ast->addChild($pathAst);339 $pathTemplate = '/:foo';340 $expectedRoute = $this->createRoute($pathTemplate);341 $this->expectedTrie->addChild(new VariableTrieNode(342 new RouteVariable('foo'),343 [],344 $expectedRoute345 ));346 $this->lexer->expects($this->once())347 ->method('lex')348 ->with($pathTemplate)349 ->willReturn(new TokenStream([]));350 $this->assertEquals($this->expectedTrie, $this->compiler->compile($expectedRoute));351 }352 public function testConstructingCompilerWithoutConstraintsStillRegistersDefaultOnes(): void353 {354 // Set up AST355 $variableNode = (new AstNode(AstNodeType::Variable, 'foo'))356 ->addChild(new AstNode(AstNodeType::VariableConstraint, 'int'));357 $pathAst = (new AstNode(AstNodeType::Path, null))358 ->addChild(new AstNode(AstNodeType::SegmentDelimiter, '/'))359 ->addChild($variableNode);360 $this->ast->addChild($pathAst);361 // Test compiling362 $pathTemplate = '/:foo(int)';363 $expectedRoute = $this->createRoute($pathTemplate);364 $this->expectedTrie->addChild(new VariableTrieNode(365 new RouteVariable('foo', [new IntegerConstraint()]),366 [],367 $expectedRoute368 ));369 $this->lexer->expects($this->once())370 ->method('lex')371 ->with($pathTemplate)372 ->willReturn(new TokenStream([]));...
AbstractASTNode.php
Source:AbstractASTNode.php
1<?php2/**3 * This file is part of PDepend.4 *5 * PHP Version 56 *7 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.8 * All rights reserved.9 *10 * Redistribution and use in source and binary forms, with or without11 * modification, are permitted provided that the following conditions12 * are met:13 *14 * * Redistributions of source code must retain the above copyright15 * notice, this list of conditions and the following disclaimer.16 *17 * * Redistributions in binary form must reproduce the above copyright18 * notice, this list of conditions and the following disclaimer in19 * the documentation and/or other materials provided with the20 * distribution.21 *22 * * Neither the name of Manuel Pichler nor the names of his23 * contributors may be used to endorse or promote products derived24 * from this software without specific prior written permission.25 *26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE37 * POSSIBILITY OF SUCH DAMAGE.38 *39 * @copyright 2008-2017 Manuel Pichler. All rights reserved.40 * @license http://www.opensource.org/licenses/bsd-license.php BSD License41 * @since 0.9.642 */43namespace PDepend\Source\AST;44/**45 * This is an abstract base implementation of the ast node interface.46 *47 * @copyright 2008-2017 Manuel Pichler. All rights reserved.48 * @license http://www.opensource.org/licenses/bsd-license.php BSD License49 * @since 0.9.650 */51abstract class AbstractASTNode implements ASTNode52{53 /**54 * Parsed child nodes of this node.55 *56 * @var \PDepend\Source\AST\ASTNode[]57 */58 protected $nodes = array();59 /**60 * The parent node of this node or <b>null</b> when this node is the root61 * of a node tree.62 *63 * @var \PDepend\Source\AST\ASTNode64 */65 protected $parent = null;66 /**67 * An optional doc comment for this node.68 *69 * @var string70 */71 protected $comment = null;72 /**73 * Metadata for this node instance, serialized in a string. This string74 * contains the start, end line, and the start, end column and the node75 * image in a colon seperated string.76 *77 * @var string78 * @since 0.10.479 */80 protected $metadata = '::::';81 /**82 * Constructs a new ast node instance.83 *84 * @param string $image The source image for this node.85 */86 public function __construct($image = null)87 {88 $this->metadata = str_repeat(':', $this->getMetadataSize() - 1);89 $this->setImage($image);90 }91 /**92 * Sets the image for this ast node.93 *94 * @param string $image95 * @return void96 */97 public function setImage($image)98 {99 $this->setMetadata(4, $image);100 }101 /**102 * Returns the source image of this ast node.103 *104 * @return string105 */106 public function getImage()107 {108 return $this->getMetadata(4);109 }110 /**111 * Returns the start line for this ast node.112 *113 * @return integer114 */115 public function getStartLine()116 {117 return $this->getMetadataInteger(0);118 }119 /**120 * Returns the start column for this ast node.121 *122 * @return integer123 */124 public function getStartColumn()125 {126 return $this->getMetadataInteger(2);127 }128 /**129 * Returns the end line for this ast node.130 *131 * @return integer132 */133 public function getEndLine()134 {135 return $this->getMetadataInteger(1);136 }137 /**138 * Returns the end column for this ast node.139 *140 * @return integer141 */142 public function getEndColumn()143 {144 return $this->getMetadataInteger(3);145 }146 /**147 * For better performance we have moved the single setter methods for the148 * node columns and lines into this configure method.149 *150 * @param integer $startLine151 * @param integer $endLine152 * @param integer $startColumn153 * @param integer $endColumn154 * @return void155 * @since 0.9.10156 */157 public function configureLinesAndColumns(158 $startLine,159 $endLine,160 $startColumn,161 $endColumn162 ) {163 $this->setMetadataInteger(0, $startLine);164 $this->setMetadataInteger(1, $endLine);165 $this->setMetadataInteger(2, $startColumn);166 $this->setMetadataInteger(3, $endColumn);167 }168 /**169 * Returns an integer value that was stored under the given index.170 *171 * @param integer $index172 * @return integer173 * @since 0.10.4174 */175 protected function getMetadataInteger($index)176 {177 return (int) $this->getMetadata($index);178 }179 /**180 * Stores an integer value under the given index in the internally used data181 * string.182 *183 * @param integer $index184 * @param integer $value185 * @return void186 * @since 0.10.4187 */188 protected function setMetadataInteger($index, $value)189 {190 $this->setMetadata($index, $value);191 }192 /**193 * Returns a boolean value that was stored under the given index.194 *195 * @param integer $index196 * @return boolean197 * @since 0.10.4198 */199 protected function getMetadataBoolean($index)200 {201 return (bool) $this->getMetadata($index);202 }203 /**204 * Stores a boolean value under the given index in the internally used data205 * string.206 *207 * @param integer $index208 * @param boolean $value209 * @return void210 * @since 0.10.4211 */212 protected function setMetadataBoolean($index, $value)213 {214 $this->setMetadata($index, $value ? 1 : 0);215 }216 /**217 * Returns the value that was stored under the given index.218 *219 * @param integer $index220 * @return mixed221 * @since 0.10.4222 */223 protected function getMetadata($index)224 {225 $metadata = explode(':', $this->metadata, $this->getMetadataSize());226 return $metadata[$index];227 }228 /**229 * Stores the given value under the given index in an internal storage230 * container.231 *232 * @param integer $index233 * @param mixed $value234 * @return void235 * @since 0.10.4236 */237 protected function setMetadata($index, $value)238 {239 $metadata = explode(':', $this->metadata, $this->getMetadataSize());240 $metadata[$index] = $value;241 $this->metadata = join(':', $metadata);242 }243 /**244 * Returns the total number of the used property bag.245 *246 * @return integer247 * @since 0.10.4248 */249 protected function getMetadataSize()250 {251 return 5;252 }253 /**254 * Returns the node instance for the given index or throws an exception.255 *256 * @param integer $index257 * @return \PDepend\Source\AST\ASTNode258 * @throws \OutOfBoundsException When no node exists at the given index.259 */260 public function getChild($index)261 {262 if (isset($this->nodes[$index])) {263 return $this->nodes[$index];264 }265 throw new \OutOfBoundsException(266 sprintf(267 'No node found at index %d in node of type: %s',268 $index,269 get_class($this)270 )271 );272 }273 /**274 * This method returns all direct children of the actual node.275 *276 * @return \PDepend\Source\AST\ASTNode[]277 */278 public function getChildren()279 {280 return $this->nodes;281 }282 /**283 * This method will search recursive for the first child node that is an284 * instance of the given <b>$targetType</b>. The returned value will be285 * <b>null</b> if no child exists for that.286 *287 * @param string $targetType288 * @return \PDepend\Source\AST\ASTNode289 */290 public function getFirstChildOfType($targetType)291 {292 foreach ($this->nodes as $node) {293 if ($node instanceof $targetType) {294 return $node;295 }296 if (($child = $node->getFirstChildOfType($targetType)) !== null) {297 return $child;298 }299 }300 return null;301 }302 /**303 * This method will search recursive for all child nodes that are an304 * instance of the given <b>$targetType</b>. The returned value will be305 * an empty <b>array</b> if no child exists for that.306 *307 * @param string $targetType Searched class or interface type.308 * @param array &$results Already found node instances. This parameter309 * is only for internal usage.310 * @return \PDepend\Source\AST\ASTNode[]311 */312 public function findChildrenOfType($targetType, array &$results = array())313 {314 foreach ($this->nodes as $node) {315 if ($node instanceof $targetType) {316 $results[] = $node;317 }318 $node->findChildrenOfType($targetType, $results);319 }320 return $results;321 }322 /**323 * This method adds a new child node at the first position of the children.324 *325 * @param \PDepend\Source\AST\ASTNode $node326 * @return void327 */328 public function prependChild(ASTNode $node)329 {330 array_unshift($this->nodes, $node);331 $node->setParent($this);332 }333 /**334 * This method adds a new child node to this node instance.335 *336 * @param \PDepend\Source\AST\ASTNode $node337 * @return void338 */339 public function addChild(ASTNode $node)340 {341 $this->nodes[] = $node;342 $node->setParent($this);343 }344 /**345 * Returns the parent node of this node or <b>null</b> when this node is346 * the root of a node tree.347 *348 * @return \PDepend\Source\AST\ASTNode349 */350 public function getParent()351 {352 return $this->parent;353 }354 /**355 * Traverses up the node tree and finds all parent nodes that are instances356 * of <b>$parentType</b>.357 *358 * @param string $parentType359 * @return \PDepend\Source\AST\ASTNode[]360 */361 public function getParentsOfType($parentType)362 {363 $parents = array();364 $parentNode = $this->parent;365 while (is_object($parentNode)) {366 if ($parentNode instanceof $parentType) {367 array_unshift($parents, $parentNode);368 }369 $parentNode = $parentNode->getParent();370 }371 return $parents;372 }373 /**374 * Sets the parent node of this node.375 *376 * @param \PDepend\Source\AST\ASTNode $node377 * @return void378 */379 public function setParent(ASTNode $node)380 {381 $this->parent = $node;382 }383 /**384 * Returns a doc comment for this node or <b>null</b> when no comment was385 * found.386 *387 * @return string388 */389 public function getComment()390 {391 return $this->comment;392 }393 /**394 * Sets the raw doc comment for this node.395 *396 * @param string $comment The doc comment block for this node.397 *398 * @return void399 */400 public function setComment($comment)401 {402 $this->comment = $comment;403 }404 /**405 * The magic sleep method will be called by PHP's runtime environment right406 * before an instance of this class gets serialized. It should return an407 * array with those property names that should be serialized for this class.408 *409 * @return array410 * @since 0.10.0411 */412 public function __sleep()413 {414 return array(415 'comment',416 'metadata',417 'nodes'418 );419 }420 /**421 * The magic wakeup method will be called by PHP's runtime environment when422 * a previously serialized object gets unserialized. This implementation of423 * the wakeup method restores the dependencies between an ast node and the424 * node's children.425 *426 * @return void427 * @since 0.10.0428 */429 public function __wakeup()430 {431 foreach ($this->nodes as $node) {432 $node->setParent($this);433 }434 }435}...
UnusedLocalVariable.php
Source:UnusedLocalVariable.php
1<?php2/**3 * This file is part of PHP Mess Detector.4 *5 * Copyright (c) Manuel Pichler <mapi@phpmd.org>.6 * All rights reserved.7 *8 * Licensed under BSD License9 * For full copyright and license information, please see the LICENSE file.10 * Redistributions of files must retain the above copyright notice.11 *12 * @author Manuel Pichler <mapi@phpmd.org>13 * @copyright Manuel Pichler. All rights reserved.14 * @license https://opensource.org/licenses/bsd-license.php BSD License15 * @link http://phpmd.org/16 */17namespace PHPMD\Rule;18use PHPMD\AbstractNode;19use PHPMD\Node\AbstractCallableNode;20use PHPMD\Node\ASTNode;21/**22 * This rule collects all local variables within a given function or method23 * that are not used by any code in the analyzed source artifact.24 */25class UnusedLocalVariable extends AbstractLocalVariable implements FunctionAware, MethodAware26{27 /**28 * Found variable images within a single method or function.29 *30 * @var array(string)31 */32 private $images = array();33 /**34 * This method checks that all local variables within the given function or35 * method are used at least one time.36 *37 * @param \PHPMD\AbstractNode $node38 * @return void39 */40 public function apply(AbstractNode $node)41 {42 $this->images = array();43 /** @var $node AbstractCallableNode */44 $this->collectVariables($node);45 $this->removeParameters($node);46 foreach ($this->images as $nodes) {47 if (count($nodes) === 1) {48 $this->doCheckNodeImage($nodes[0]);49 }50 }51 }52 /**53 * This method removes all variables from the <b>$_images</b> property that54 * are also found in the formal parameters of the given method or/and55 * function node.56 *57 * @param \PHPMD\Node\AbstractCallableNode $node58 * @return void59 */60 private function removeParameters(AbstractCallableNode $node)61 {62 // Get formal parameter container63 $parameters = $node->getFirstChildOfType('FormalParameters');64 // Now get all declarators in the formal parameters container65 $declarators = $parameters->findChildrenOfType('VariableDeclarator');66 foreach ($declarators as $declarator) {67 unset($this->images[$declarator->getImage()]);68 }69 }70 /**71 * This method collects all local variable instances from the given72 * method/function node and stores their image in the <b>$_images</b>73 * property.74 *75 *76 * @param \PHPMD\Node\AbstractCallableNode $node77 * @return void78 */79 private function collectVariables(AbstractCallableNode $node)80 {81 foreach ($node->findChildrenOfType('Variable') as $variable) {82 /** @var $variable ASTNode */83 if ($this->isLocal($variable)) {84 $this->collectVariable($variable);85 }86 }87 foreach ($node->findChildrenOfType('CompoundVariable') as $variable) {88 $this->collectCompoundVariableInString($variable);89 }90 foreach ($node->findChildrenOfType('VariableDeclarator') as $variable) {91 $this->collectVariable($variable);92 }93 foreach ($node->findChildrenOfType('FunctionPostfix') as $func) {94 if ($this->isFunctionNameEndingWith($func, 'compact')) {95 foreach ($func->findChildrenOfType('Literal') as $literal) {96 /** @var $literal ASTNode */97 $this->collectLiteral($literal);98 }99 }100 }101 }102 /**103 * Stores the given compound variable node in an internal list of found variables.104 *105 * @param \PHPMD\Node\ASTNode $node106 * @return void107 */108 private function collectCompoundVariableInString(ASTNode $node)109 {110 $parentNode = $node->getParent()->getNode();111 $candidateParentNodes = $node->getParentsOfType('PDepend\Source\AST\ASTString');112 if (in_array($parentNode, $candidateParentNodes)) {113 $variablePrefix = $node->getImage();114 foreach ($node->findChildrenOfType('Expression') as $child) {115 $variableName = $child->getImage();116 $variableImage = $variablePrefix . $variableName;117 $this->storeImage($variableImage, $node);118 }119 }120 }121 /**122 * Stores the given variable node in an internal list of found variables.123 *124 * @param \PHPMD\Node\ASTNode $node125 * @return void126 */127 private function collectVariable(ASTNode $node)128 {129 $imageName = $node->getImage();130 $this->storeImage($imageName, $node);131 }132 /**133 * Safely add node to $this->images.134 *135 * @param string $imageName the name to store the node as136 * @param \PHPMD\Node\ASTNode $node the node being stored137 * @return void138 */139 private function storeImage($imageName, ASTNode $node)140 {141 if (!isset($this->images[$imageName])) {142 $this->images[$imageName] = array();143 }144 $this->images[$imageName][] = $node;145 }146 /**147 * Stores the given literal node in an internal list of found variables.148 *149 * @param \PHPMD\Node\ASTNode $node150 * @return void151 */152 private function collectLiteral(ASTNode $node)153 {154 $variable = '$' . trim($node->getImage(), '\'');155 if (!isset($this->images[$variable])) {156 $this->images[$variable] = array();157 }158 $this->images[$variable][] = $node;159 }160 /**161 * Template method that performs the real node image check.162 *163 * @param ASTNode $node164 * @return void165 */166 protected function doCheckNodeImage(ASTNode $node)167 {168 if ($this->isNameAllowedInContext($node)) {169 return;170 }171 if ($this->isUnusedForeachVariableAllowed($node)) {172 return;173 }174 $exceptions = $this->getExceptionsList();175 if (in_array(substr($node->getImage(), 1), $exceptions)) {176 return;177 }178 $this->addViolation($node, array($node->getImage()));179 }180 /**181 * Checks if a short name is acceptable in the current context. For the182 * moment these contexts are the init section of a for-loop and short183 * variable names in catch-statements.184 *185 * @param \PHPMD\AbstractNode $node186 * @return boolean187 */188 private function isNameAllowedInContext(AbstractNode $node)189 {190 return $this->isChildOf($node, 'CatchStatement');191 }192 /**193 * Checks if an unused foreach variable (key or variable) is allowed.194 *195 * If it's not a foreach variable, it returns always false.196 *197 * @param \PHPMD\Node\ASTNode $variable The variable to check.198 * @return bool True if allowed, else false.199 */200 private function isUnusedForeachVariableAllowed(ASTNode $variable)201 {202 $isForeachVariable = $this->isChildOf($variable, 'ForeachStatement');203 if (!$isForeachVariable) {204 return false;205 }206 return $this->getBooleanProperty('allow-unused-foreach-variables');207 }208 /**209 * Checks if the given node is a direct or indirect child of a node with210 * the given type.211 *212 * @param \PHPMD\AbstractNode $node213 * @param string $type214 * @return boolean215 */216 private function isChildOf(AbstractNode $node, $type)217 {218 $parent = $node->getParent();219 return $parent->isInstanceOf($type);220 }221 /**222 * Gets array of exceptions from property223 *224 * @return array225 */226 private function getExceptionsList()227 {228 try {229 $exceptions = $this->getStringProperty('exceptions');230 } catch (\OutOfBoundsException $e) {231 $exceptions = '';232 }233 return explode(',', $exceptions);234 }235}...
UnusedPrivateField.php
Source:UnusedPrivateField.php
1<?php2/**3 * This file is part of PHP Mess Detector.4 *5 * Copyright (c) Manuel Pichler <mapi@phpmd.org>.6 * All rights reserved.7 *8 * Licensed under BSD License9 * For full copyright and license information, please see the LICENSE file.10 * Redistributions of files must retain the above copyright notice.11 *12 * @author Manuel Pichler <mapi@phpmd.org>13 * @copyright Manuel Pichler. All rights reserved.14 * @license https://opensource.org/licenses/bsd-license.php BSD License15 * @link http://phpmd.org/16 */17namespace PHPMD\Rule;18use PHPMD\AbstractNode;19use PHPMD\AbstractRule;20use PHPMD\Node\ASTNode;21use PHPMD\Node\ClassNode;22/**23 * This rule collects all private fields in a class that aren't used in any24 * method of the analyzed class.25 */26class UnusedPrivateField extends AbstractRule implements ClassAware27{28 /**29 * Collected private fields/variable declarators in the currently processed30 * class.31 *32 * @var \PHPMD\Node\ASTNode[]33 */34 private $fields = array();35 /**36 * This method checks that all private class properties are at least accessed37 * by one method.38 *39 * @param \PHPMD\AbstractNode $node40 * @return void41 */42 public function apply(AbstractNode $node)43 {44 /** @var ClassNode $field */45 foreach ($this->collectUnusedPrivateFields($node) as $field) {46 $this->addViolation($field, array($field->getImage()));47 }48 }49 /**50 * This method collects all private fields that aren't used by any class51 * method.52 *53 * @param \PHPMD\Node\ClassNode $class54 * @return \PHPMD\AbstractNode[]55 */56 private function collectUnusedPrivateFields(ClassNode $class)57 {58 $this->fields = array();59 $this->collectPrivateFields($class);60 $this->removeUsedFields($class);61 return $this->fields;62 }63 /**64 * This method collects all private fields in the given class and stores65 * them in the <b>$_fields</b> property.66 *67 * @param \PHPMD\Node\ClassNode $class68 * @return void69 */70 private function collectPrivateFields(ClassNode $class)71 {72 foreach ($class->findChildrenOfType('FieldDeclaration') as $declaration) {73 /** @var ASTNode $declaration */74 if ($declaration->isPrivate()) {75 $this->collectPrivateField($declaration);76 }77 }78 }79 /**80 * This method extracts all variable declarators from the given field81 * declaration and stores them in the <b>$_fields</b> property.82 *83 * @param \PHPMD\Node\ASTNode $declaration84 * @return void85 */86 private function collectPrivateField(ASTNode $declaration)87 {88 $fields = $declaration->findChildrenOfType('VariableDeclarator');89 foreach ($fields as $field) {90 $this->fields[$field->getImage()] = $field;91 }92 }93 /**94 * This method extracts all property postfix nodes from the given class and95 * removes all fields from the <b>$_fields</b> property that are accessed by96 * one of the postfix nodes.97 *98 * @param \PHPMD\Node\ClassNode $class99 * @return void100 */101 private function removeUsedFields(ClassNode $class)102 {103 foreach ($class->findChildrenOfType('PropertyPostfix') as $postfix) {104 /** @var $postfix ASTNode */105 if ($this->isInScopeOfClass($class, $postfix)) {106 $this->removeUsedField($postfix);107 }108 }109 }110 /**111 * This method removes the field from the <b>$_fields</b> property that is112 * accessed through the given property postfix node.113 *114 * @param \PHPMD\Node\ASTNode $postfix115 * @return void116 */117 private function removeUsedField(ASTNode $postfix)118 {119 $image = '$';120 $child = $postfix->getFirstChildOfType('Identifier');121 if ($postfix->getParent()->isStatic()) {122 $image = '';123 $child = $postfix->getFirstChildOfType('Variable');124 }125 if ($this->isValidPropertyNode($child)) {126 unset($this->fields[$image . $child->getImage()]);127 }128 }129 /**130 * Checks if the given node is a valid property node.131 *132 * @param \PHPMD\Node\ASTNode $node133 * @return boolean134 * @since 0.2.6135 */136 protected function isValidPropertyNode(ASTNode $node = null)137 {138 if ($node === null) {139 return false;140 }141 $parent = $node->getParent();142 while (!$parent->isInstanceOf('PropertyPostfix')) {143 if ($parent->isInstanceOf('CompoundVariable')) {144 return false;145 }146 $parent = $parent->getParent();147 if (is_null($parent)) {148 return false;149 }150 }151 return true;152 }153 /**154 * This method checks that the given property postfix is accessed on an155 * instance or static reference to the given class.156 *157 * @param \PHPMD\Node\ClassNode $class158 * @param \PHPMD\Node\ASTNode $postfix159 * @return boolean160 */161 protected function isInScopeOfClass(ClassNode $class, ASTNode $postfix)162 {163 $owner = $this->getOwner($postfix);164 return (165 $owner->isInstanceOf('SelfReference') ||166 $owner->isInstanceOf('StaticReference') ||167 strcasecmp($owner->getImage(), '$this') === 0 ||168 strcasecmp($owner->getImage(), $class->getImage()) === 0169 );170 }171 /**172 * Looks for owner of the given variable.173 *174 * @param \PHPMD\Node\ASTNode $postfix175 * @return \PHPMD\Node\ASTNode176 */177 protected function getOwner(ASTNode $postfix)178 {179 $owner = $postfix->getParent()->getChild(0);180 if ($owner->isInstanceOf('PropertyPostfix')) {181 $owner = $owner->getParent()->getParent()->getChild(0);182 }183 if ($owner->getParent()->isInstanceOf('ArrayIndexExpression')) {184 $owner = $owner->getParent()->getParent()->getChild(0);185 }186 return $owner;187 }188}...
AbstractLocalVariable.php
Source:AbstractLocalVariable.php
1<?php2/**3 * This file is part of PHP Mess Detector.4 *5 * Copyright (c) Manuel Pichler <mapi@phpmd.org>.6 * All rights reserved.7 *8 * Licensed under BSD License9 * For full copyright and license information, please see the LICENSE file.10 * Redistributions of files must retain the above copyright notice.11 *12 * @author Manuel Pichler <mapi@phpmd.org>13 * @copyright Manuel Pichler. All rights reserved.14 * @license https://opensource.org/licenses/bsd-license.php BSD License15 * @link http://phpmd.org/16 */17namespace PHPMD\Rule;18use PHPMD\AbstractNode;19use PHPMD\AbstractRule;20use PHPMD\Node\ASTNode;21/**22 * Base class for rules that rely on local variables.23 *24 * @since 0.2.625 */26abstract class AbstractLocalVariable extends AbstractRule27{28 /**29 * PHP super globals that are available in all php scopes, so that they30 * can never be unused local variables.31 *32 * @var array(string=>boolean)33 * @link http://php.net/manual/en/reserved.variables.php34 */35 private static $superGlobals = array(36 '$argc' => true,37 '$argv' => true,38 '$_COOKIE' => true,39 '$_ENV' => true,40 '$_FILES' => true,41 '$_GET' => true,42 '$_POST' => true,43 '$_REQUEST' => true,44 '$_SERVER' => true,45 '$_SESSION' => true,46 '$GLOBALS' => true,47 '$HTTP_RAW_POST_DATA' => true,48 '$php_errormsg' => true,49 '$http_response_header' => true,50 );51 /**52 * Tests if the given variable node represents a local variable or if it is53 * a static object property or something similar.54 *55 * @param \PHPMD\Node\ASTNode $variable The variable to check.56 * @return boolean57 */58 protected function isLocal(ASTNode $variable)59 {60 return (false === $variable->isThis()61 && $this->isNotSuperGlobal($variable)62 && $this->isRegularVariable($variable)63 );64 }65 /**66 * Tests if the given variable represents one of the PHP super globals67 * that are available in scopes.68 *69 * @param \PHPMD\AbstractNode $variable70 * @return boolean71 */72 protected function isNotSuperGlobal(AbstractNode $variable)73 {74 return !isset(self::$superGlobals[$variable->getImage()]);75 }76 /**77 * Tests if the given variable node is a regular variable an not property78 * or method postfix.79 *80 * @param \PHPMD\Node\ASTNode $variable81 * @return boolean82 */83 protected function isRegularVariable(ASTNode $variable)84 {85 $node = $this->stripWrappedIndexExpression($variable);86 $parent = $node->getParent();87 if ($parent->isInstanceOf('PropertyPostfix')) {88 $primaryPrefix = $parent->getParent();89 if ($primaryPrefix->getParent()->isInstanceOf('MemberPrimaryPrefix')) {90 return !$primaryPrefix->getParent()->isStatic();91 }92 return ($parent->getChild(0)->getNode() !== $node->getNode()93 || !$primaryPrefix->isStatic()94 );95 }96 return true;97 }98 /**99 * Removes all index expressions that are wrapped around the given node100 * instance.101 *102 * @param \PHPMD\Node\ASTNode $node103 * @return \PHPMD\Node\ASTNode104 */105 protected function stripWrappedIndexExpression(ASTNode $node)106 {107 if (false === $this->isWrappedByIndexExpression($node)) {108 return $node;109 }110 $parent = $node->getParent();111 if ($parent->getChild(0)->getNode() === $node->getNode()) {112 return $this->stripWrappedIndexExpression($parent);113 }114 return $node;115 }116 /**117 * Tests if the given variable node os part of an index expression.118 *119 * @param \PHPMD\Node\ASTNode $node120 * @return boolean121 */122 protected function isWrappedByIndexExpression(ASTNode $node)123 {124 return ($node->getParent()->isInstanceOf('ArrayIndexExpression')125 || $node->getParent()->isInstanceOf('StringIndexExpression')126 );127 }128 /**129 * PHP is case insensitive so we should compare function names case130 * insensitive.131 *132 * @param \PHPMD\AbstractNode $node133 * @param string $name134 * @return boolean135 */136 protected function isFunctionNameEqual(AbstractNode $node, $name)137 {138 return (0 === strcasecmp(trim($node->getImage(), '\\'), $name));139 }140 /**141 * AST puts namespace prefix to global functions called from a namespace.142 * This method checks if the last part of function fully qualified name is equal to $name143 *144 * @param \PHPMD\AbstractNode $node145 * @param string $name146 * @return boolean147 */148 protected function isFunctionNameEndingWith(AbstractNode $node, $name)149 {150 $parts = explode('\\', trim($node->getImage(), '\\'));151 return (0 === strcasecmp(array_pop($parts), $name));152 }153}...
DuplicatedArrayKey.php
Source:DuplicatedArrayKey.php
1<?php2/**3 * This file is part of PHP Mess Detector.4 *5 * Copyright (c) Manuel Pichler <mapi@phpmd.org>.6 * All rights reserved.7 *8 * Licensed under BSD License9 * For full copyright and license information, please see the LICENSE file.10 * Redistributions of files must retain the above copyright notice.11 *12 * @author Manuel Pichler <mapi@phpmd.org>13 * @copyright Manuel Pichler. All rights reserved.14 * @license https://opensource.org/licenses/bsd-license.php BSD License15 * @link http://phpmd.org/16 */17namespace PHPMD\Rule\CleanCode;18use PDepend\Source\AST\AbstractASTNode;19use PDepend\Source\AST\ASTArrayElement;20use PDepend\Source\AST\ASTLiteral;21use PDepend\Source\AST\ASTNode as PDependASTNode;22use PHPMD\AbstractNode;23use PHPMD\AbstractRule;24use PHPMD\Node\ASTNode;25use PHPMD\Rule\FunctionAware;26use PHPMD\Rule\MethodAware;27/**28 * Duplicated Array Key Rule29 *30 * This rule detects duplicated array keys.31 *32 * @author RafaÅ Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>33 * @author Kamil Szymanaski <kamil.szymanski@gmail.com>34 */35class DuplicatedArrayKey extends AbstractRule implements MethodAware, FunctionAware36{37 /**38 * Retrieves all arrays from single node and performs comparison logic on it39 *40 * @param AbstractNode $node41 * @return void42 */43 public function apply(AbstractNode $node)44 {45 foreach ($node->findChildrenOfType('Array') as $arrayNode) {46 /** @var ASTNode $arrayNode */47 $this->checkForDuplicatedArrayKeys($arrayNode);48 }49 }50 /**51 * This method checks if a given function or method contains an array literal52 * with duplicated entries for any key and emits a rule violation if so.53 *54 * @param ASTNode $node Array node.55 * @return void56 */57 private function checkForDuplicatedArrayKeys(ASTNode $node)58 {59 $keys = array();60 /** @var ASTArrayElement $arrayElement */61 foreach ($node->getChildren() as $index => $arrayElement) {62 $arrayElement = $this->normalizeKey($arrayElement, $index);63 if (null === $arrayElement) {64 // skip everything that can't be resolved easily65 continue;66 }67 $key = $arrayElement->getImage();68 if (isset($keys[$key])) {69 $this->addViolation($node, array($key, $arrayElement->getStartLine()));70 continue;71 }72 $keys[$key] = $arrayElement;73 }74 }75 /**76 * Changes key name to its string format.77 *78 * To compare keys, we have to cast them to string.79 * Non-associative keys have to use index as its key,80 * while boolean and nulls have to be casted respectively.81 * As current logic doesn't evaluate expressions nor constants,82 * statics, globals, etc. we simply skip them.83 *84 * @param AbstractASTNode $node Array key to evaluate.85 * @param int $index Fallback in case of non-associative arrays86 * @return AbstractASTNode Key name87 */88 private function normalizeKey(AbstractASTNode $node, $index)89 {90 $childCount = count($node->getChildren());91 // Skip, if there is no array key, just an array value92 if ($childCount === 1) {93 return null;94 }95 // non-associative - key name equals to its index96 if ($childCount === 0) {97 $node->setImage((string) $index);98 return $node;99 }100 101 $node = $node->getChild(0);102 if (!($node instanceof ASTLiteral)) {103 // skip expressions, method calls, globals and constants104 return null;105 }106 $node->setImage($this->castStringFromLiteral($node));107 return $node;108 }109 /**110 * Cleans string literals and casts boolean and null values as PHP engine does111 *112 * @param PDependASTNode $key113 * @return string114 */115 private function castStringFromLiteral(PDependASTNode $key)116 {117 $value = $key->getImage();118 switch ($value) {119 case 'false':120 return '0';121 case 'true':122 return '1';123 case 'null':124 return '';125 default:126 return trim($value, '\'""');127 }128 }129}...
ASTNodeTest.php
Source:ASTNodeTest.php
1<?php2/**3 * This file is part of PHP Mess Detector.4 *5 * Copyright (c) 2008-2012, Manuel Pichler <mapi@phpmd.org>.6 * All rights reserved.7 *8 * Redistribution and use in source and binary forms, with or without9 * modification, are permitted provided that the following conditions10 * are met:11 *12 * * Redistributions of source code must retain the above copyright13 * notice, this list of conditions and the following disclaimer.14 *15 * * Redistributions in binary form must reproduce the above copyright16 * notice, this list of conditions and the following disclaimer in17 * the documentation and/or other materials provided with the18 * distribution.19 *20 * * Neither the name of Manuel Pichler nor the names of his21 * contributors may be used to endorse or promote products derived22 * from this software without specific prior written permission.23 *24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE35 * POSSIBILITY OF SUCH DAMAGE.36 *37 * @author Manuel Pichler <mapi@phpmd.org>38 * @copyright 2008-2014 Manuel Pichler. All rights reserved.39 * @license http://www.opensource.org/licenses/bsd-license.php BSD License40 */41namespace PHPMD\Node;42use PHPMD\AbstractTest;43/**44 * Test case for the {@link \PHPMD\Node\ASTNode} class.45 *46 * @author Manuel Pichler <mapi@phpmd.org>47 * @copyright 2008-2014 Manuel Pichler. All rights reserved.48 * @license http://www.opensource.org/licenses/bsd-license.php BSD License49 *50 * @covers \PHPMD\Node\ASTNode51 * @group phpmd52 * @group phpmd::node53 * @group unittest54 */55class ASTNodeTest extends AbstractTest56{57 /**58 * testGetImageDelegatesToGetImageMethodOfWrappedNode59 *60 * @return void61 */62 public function testGetImageDelegatesToGetImageMethodOfWrappedNode()63 {64 $mock = $this->getMock('PDepend\Source\AST\ASTNode');65 $mock->expects($this->once())66 ->method('getImage');67 $node = new ASTNode($mock, __FILE__);68 $node->getImage();69 }70 /**71 * testGetNameDelegatesToGetImageMethodOfWrappedNode72 *73 * @return void74 */75 public function testGetNameDelegatesToGetImageMethodOfWrappedNode()76 {77 $mock = $this->getMock('PDepend\Source\AST\ASTNode');78 $mock->expects($this->once())79 ->method('getImage');80 $node = new ASTNode($mock, __FILE__);81 $node->getName();82 }83 /**84 * testHasSuppressWarningsAnnotationForAlwaysReturnsFalse85 *86 * @return void87 */88 public function testHasSuppressWarningsAnnotationForAlwaysReturnsFalse()89 {90 $mock = $this->getMock('PDepend\Source\AST\ASTNode');91 $node = new ASTNode($mock, __FILE__);92 $rule = $this->getMockForAbstractClass('PHPMD\\AbstractRule');93 $this->assertFalse($node->hasSuppressWarningsAnnotationFor($rule));94 }95 /**96 * testGetParentNameReturnsNull97 *98 * @return void99 */100 public function testGetParentNameReturnsNull()101 {102 $mock = $this->getMock('PDepend\Source\AST\ASTNode');103 $node = new ASTNode($mock, __FILE__);104 $this->assertNull($node->getParentName());105 }106 /**107 * testGetNamespaceNameReturnsNull108 *109 * @return void110 */111 public function testGetNamespaceNameReturnsNull()112 {113 $mock = $this->getMock('PDepend\Source\AST\ASTNode');114 $node = new ASTNode($mock, __FILE__);115 $this->assertNull($node->getNamespaceName());116 }117}...
AstNode
Using AI Code Generation
1require_once 'vendor/autoload.php';2use Behat\Gherkin\Gherkin;3use Behat\Gherkin\Node\FeatureNode;4use Behat\Gherkin\Node\ScenarioNode;5use Behat\Gherkin\Node\StepNode;6use Behat\Gherkin\Node\TableNode;7use Behat\Gherkin\Node\PyStringNode;8use Behat\Gherkin\Node\BackgroundNode;9use Behat\Gherkin\Node\OutlineNode;10use Behat\Gherkin\Node\ExampleNode;11use Behat\Gherkin\Node\StepContainerInterface;12use Behat\Gherkin\Node\FeatureInterface;13use Behat\Gherkin\Node\ScenarioInterface;14use Behat\Gherkin\Node\StepInterface;15use Behat\Gherkin\Node\BackgroundInterface;16use Behat\Gherkin\Node\OutlineInterface;17use Behat\Gherkin\Node\ExampleInterface;18use Behat\Gherkin\Node\StepArgumentInterface;19use Behat\Gherkin\Node\PyStringNode;20use Behat\Gherkin\Node\TableNode;21use Behat\Gherkin\Node\AstNode;22use Behat\Gherkin\Node\BackgroundNode;23use Behat\Gherkin\Node\FeatureNode;24use Behat\Gherkin\Node\OutlineNode;25use Behat\Gherkin\Node\ScenarioNode;26use Behat\Gherkin\Node\StepNode;27use Behat\Gherkin\Node\TableNode;28use Behat\Gherkin\Node\PyStringNode;29use Behat\Gherkin\Node\StepArgumentInterface;30use Behat\Gherkin\Node\StepContainerInterface;31use Behat\Gherkin\Node\FeatureInterface;32use Behat\Gherkin\Node\ScenarioInterface;33use Behat\Gherkin\Node\StepInterface;34use Behat\Gherkin\Node\BackgroundInterface;35use Behat\Gherkin\Node\OutlineInterface;36use Behat\Gherkin\Node\ExampleInterface;
AstNode
Using AI Code Generation
1require_once 'vendor/autoload.php';2use Behat\Gherkin\Node\AstNode;3use Behat\Gherkin\Node\FeatureNode;4use Behat\Gherkin\Node\ScenarioNode;5use Behat\Gherkin\Node\StepNode;6use Behat\Gherkin\Node\TableNode;7use Behat\Gherkin\Node\PyStringNode;8use Behat\Gherkin\Parser;9use Behat\Gherkin\Lexer;10use Behat\Gherkin\Filter\LineFilter;11use Behat\Gherkin\Filter\TagFilter;12use Behat\Gherkin\Filter\NameFilter;13use Behat\Gherkin\Filter\RoleFilter;14use Behat\Gherkin\Filter\FeatureFilter;15use Behat\Gherkin\Filter\ScenarioFilter;16use Behat\Gherkin\Filter\StepFilter;17use Behat\Gherkin\Filter\BackgroundFilter;18use Behat\Gherkin\Filter\OutlineFilter;19use Behat\Gherkin\Filter\ExamplesFilter;20use Behat\Gherkin\FilterFactory;21use Behat\Gherkin\Dumper\GherkinDumper;22use Behat\Gherkin\Node\NodeElement;23use Behat\Gherkin\Node\NodeElementFactory;24use Behat\Gherkin\Node\NodeBuilder;25use Behat\Gherkin\Node\NodeFactory;26use Behat\Gherkin\Node\NodeFactoryInterface;27use Behat\Gherkin\Node\NodeVisitor;28use Behat\Gherkin\Node\NodeVisitorInterface;
AstNode
Using AI Code Generation
1require_once 'vendor/autoload.php';2use Behat\Gherkin\Keywords\ArrayKeywords;3use Behat\Gherkin\Keywords\KeywordsInterface;4use Behat\Gherkin\Keywords\Keywords;5use Behat\Gherkin\Keywords\KeywordsTable;6use Behat\Gherkin\Node\StepNode;7use Behat\Gherkin\Node\ScenarioNode;8use Behat\Gherkin\Node\FeatureNode;9use Behat\Gherkin\Node\BackgroundNode;10use Behat\Gherkin\Node\AstNode;11use Behat\Gherkin\Node\OutlineNode;12use Behat\Gherkin\Node\PyStringNode;13use Behat\Gherkin\Node\TableNode;14use Behat\Gherkin\Node\ExamplesNode;15use Behat\Gherkin\Node\StepContainerInterface;16use Behat\Gherkin\Node\ScenarioLikeInterface;17use Behat\Gherkin\Node\FeatureInterface;18use Behat\Gherkin\Node\StepInterface;19use Behat\Gherkin\Node\NodeInterface;20use Behat\Gherkin\Filter\NameFilter;21use Behat\Gherkin\Filter\TagFilter;22use Behat\Gherkin\Filter\LineFilter;23use Behat\Gherkin\Filter\CompositeFilter;24use Behat\Gherkin\Filter\FilterInterface;25use Behat\Gherkin\Loader\LoaderInterface;26use Behat\Gherkin\Loader\GherkinFileLoader;27use Behat\Gherkin\Loader\GherkinStringLoader;28use Behat\Gherkin\Loader\GherkinDirectoryLoader;29use Behat\Gherkin\Loader\CachedFileLoader;30use Behat\Gherkin\Loader\CachedDirectoryLoader;31use Behat\Gherkin\Loader\LoaderChain;32use Behat\Gherkin\Loader\LoaderResolver;33use Behat\Gherkin\Loader\NodeLoaderInterface;34use Behat\Gherkin\Loader\NodeGherkinFileLoader;35use Behat\Gherkin\Loader\NodeGherkinStringLoader;36use Behat\Gherkin\Loader\NodeGherkinDirectoryLoader;
AstNode
Using AI Code Generation
1require_once 'vendor/autoload.php';2use Behat\Gherkin\Node\AstNode;3use Behat\Gherkin\Node\FeatureNode;4use Behat\Gherkin\Node\ScenarioNode;5use Behat\Gherkin\Node\StepNode;6use Behat\Gherkin\Node\OutlineNode;7use Behat\Gherkin\Node\BackgroundNode;8use Behat\Gherkin\Node\ExampleTableNode;9use Behat\Gherkin\Node\ExampleNode;10use Behat\Gherkin\Node\PyStringNode;11use Behat\Gherkin\Node\TableNode;12use Behat\Gherkin\Node\RowNode;13use Behat\Gherkin\Node\TagNode;14use Behat\Gherkin\Node\ArgumentInterface;15use Behat\Gherkin\Node\Argument\PyStringArgument;16use Behat\Gherkin\Node\Argument\TableArgument;
AstNode
Using AI Code Generation
1include_once 'vendor/autoload.php';2use Behat\Gherkin\Node\StepNode;3use Behat\Gherkin\Node\PyStringNode;4use Behat\Gherkin\Node\TableNode;5use Behat\Gherkin\Node\StepNode;6use Behat\Gherkin\Node\PyStringNode;7use Behat\Gherkin\Node\TableNode;8use Behat\Gherkin\Node\StepNode;9use Behat\Gherkin\Node\PyStringNode;10use Behat\Gherkin\Node\TableNode;11use Behat\Gherkin\Node\StepNode;12use Behat\Gherkin\Node\PyStringNode;13use Behat\Gherkin\Node\TableNode;14use Behat\Gherkin\Node\StepNode;15use Behat\Gherkin\Node\PyStringNode;16use Behat\Gherkin\Node\TableNode;17use Behat\Gherkin\Node\StepNode;18use Behat\Gherkin\Node\PyStringNode;19use Behat\Gherkin\Node\TableNode;20use Behat\Gherkin\Node\StepNode;21use Behat\Gherkin\Node\PyStringNode;22use Behat\Gherkin\Node\TableNode;23use Behat\Gherkin\Node\StepNode;24use Behat\Gherkin\Node\PyStringNode;25use Behat\Gherkin\Node\TableNode;26use Behat\Gherkin\Node\StepNode;27use Behat\Gherkin\Node\PyStringNode;28use Behat\Gherkin\Node\TableNode;29use Behat\Gherkin\Node\StepNode;
AstNode
Using AI Code Generation
1require_once 'Gherkin/Parser.php';2require_once 'Gherkin/TokenScanner.php';3require_once 'Gherkin/TokenMatcher.php';4require_once 'Gherkin/Gherkin.php';5require_once 'Gherkin/Exception.php';6require_once 'Gherkin/Exception/ParserException.php';7require_once 'Gherkin/Exception/CompositeException.php';8require_once 'Gherkin/Exception/CompositeParserException.php';9require_once 'Gherkin/Exception/CompositeLexicalException.php';10require_once 'Gherkin/Exception/CompositeAstException.php';11require_once 'Gherkin/Exception/LexicalException.php';12require_once 'Gherkin/Exception/AstException.php';13require_once 'Gherkin/Exception/UndefinedStepException.php';14require_once 'Gherkin/Exception/RedundantStepException.php';15require_once 'Gherkin/Exception/RedundantArgument.php';16require_once 'Gherkin/Exception/UndefinedStepDefinitionException.php';17require_once 'Gherkin/Exception/UnexpectedException.php';18require_once 'Gherkin/Exception/InvalidFeatureFileException.php';19require_once 'Gherkin/Exception/NodeException.php';20require_once 'Gherkin/Exception/RedundantScenarioException.php';21require_once 'Gherkin/Exception/RedundantScenarioOutlineException.php';22require_once 'Gherkin/Exception/RedundantBackgroundException.php';23require_once 'Gherkin/Exception/RedundantExamplesException.php';24require_once 'Gherkin/Exception/RedundantExampleException.php';25require_once 'Gherkin/Exception/RedundantStepException.php';
AstNode
Using AI Code Generation
1$parser = new Gherkin\Parser();2$gherkin = $parser->parse(file_get_contents('features/feature.feature'));3$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();4$parser = new Behat\Gherkin\Parser();5$gherkin = $parser->parse(file_get_contents('features/feature.feature'));6$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();7$parser = new Behat\Gherkin\Parser();8$gherkin = $parser->parse(file_get_contents('features/feature.feature'));9$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();10$parser = new Behat\Gherkin\Parser();11$gherkin = $parser->parse(file_get_contents('features/feature.feature'));12$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();13$parser = new Behat\Gherkin\Parser();14$gherkin = $parser->parse(file_get_contents('features/feature.feature'));15$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();16$parser = new Behat\Gherkin\Parser();17$gherkin = $parser->parse(file_get_contents('features/feature.feature'));18$gherkin->getFeature()->getChildren()[0]->getSteps()[0]->getAstNode()->getKeyword();
AstNode
Using AI Code Generation
1require_once 'vendor/autoload.php';2use Behat\Gherkin\Node\ScenarioNode;3$gherkin = new \Behat\Gherkin\Gherkin();4$parser = $gherkin->getParser();5$gherkin = new \Behat\Gherkin\Gherkin();6$parser = $gherkin->getParser();7$feature = $parser->parse($file);8$feature = $parser->parse($file);9$scenarios = $feature->getScenarios();10$scenarios = $feature->getScenarios();11foreach ($scenarios as $scenario) {12 $scenario->getTitle();13 $scenario->getTags();14 $scenario->getSteps();15 $scenario->getExamples();16 $scenario->getKeyword();17 $scenario->getLine();18 $scenario->getKeywordType();19}20print_r($scenarios);21require_once 'vendor/autoload.php';22use Behat\Gherkin\Node\ScenarioNode;23$gherkin = new \Behat\Gherkin\Gherkin();24$parser = $gherkin->getParser();25$gherkin = new \Behat\Gherkin\Gherkin();26$parser = $gherkin->getParser();27$feature = $parser->parse($file);28$feature = $parser->parse($file);29$scenarios = $feature->getScenarios();30$scenarios = $feature->getScenarios();31foreach ($scenarios as $scenario) {32 $scenario->getTitle();33 $scenario->getTags();34 $scenario->getSteps();35 $scenario->getExamples();36 $scenario->getKeyword();37 $scenario->getLine();38 $scenario->getKeywordType();39}40print_r($scenarios);41require_once 'vendor/autoload.php';42use Behat\Gherkin\Node\ScenarioNode;
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Trigger Selenium automation tests on a cloud-based Grid of 3000+ real browsers and operating systems.
Test now for FreeGet 100 minutes of automation test minutes FREE!!