Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
TestGenerationHelper
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createSetUpMethod
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 createTestMethod
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 createAssertion
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 addTestImports
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 createTestClass
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace quintenmbusiness\PhpAstCodeGenerationHelper\GeneratorHelpers;
6
7use PhpParser\Builder\Class_;
8use PhpParser\Builder\Method;
9use PhpParser\Builder\Namespace_;
10use PhpParser\BuilderFactory;
11use PhpParser\Node\Expr\MethodCall;
12use PhpParser\Node\Expr\Variable;
13use PhpParser\Node\Stmt;
14use PhpParser\Node\Stmt\Expression;
15
16class TestGenerationHelper extends ClassGenerationHelper
17{
18    /**
19     * @param BuilderFactory $factory
20     */
21    public function __construct(BuilderFactory $factory)
22    {
23        parent::__construct($factory);
24    }
25
26    /**
27     * Creates a `setUp` method for initializing test dependencies.
28     *
29     * @param array<int, Expression> $body Statements to include in the `setUp` method body.
30     * @return Method
31     */
32    public function createSetUpMethod(array $body = []): Method
33    {
34        $method = $this->factory->method('setUp')
35            ->makeProtected()
36            ->setReturnType('void');
37
38        $method->addStmt(new Expression(new MethodCall(new Variable('this'), 'parent::setUp')));
39
40        foreach ($body as $stmt) {
41            $method->addStmt($stmt);
42        }
43
44        $this->createDocComment($method, returnType: 'void');
45
46        return $method;
47    }
48
49    /**
50     * Creates a generic test method with optional body statements.
51     *
52     * @param string $methodName The name of the test method.
53     * @param array<int, Stmt> $body Statements to include in the method body.
54     * @return Method
55     */
56    public function createTestMethod(string $methodName, array $body = []): Method
57    {
58        $method = $this->factory->method($methodName)
59            ->makePublic()
60            ->setReturnType('void');
61
62        foreach ($body as $stmt) {
63            $method->addStmt($stmt);
64        }
65
66        $this->createDocComment($method, returnType: 'void');
67
68        return $method;
69    }
70
71    /**
72     * Creates an assertion statement.
73     *
74     * @param string $assertMethod The PHPUnit assertion method (e.g., assertEquals, assertTrue).
75     * @param array<int, mixed> $arguments Arguments for the assertion.
76     * @return Expression
77     */
78    public function createAssertion(string $assertMethod, array $arguments = []): Expression
79    {
80        return new Expression(
81            new MethodCall(new Variable('this'), $assertMethod, $this->createArguments($arguments))
82        );
83    }
84
85    /**
86     * Adds common PHPUnit imports to a test class.
87     *
88     * @param Class_ $class
89     * @param array<string> $imports List of classes to import.
90     * @return Namespace_
91     */
92    public function addTestImports(Class_ $class, array $imports = []): Namespace_
93    {
94        // Create a namespace and add imports
95        return $this->setNamespace('Tests\\Generated', $class, array_merge([
96            'PHPUnit\\Framework\\TestCase',
97            'PhpParser\\BuilderFactory',
98        ], $imports));
99    }
100
101    /**
102     * Creates a fully functional test class.
103     *
104     * @param string $className The name of the test class.
105     * @param array<string, Method> $methods An array of test methods.
106     * @param array<string> $imports List of additional classes to import.
107     * @param array<int, Expression> $setupBody Optional body for the `setUp` method.
108     * @return Class_
109     */
110    public function createTestClass(
111        string $className,
112        array $methods,
113        array $imports = [],
114        array $setupBody = []
115    ): Class_ {
116        $class = $this->createClass($className);
117
118        // Extend TestCase
119        $this->extendClass($class, 'TestCase');
120
121        // Add the setUp method
122        if (!empty($setupBody)) {
123            $class->addStmt($this->createSetUpMethod($setupBody));
124        }
125
126        // Add all test methods
127        foreach ($methods as $methodName => $method) {
128            $class->addStmt($method);
129        }
130
131        // Add imports
132        $this->addTestImports($class, $imports);
133
134        return $class;
135    }
136}