1 <?php declare(strict_types=1);
6 use PhpParser\Node\Arg;
7 use PhpParser\Node\Expr;
8 use PhpParser\Node\Expr\BinaryOp\Concat;
9 use PhpParser\Node\Identifier;
10 use PhpParser\Node\Name;
11 use PhpParser\Node\Scalar\LNumber;
12 use PhpParser\Node\Scalar\String_;
13 use PHPUnit\Framework\TestCase;
14 use Symfony\Component\Yaml\Tests\A;
16 class BuilderFactoryTest extends TestCase
19 * @dataProvider provideTestFactory
21 public function testFactory($methodName, $className) {
22 $factory = new BuilderFactory;
23 $this->assertInstanceOf($className, $factory->$methodName('test'));
26 public function provideTestFactory() {
28 ['namespace', Builder\Namespace_::class],
29 ['class', Builder\Class_::class],
30 ['interface', Builder\Interface_::class],
31 ['trait', Builder\Trait_::class],
32 ['method', Builder\Method::class],
33 ['function', Builder\Function_::class],
34 ['property', Builder\Property::class],
35 ['param', Builder\Param::class],
36 ['use', Builder\Use_::class],
37 ['useFunction', Builder\Use_::class],
38 ['useConst', Builder\Use_::class],
42 public function testVal() {
43 // This method is a wrapper around BuilderHelpers::normalizeValue(),
44 // which is already tested elsewhere
45 $factory = new BuilderFactory();
52 public function testConcat() {
53 $factory = new BuilderFactory();
54 $varA = new Expr\Variable('a');
55 $varB = new Expr\Variable('b');
56 $varC = new Expr\Variable('c');
59 new Concat($varA, $varB),
60 $factory->concat($varA, $varB)
63 new Concat(new Concat($varA, $varB), $varC),
64 $factory->concat($varA, $varB, $varC)
67 new Concat(new Concat(new String_("a"), $varB), new String_("c")),
68 $factory->concat("a", $varB, "c")
72 public function testConcatOneError() {
73 $this->expectException(\LogicException::class);
74 $this->expectExceptionMessage('Expected at least two expressions');
75 (new BuilderFactory())->concat("a");
78 public function testConcatInvalidExpr() {
79 $this->expectException(\LogicException::class);
80 $this->expectExceptionMessage('Expected string or Expr');
81 (new BuilderFactory())->concat("a", 42);
84 public function testArgs() {
85 $factory = new BuilderFactory();
86 $unpack = new Arg(new Expr\Variable('c'), false, true);
89 new Arg(new Expr\Variable('a')),
90 new Arg(new String_('b')),
93 $factory->args([new Expr\Variable('a'), 'b', $unpack])
97 public function testCalls() {
98 $factory = new BuilderFactory();
100 // Simple function call
103 new Name('var_dump'),
104 [new Arg(new String_('str'))]
106 $factory->funcCall('var_dump', ['str'])
108 // Dynamic function call
110 new Expr\FuncCall(new Expr\Variable('fn')),
111 $factory->funcCall(new Expr\Variable('fn'))
114 // Simple method call
117 new Expr\Variable('obj'),
118 new Identifier('method'),
119 [new Arg(new LNumber(42))]
121 $factory->methodCall(new Expr\Variable('obj'), 'method', [42])
123 // Explicitly pass Identifier node
126 new Expr\Variable('obj'),
127 new Identifier('method')
129 $factory->methodCall(new Expr\Variable('obj'), new Identifier('method'))
131 // Dynamic method call
134 new Expr\Variable('obj'),
135 new Expr\Variable('method')
137 $factory->methodCall(new Expr\Variable('obj'), new Expr\Variable('method'))
140 // Simple static method call
143 new Name\FullyQualified('Foo'),
144 new Identifier('bar'),
145 [new Arg(new Expr\Variable('baz'))]
147 $factory->staticCall('\Foo', 'bar', [new Expr\Variable('baz')])
149 // Dynamic static method call
152 new Expr\Variable('foo'),
153 new Expr\Variable('bar')
155 $factory->staticCall(new Expr\Variable('foo'), new Expr\Variable('bar'))
160 new Expr\New_(new Name\FullyQualified('stdClass')),
161 $factory->new('\stdClass')
166 new Expr\Variable('foo'),
167 [new Arg(new String_('bar'))]
169 $factory->new(new Expr\Variable('foo'), ['bar'])
173 public function testConstFetches() {
174 $factory = new BuilderFactory();
176 new Expr\ConstFetch(new Name('FOO')),
177 $factory->constFetch('FOO')
180 new Expr\ClassConstFetch(new Name('Foo'), new Identifier('BAR')),
181 $factory->classConstFetch('Foo', 'BAR')
184 new Expr\ClassConstFetch(new Expr\Variable('foo'), new Identifier('BAR')),
185 $factory->classConstFetch(new Expr\Variable('foo'), 'BAR')
189 public function testVar() {
190 $factory = new BuilderFactory();
192 new Expr\Variable("foo"),
196 new Expr\Variable(new Expr\Variable("foo")),
197 $factory->var($factory->var("foo"))
201 public function testPropertyFetch() {
202 $f = new BuilderFactory();
204 new Expr\PropertyFetch(new Expr\Variable('foo'), 'bar'),
205 $f->propertyFetch($f->var('foo'), 'bar')
208 new Expr\PropertyFetch(new Expr\Variable('foo'), 'bar'),
209 $f->propertyFetch($f->var('foo'), new Identifier('bar'))
212 new Expr\PropertyFetch(new Expr\Variable('foo'), new Expr\Variable('bar')),
213 $f->propertyFetch($f->var('foo'), $f->var('bar'))
217 public function testInvalidIdentifier() {
218 $this->expectException(\LogicException::class);
219 $this->expectExceptionMessage('Expected string or instance of Node\Identifier');
220 (new BuilderFactory())->classConstFetch('Foo', new Expr\Variable('foo'));
223 public function testInvalidIdentifierOrExpr() {
224 $this->expectException(\LogicException::class);
225 $this->expectExceptionMessage('Expected string or instance of Node\Identifier or Node\Expr');
226 (new BuilderFactory())->staticCall('Foo', new Name('bar'));
229 public function testInvalidNameOrExpr() {
230 $this->expectException(\LogicException::class);
231 $this->expectExceptionMessage('Name must be a string or an instance of Node\Name or Node\Expr');
232 (new BuilderFactory())->funcCall(new Node\Stmt\Return_());
235 public function testInvalidVar() {
236 $this->expectException(\LogicException::class);
237 $this->expectExceptionMessage('Variable name must be string or Expr');
238 (new BuilderFactory())->var(new Node\Stmt\Return_());
241 public function testIntegration() {
242 $factory = new BuilderFactory;
243 $node = $factory->namespace('Name\Space')
244 ->addStmt($factory->use('Foo\Bar\SomeOtherClass'))
245 ->addStmt($factory->use('Foo\Bar')->as('A'))
246 ->addStmt($factory->useFunction('strlen'))
247 ->addStmt($factory->useConst('PHP_VERSION'))
250 ->extend('SomeOtherClass')
251 ->implement('A\Few', '\Interfaces')
254 ->addStmt($factory->useTrait('FirstTrait'))
256 ->addStmt($factory->useTrait('SecondTrait', 'ThirdTrait')
257 ->and('AnotherTrait')
258 ->with($factory->traitUseAdaptation('foo')->as('bar'))
259 ->with($factory->traitUseAdaptation('AnotherTrait', 'baz')->as('test'))
260 ->with($factory->traitUseAdaptation('AnotherTrait', 'func')->insteadof('SecondTrait')))
262 ->addStmt($factory->method('firstMethod'))
264 ->addStmt($factory->method('someMethod')
267 ->addParam($factory->param('someParam')->setType('SomeClass'))
269 * This method does something.
271 * @param SomeClass And takes a parameter
274 ->addStmt($factory->method('anotherMethod')
276 ->addParam($factory->param('someParam')->setDefault('test'))
277 ->addStmt(new Expr\Print_(new Expr\Variable('someParam'))))
279 ->addStmt($factory->property('someProperty')->makeProtected())
280 ->addStmt($factory->property('anotherProperty')
282 ->setDefault([1, 2, 3])))
289 namespace Name\Space;
291 use Foo\Bar\SomeOtherClass;
294 use const PHP_VERSION;
295 abstract class SomeClass extends SomeOtherClass implements A\Few, \Interfaces
298 use SecondTrait, ThirdTrait, AnotherTrait {
300 AnotherTrait::baz as test;
301 AnotherTrait::func insteadof SecondTrait;
303 protected $someProperty;
304 private $anotherProperty = array(1, 2, 3);
305 function firstMethod()
309 * This method does something.
311 * @param SomeClass And takes a parameter
313 public abstract function someMethod(SomeClass $someParam);
314 protected function anotherMethod($someParam = 'test')
322 $prettyPrinter = new PrettyPrinter\Standard();
323 $generated = $prettyPrinter->prettyPrintFile($stmts);
326 str_replace("\r\n", "\n", $expected),
327 str_replace("\r\n", "\n", $generated)