Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.85% covered (success)
93.85%
61 / 65
62.50% covered (warning)
62.50%
5 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
CustomTester
93.85% covered (success)
93.85%
61 / 65
62.50% covered (warning)
62.50%
5 / 8
31.22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 registerTestFiles
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
5.39
 getSubDir
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 standardErrorHandling
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
6.01
 bypassStandardErrorHandling
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 realRunSubTest
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 realRun
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
5.03
 run
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace HtaccessCapabilityTester\Testers;
4
5use \HtaccessCapabilityTester\HtaccessCapabilityTester;
6use \HtaccessCapabilityTester\HttpRequesterInterface;
7use \HtaccessCapabilityTester\HttpResponse;
8use \HtaccessCapabilityTester\SimpleHttpRequester;
9use \HtaccessCapabilityTester\TestResult;
10use \HtaccessCapabilityTester\Testers\Helpers\ResponseInterpreter;
11
12class CustomTester extends AbstractTester
13{
14    /** @var array  A definition defining the test */
15    protected $test;
16
17    /** @var array  For convenience, all tests */
18    private $tests;
19
20    /**
21     * Constructor.
22     *
23     * @param  array   $test     The test (may contain subtests)
24     *
25     * @return void
26     */
27    public function __construct($test)
28    {
29        $this->test = $test;
30
31        if (isset($test['subtests'])) {
32            $this->tests = $test['subtests'];
33
34            // Add main subdir to subdir for all subtests
35            foreach ($this->tests as &$subtest) {
36                if (isset($subtest['subdir'])) {
37                    $subtest['subdir'] = $test['subdir'] . '/' . $subtest['subdir'];
38                }
39            }
40        } else {
41            $this->tests = [$test];
42        }
43
44        //echo '<pre>' . print_r($this->tests, true) . '</pre>';
45        //echo json_encode($this->tests) . '<br>';
46        parent::__construct();
47    }
48
49    /**
50     * Register the test files using the "registerTestFile" method
51     *
52     * @return  void
53     */
54    protected function registerTestFiles()
55    {
56
57        foreach ($this->tests as $test) {
58            if (isset($test['files'])) {
59                foreach ($test['files'] as $file) {
60                    // Two syntaxes are allowed:
61                    // - Simple array (ie: ['0.txt', '0']
62                    // - Named, ie:  ['filename' => '0.txt', 'content' => '0']
63                    // The second makes more readable YAML definitions
64                    if (isset($file['filename'])) {
65                        $filename = $file['filename'];
66                        $content = $file['content'];
67                    } else {
68                        list ($filename, $content) = $file;
69                    }
70                    $this->registerTestFile($test['subdir'] . '/' . $filename, $content);
71                }
72            }
73        }
74    }
75
76    public function getSubDir()
77    {
78        return $this->test['subdir'];
79    }
80
81    /**
82     *  Standard Error handling
83     *
84     * @param  HttpResponse  $response
85     *
86     * @return TestResult|null  If no errors, null is returned, otherwise a TestResult
87     */
88    private function standardErrorHandling($response)
89    {
90        switch ($response->statusCode) {
91            case '0':
92                return new TestResult(null, $response->body);
93            case '403':
94                return new TestResult(null, '403 Forbidden');
95            case '404':
96                return new TestResult(null, '404 Not Found');
97            case '500':
98                $hct = $this->getHtaccessCapabilityTester();
99
100                // Run innocent request / get it from cache. This sets
101                // $statusCodeOfLastRequest, which we need now
102                $hct->innocentRequestWorks();
103                if ($hct->statusCodeOfLastRequest == '500') {
104                    return new TestResult(null, 'Errored with 500. Everything errors with 500.');
105                } else {
106                    return new TestResult(
107                        false,
108                        'Errored with 500. ' .
109                        'Not all goes 500, so it must be a forbidden directive in the .htaccess'
110                    );
111                }
112        }
113        return null;
114    }
115
116    /**
117     * Checks if standard error handling should be bypassed on the test.
118     *
119     * This stuff is controlled in the test definition. More precisely, by the "bypass-standard-error-handling"
120     * property bellow the "request" property. If this property is set to ie ['404', '500'], the standard error
121     * handler will be bypassed for those codes (but still be in effect for ie '403'). If set to ['all'], all
122     * standard error handling will be bypassed.
123     *
124     * @param  array         $test      the subtest
125     * @param  HttpResponse  $response  the response
126     *
127     * @return bool          true if error handling should be bypassed
128     */
129    private function bypassStandardErrorHandling($test, $response)
130    {
131        if (!(isset($test['request']['bypass-standard-error-handling']))) {
132            return false;
133        }
134        $bypassErrors = $test['request']['bypass-standard-error-handling'];
135        if (in_array($response->statusCode, $bypassErrors) || in_array('all', $bypassErrors)) {
136            return true;
137        }
138        return false;
139    }
140
141    /**
142     *  Run single test
143     *
144     * @param  array  $test  the subtest to run
145     *
146     * @return TestResult  Returns a test result
147     */
148    private function realRunSubTest($test)
149    {
150        $requestUrl = $this->baseUrl . '/' . $test['subdir'] . '/';
151        if (isset($test['request']['url'])) {
152            $requestUrl .= $test['request']['url'];
153        } else {
154            $requestUrl .= $test['request'];
155        }
156        //echo $requestUrl . '<br>';
157        $response = $this->makeHttpRequest($requestUrl);
158
159        // Standard error handling
160        if (!($this->bypassStandardErrorHandling($test, $response))) {
161            $errorResult = $this->standardErrorHandling($response);
162            if (!is_null($errorResult)) {
163                return $errorResult;
164            }
165        }
166        return ResponseInterpreter::interpret($response, $test['interpretation']);
167    }
168
169    /**
170     *  Run
171     *
172     * @param  string  $baseDir  Directory on the server where the test files can be put
173     * @param  string  $baseUrl  The base URL of the test files
174     *
175     * @return TestResult  Returns a test result
176     * @throws \Exception  In case the test cannot be run due to serious issues
177     */
178    private function realRun($baseDir, $baseUrl)
179    {
180        $this->prepareForRun($baseDir, $baseUrl);
181
182        $result = null;
183        foreach ($this->tests as $i => $test) {
184            /*
185            Disabled, as I'm no longer sure if it is that useful
186
187            if (isset($test['requirements'])) {
188            $hct = $this->getHtaccessCapabilityTester();
189
190            foreach ($test['requirements'] as $requirement) {
191                $requirementResult = $hct->callMethod($requirement);
192                if (!$requirementResult) {
193                    // Skip test
194                    continue 2;
195                }
196            }
197            }*/
198            if (isset($test['request'])) {
199                $result = $this->realRunSubTest($test);
200                if ($result->info != 'no-match') {
201                    return $result;
202                }
203            }
204        }
205        if (is_null($result)) {
206            $result = new TestResult(null, 'Nothing to test!');
207        }
208        return $result;
209    }
210
211    /**
212     *  Run
213     *
214     * @param  string  $baseDir  Directory on the server where the test files can be put
215     * @param  string  $baseUrl  The base URL of the test files
216     *
217     * @return TestResult  Returns a test result
218     * @throws \Exception  In case the test cannot be run due to serious issues
219     */
220    public function run($baseDir, $baseUrl)
221    {
222        $testResult = $this->realRun($baseDir, $baseUrl);
223
224        // A test might not create a request if it has an unfulfilled requirement
225        if (isset($this->lastHttpResponse)) {
226            $testResult->statusCodeOfLastRequest = $this->lastHttpResponse->statusCode;
227        }
228        return $testResult;
229    }
230}