BaseTestCase::runTest()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 18
c 0
b 0
f 0
ccs 6
cts 6
cp 1
rs 9.4285
cc 3
eloc 9
nc 3
nop 0
crap 3
1
<?php
2
3
/*
4
 * This file is part of the JVal package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace JVal\Testing;
11
12
use JVal\Utils;
13
14
/**
15
 * Provides common methods for dealing with JSON data (loading, assertions,
16
 * etc.).
17
 */
18
abstract class BaseTestCase extends \PHPUnit_Framework_TestCase
19
{
20
    private $expectException = false;
21
22
    /**
23
     * Wraps the default #runTest() method to provide an exception hook.
24
     *
25
     * @return mixed|null
26
     *
27
     * @throws \Exception
28
     */
29 626
    protected function runTest()
30
    {
31
        try {
32 626
            $result = parent::runTest();
33 626
        } catch (\Exception $ex) {
34 61
            $this->exceptionHook($ex);
35
36 61
            return;
37
        }
38
39
        // @codeCoverageIgnoreStart
40
        if ($this->expectException) {
41
            $this->fail('An exception was expected but none has been thrown.');
42
        }
43
        // @codeCoverageIgnoreEnd
44
45 565
        return $result;
46
    }
47
48
    /**
49
     * Sets the flag indicating that an exception is expected.
50
     */
51 61
    protected function expectException()
52
    {
53 61
        $this->expectException = true;
54 61
    }
55
56
    /**
57
     * @codeCoverageIgnore (shouldn't happen in a green test suite)
58
     *
59
     * Hook called when an unexpected exception is thrown.
60
     *
61
     * Override this hook to make custom assertions on exceptions.
62
     *
63
     * @param \Exception $ex
64
     *
65
     * @throws \Exception
66
     */
67
    protected function exceptionHook(\Exception $ex)
68
    {
69
        throw $ex;
70
    }
71
72
    /**
73
     * Returns the JSON-decoded content of a file.
74
     *
75
     * @param string $file
76
     *
77
     * @return mixed
78
     */
79 93
    protected function loadJsonFromFile($file)
80
    {
81 93
        return Utils::loadJsonFromFile($file);
82
    }
83
84
    /**
85
     * Returns a JSON-decoded schema from tests/Data/schemas.
86
     *
87
     * @param string $name Name of the file without the extension
88
     *
89
     * @return mixed
90
     */
91 93
    protected function loadSchema($name)
92
    {
93 93
        $schemaDir = realpath(__DIR__.'/../../tests/Data/schemas');
94
95 93
        return $this->loadJsonFromFile("{$schemaDir}/{$name}.json");
96
    }
97
98
    /**
99
     * Asserts the validation results equal the expected one and make
100
     * a full report otherwise.
101
     *
102
     * @param string    $file
103
     * @param string    $title
104
     * @param mixed     $instance
105
     * @param \stdClass $schema
106
     * @param bool      $isInstanceValid
107
     * @param array     $expectedErrors
108
     * @param array     $actualErrors
109
     */
110 487
    protected function assertValidationResult(
111
        $file,
112
        $title,
113
        $instance,
114
        \stdClass $schema,
115
        $isInstanceValid,
116
        array $expectedErrors,
117
        array $actualErrors
118
    ) {
119
        $reportParameters = array(
120 487
            $file,
121 487
            $title,
122 487
            $this->dump($schema),
123 487
            $this->dump($instance),
124 487
            count($expectedErrors) > 0 ? $this->dump($expectedErrors) : 'no error',
125 487
            count($actualErrors) > 0 ? $this->dump($actualErrors) : 'no error',
126 487
        );
127
128 487
        if (!$isInstanceValid && count($expectedErrors) === 0) {
129 153
            $reportParameters[4] = 'at least one error';
130 153
            $this->assertHasError($actualErrors, $reportParameters);
131 154
        } else {
132 334
            $this->assertErrorsAreEqual($actualErrors, $expectedErrors, $reportParameters);
133
        }
134 487
    }
135
136
    /**
137
     * Returns a mock object, bypassing original constructor.
138
     *
139
     * @param string $class
140
     *
141
     * @return \PHPUnit_Framework_MockObject_MockObject
142
     */
143 83
    protected function mock($class)
144
    {
145 83
        return $this->getMockBuilder($class)
146 83
            ->disableOriginalConstructor()
147 83
            ->getMock();
148
    }
149
150
    /**
151
     * Returns URI to local file system.
152
     *
153
     * @param  string $path
154
     *
155
     * @return string
156
     */
157 307
    protected function getLocalUri($path)
158
    {
159
        // @codeCoverageIgnoreStart
160
        if (preg_match('/^[A-Z]:/i', $path)) {
161
            $path = '/' . strtr($path, '\\', '/');
162
        }
163
        // @codeCoverageIgnoreEnd
164
165 307
        return 'file://' . $path;
166
    }
167
168
    /**
169
     * @codeCoverageIgnore (cannot cover code whose behaviour depends on PHP version)
170
     *
171
     * @param mixed $variable
172
     *
173
     * @return string
174
     */
175
    private function dump($variable)
176
    {
177
        if (defined('JSON_PRETTY_PRINT')) {
178
            $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES;
179
180
            if (defined('JSON_PRESERVE_ZERO_FRACTION')) {
181
                $options |= JSON_PRESERVE_ZERO_FRACTION;
182
            }
183
184
            $output = @json_encode($variable, $options);
185
186
            if (json_last_error() === JSON_ERROR_NONE) {
187
                return $output;
188
            }
189
        }
190
191
        return print_r($variable, true);
192
    }
193
194 153
    private function assertHasError(array $errors, array $reportParameters)
195
    {
196
        // @codeCoverageIgnoreStart
197
        if (count($errors) === 0) {
198
            $this->fail(vsprintf($this->getFailureReportMask(), $reportParameters));
199
        }
200
        // @codeCoverageIgnoreEnd
201 153
    }
202
203 334
    private function assertErrorsAreEqual(array $actual, array $expected, array $reportParameters)
204
    {
205 334
        $report = vsprintf($this->getFailureReportMask(), $reportParameters);
206
207
        // @codeCoverageIgnoreStart
208
        if (count($actual) !== count($expected)) {
209
            $this->fail($report);
210
        }
211
        // @codeCoverageIgnoreEnd
212
213 334
        foreach ($expected as $error) {
214
            // @codeCoverageIgnoreStart
215
            if (!in_array($error, $actual)) {
216
                $this->fail($report);
217
            }
218
            // @codeCoverageIgnoreEnd
219 334
        }
220 334
    }
221
222 334
    private function getFailureReportMask()
223
    {
224
        return <<<MSG
225
**********************************************************************
226
227
File: %s
228
229
Test: %s
230
231
Schema: %s
232
233
Instance: %s
234
235
Expected: %s
236
237
Actual: %s
238
239
**********************************************************************
240 334
MSG;
241
    }
242
}
243