Passed
Push — master ( 7b52e4...d40832 )
by Jakub
01:50
created

TestCase   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Test Coverage

Coverage 97.3%

Importance

Changes 40
Bugs 0 Features 7
Metric Value
wmc 21
eloc 75
c 40
b 0
f 7
dl 0
loc 163
rs 10
ccs 72
cts 74
cp 0.973

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getSuiteName() 0 7 2
A getJobName() 0 7 2
A run() 0 13 3
A setUp() 0 2 1
A runJob() 0 18 3
A startUp() 0 2 1
A __construct() 0 7 1
A shutDown() 0 2 1
B getJobs() 0 34 6
A tearDown() 0 2 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MyTester;
6
7
use MyTester\Annotations\PhpAttributesEngine;
8
use MyTester\Annotations\Reader;
9
use ReflectionClass;
10
use ReflectionMethod;
11
12
/**
13
 * One test suite
14
 *
15
 * @author Jakub Konečný
16
 * @property-read Job[] $jobs @internal
17
 */
18
abstract class TestCase
19
{
20
    use \Nette\SmartObject;
21
    use TAssertions;
22
23
    public const RESULT_PASSED = ".";
24
    public const RESULT_SKIPPED = "s";
25
    public const RESULT_FAILED = "F";
26
27
    public const METHOD_PATTERN = '#^test[A-Z0-9_]#';
28
29
    /** @internal */
30
    public const ANNOTATION_TEST = "test";
31
    /** @internal */
32
    public const ANNOTATION_TEST_SUITE = "testSuite";
33
34
    protected SkipChecker $skipChecker;
35
    protected ShouldFailChecker $shouldFailChecker;
36
    protected DataProvider $dataProvider;
37
    protected Reader $annotationsReader;
38
39
    /** @var Job[] */
40
    private array $jobs = [];
41
42 1
    public function __construct()
43
    {
44 1
        $this->annotationsReader = new Reader();
45 1
        $this->annotationsReader->registerEngine(new PhpAttributesEngine());
46 1
        $this->skipChecker = new SkipChecker($this->annotationsReader);
47 1
        $this->shouldFailChecker = new ShouldFailChecker($this->annotationsReader);
48 1
        $this->dataProvider = new DataProvider($this->annotationsReader);
49 1
    }
50
51
    /**
52
     * Get list of jobs with parameters for current test suite
53
     *
54
     * @return Job[]
55
     */
56 1
    protected function getJobs(): array
57
    {
58 1
        if (count($this->jobs) === 0) {
59 1
            $r = new ReflectionClass(static::class);
60 1
            $methods = array_values((array) preg_grep(static::METHOD_PATTERN, array_map(function (ReflectionMethod $rm) {
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 121 characters
Loading history...
61 1
                return $rm->getName();
62 1
            }, $r->getMethods(ReflectionMethod::IS_PUBLIC))));
63 1
            foreach ($methods as $method) {
64
                /** @var callable $callback */
65 1
                $callback = [$this, $method];
66 1
                $job = [
67 1
                    "name" => $this->getJobName(static::class, $method),
68 1
                    "callback" => $callback,
69
                    "params" => [],
70 1
                    "skip" => $this->skipChecker->shouldSkip(static::class, $method),
71 1
                    "shouldFail" => $this->shouldFailChecker->shouldFail(static::class, $method),
72
                ];
73 1
                $data = $this->dataProvider->getData($this, $method);
74 1
                if (count($data) > 0) {
75 1
                    foreach ($data as $value) {
76 1
                        $job["params"][0] = $value;
77 1
                        $this->jobs[] = new Job(... $job);
78 1
                        $job["params"] = [];
79
                    }
80
                } else {
81 1
                    $rm = new ReflectionMethod($this, $method);
82 1
                    if ($rm->getNumberOfParameters() > 0) {
83 1
                        $job["skip"] = "Method requires at least 1 parameter but data provider does not provide any.";
84
                    }
85 1
                    $this->jobs[] = new Job(... $job);
86
                }
87
            }
88
        }
89 1
        return $this->jobs;
90
    }
91
92
    /**
93
     * Get name of current test suite
94
     */
95 1
    protected function getSuiteName(): string
96
    {
97 1
        $annotation = $this->annotationsReader->getAnnotation(static::ANNOTATION_TEST_SUITE, static::class);
98 1
        if ($annotation !== null) {
99 1
            return $annotation;
100
        }
101 1
        return static::class;
102
    }
103
104
    /**
105
     * Get name for a job
106
     */
107 1
    protected function getJobName(string|object $class, string $method): string
108
    {
109 1
        $annotation = $this->annotationsReader->getAnnotation(static::ANNOTATION_TEST, $class, $method);
110 1
        if ($annotation !== null) {
111 1
            return $annotation;
112
        }
113 1
        return $this->getSuiteName() . "::" . $method;
114
    }
115
116
    /**
117
     * Called at start of the suite
118
     */
119 1
    public function startUp(): void
120
    {
121 1
    }
122
123
    /**
124
     * Called at end of the suite
125
     */
126 1
    public function shutDown(): void
127
    {
128 1
    }
129
130
    /**
131
     * Called before each job
132
     */
133 1
    public function setUp(): void
134
    {
135 1
    }
136
137
    /**
138
     * Called after each job
139
     */
140 1
    public function tearDown(): void
141
    {
142 1
    }
143
144 1
    protected function runJob(Job $job): string
145
    {
146 1
        $this->resetCounter();
147 1
        if (!$job->skip) {
148 1
            $this->setUp();
149
        }
150 1
        $this->shouldFail = $job->shouldFail;
151 1
        $job->execute();
152 1
        if (!$job->skip) {
153 1
            $this->tearDown();
154
        }
155 1
        $this->shouldFail = false;
156 1
        $this->resetCounter();
157 1
        return match ($job->result) {
158 1
            Job::RESULT_PASSED => static::RESULT_PASSED,
159 1
            Job::RESULT_SKIPPED => static::RESULT_SKIPPED,
160
            Job::RESULT_FAILED => static::RESULT_FAILED,
161 1
            default => "",
162
        };
163
    }
164
165
    /**
166
     * Runs the test suite
167
     */
168 1
    public function run(): bool
169
    {
170 1
        $this->startUp();
171 1
        $jobs = $this->getJobs();
172 1
        $passed = true;
173 1
        foreach ($jobs as $job) {
174 1
            $this->runJob($job);
175 1
            if ($job->result === Job::RESULT_FAILED) {
176
                $passed = false;
177
            }
178
        }
179 1
        $this->shutDown();
180 1
        return $passed;
181
    }
182
}
183