Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace Moodle\BehatExtension\EventDispatcher\Tester;
18
 
19
use Behat\Behat\EventDispatcher\Event\AfterStepSetup;
20
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
21
use Behat\Behat\EventDispatcher\Event\BeforeStepTeardown;
22
use Behat\Behat\EventDispatcher\Event\BeforeStepTested;
23
use Behat\Behat\Tester\Result\ExecutedStepResult;
24
use Behat\Behat\Tester\Result\SkippedStepResult;
25
use Behat\Behat\Tester\Result\StepResult;
26
use Behat\Behat\Tester\Result\UndefinedStepResult;
27
use Behat\Behat\Tester\StepTester;
28
use Behat\Gherkin\Node\FeatureNode;
29
use Behat\Gherkin\Node\StepNode;
30
use Behat\Testwork\Call\CallResult;
31
use Behat\Testwork\Environment\Environment;
32
use Behat\Testwork\EventDispatcher\TestworkEventDispatcher;
33
use Moodle\BehatExtension\Context\Step\ChainedStep;
34
use Moodle\BehatExtension\Exception\SkippedException;
35
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
36
 
37
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
38
 
39
/**
40
 * Override step tester to ensure chained steps gets executed.
41
 *
42
 * @package    core
43
 * @copyright  2016 Rajesh Taneja <rajesh@moodle.com>
44
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45
 */
46
class ChainedStepTester implements StepTester {
47
    /**
48
     * The text of the step to look for exceptions / debugging messages.
49
     */
50
    const EXCEPTIONS_STEP_TEXT = 'I look for exceptions';
51
 
52
    /**
53
     * @var StepTester Base step tester.
54
     */
55
    private $singlesteptester;
56
 
57
    /**
58
     * @var EventDispatcher keep step event dispatcher.
59
     */
60
    private $eventdispatcher;
61
 
62
    /**
63
     * Keep status of chained steps if used.
64
     * @var bool
65
     */
66
    protected static $chainedstepused = false;
67
 
68
    /**
69
     * Constructor.
70
     *
71
     * @param StepTester $steptester single step tester.
72
     */
73
    public function __construct(StepTester $steptester) {
74
        $this->singlesteptester = $steptester;
75
    }
76
 
77
    /**
78
     * Set event dispatcher to use for events.
79
     *
80
     * @param EventDispatcherInterface $eventdispatcher
81
     */
82
    public function setEventDispatcher(EventDispatcherInterface $eventdispatcher) {
83
        $this->eventdispatcher = $eventdispatcher;
84
    }
85
 
86
    /**
87
     * Sets up step for a test.
88
     *
89
     * @param Environment $env
90
     * @param FeatureNode $feature
91
     * @param StepNode    $step
92
     * @param bool     $skip
93
     *
94
     * @return Setup
95
     */
96
    public function setUp(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
97
        return $this->singlesteptester->setUp($env, $feature, $step, $skip);
98
    }
99
 
100
    /**
101
     * Tests step.
102
     *
103
     * @param Environment $env
104
     * @param FeatureNode $feature
105
     * @param StepNode    $step
106
     * @param bool     $skip
107
     * @return StepResult
108
     */
109
    public function test(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
110
        $result = $this->singlesteptester->test($env, $feature, $step, $skip);
111
 
112
        if (!($result instanceof ExecutedStepResult) || !$this->supportsResult($result->getCallResult())) {
113
            $result = $this->checkSkipResult($result);
114
 
115
            // If undefined step then don't continue chained steps.
116
            if ($result instanceof UndefinedStepResult) {
117
                return $result;
118
            }
119
 
120
            // If exception caught, then don't continue chained steps.
121
            if (($result instanceof ExecutedStepResult) && $result->hasException()) {
122
                return $result;
123
            }
124
 
125
            // If step is skipped, then return. no need to continue chain steps.
126
            if ($result instanceof SkippedStepResult) {
127
                return $result;
128
            }
129
 
130
            // Check for exceptions.
131
            // Extra step, looking for a moodle exception, a debugging() message or a PHP debug message.
132
            $checkingstep = new StepNode('Given', self::EXCEPTIONS_STEP_TEXT, [], $step->getLine());
133
            $afterexceptioncheckingevent = $this->singlesteptester->test($env, $feature, $checkingstep, $skip);
134
            $exceptioncheckresult = $this->checkSkipResult($afterexceptioncheckingevent);
135
 
136
            if (!$exceptioncheckresult->isPassed()) {
137
                return $exceptioncheckresult;
138
            }
139
 
140
            return $result;
141
        }
142
 
143
        return $this->runChainedSteps($env, $feature, $result, $skip);
144
    }
145
 
146
    /**
147
     * Tears down step after a test.
148
     *
149
     * @param Environment $env
150
     * @param FeatureNode $feature
151
     * @param StepNode    $step
152
     * @param bool     $skip
153
     * @param StepResult  $result
154
     * @return Teardown
155
     */
156
    public function tearDown(Environment $env, FeatureNode $feature, StepNode $step, $skip, StepResult $result) {
157
        return $this->singlesteptester->tearDown($env, $feature, $step, $skip, $result);
158
    }
159
 
160
    /**
161
     * Check if results supported.
162
     *
163
     * @param CallResult $result
164
     * @return bool
165
     */
166
    private function supportsResult(CallResult $result) {
167
        $return = $result->getReturn();
168
        if ($return instanceof ChainedStep) {
169
            return true;
170
        }
171
        if (!is_array($return) || empty($return)) {
172
            return false;
173
        }
174
        foreach ($return as $value) {
175
            if (!$value instanceof ChainedStep) {
176
                return false;
177
            }
178
        }
179
        return true;
180
    }
181
 
182
    /**
183
     * Run chained steps.
184
     *
185
     * @param Environment $env
186
     * @param FeatureNode $feature
187
     * @param ExecutedStepResult $result
188
     * @param bool $skip
189
     * @return ExecutedStepResult|StepResult
190
     */
191
    private function runChainedSteps(Environment $env, FeatureNode $feature, ExecutedStepResult $result, $skip) {
192
        // Set chained setp is used, so it can be used by formatter to o/p.
193
        self::$chainedstepused = true;
194
 
195
        $callresult = $result->getCallResult();
196
        $steps = $callresult->getReturn();
197
 
198
        if (!is_array($steps)) {
199
            // Test it, no need to dispatch events for single chain.
200
            $stepresult = $this->test($env, $feature, $steps, $skip);
201
            return $this->checkSkipResult($stepresult);
202
        }
203
 
204
        // Test all steps.
205
        foreach ($steps as $step) {
206
            // Setup new step.
207
            $event = new BeforeStepTested($env, $feature, $step);
208
            if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
209
                // Symfony 4.3 and up.
210
                $this->eventdispatcher->dispatch($event, $event::BEFORE);
211
            } else {
212
                // TODO: Remove when our min supported version is >= 4.3.
213
                $this->eventdispatcher->dispatch($event::BEFORE, $event);
214
            }
215
 
216
            $setup = $this->setUp($env, $feature, $step, $skip);
217
 
218
            $event = new AfterStepSetup($env, $feature, $step, $setup);
219
            if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
220
                // Symfony 4.3 and up.
221
                $this->eventdispatcher->dispatch($event, $event::AFTER_SETUP);
222
            } else {
223
                // TODO: Remove when our min supported version is >= 4.3.
224
                $this->eventdispatcher->dispatch($event::AFTER_SETUP, $event);
225
            }
226
 
227
            // Test it.
228
            $stepresult = $this->test($env, $feature, $step, $skip);
229
 
230
            // Tear down.
231
            $event = new BeforeStepTeardown($env, $feature, $step, $result);
232
            if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
233
                // Symfony 4.3 and up.
234
                $this->eventdispatcher->dispatch($event, $event::BEFORE_TEARDOWN);
235
            } else {
236
                // TODO: Remove when our min supported version is >= 4.3.
237
                $this->eventdispatcher->dispatch($event::BEFORE_TEARDOWN, $event);
238
            }
239
 
240
            $teardown = $this->tearDown($env, $feature, $step, $skip, $result);
241
 
242
            $event = new AfterStepTested($env, $feature, $step, $result, $teardown);
243
            if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
244
                // Symfony 4.3 and up.
245
                $this->eventdispatcher->dispatch($event, $event::AFTER);
246
            } else {
247
                // TODO: Remove when our min supported version is >= 4.3.
248
                $this->eventdispatcher->dispatch($event::AFTER, $event);
249
            }
250
 
251
            if (!$stepresult->isPassed()) {
252
                return $this->checkSkipResult($stepresult);
253
            }
254
        }
255
        return $this->checkSkipResult($stepresult);
256
    }
257
 
258
    /**
259
     * Handle skip exception.
260
     *
261
     * @param StepResult $result
262
     *
263
     * @return ExecutedStepResult|SkippedStepResult
264
     */
265
    private function checkSkipResult(StepResult $result) {
266
        if ((method_exists($result, 'getException')) && ($result->getException() instanceof SkippedException)) {
267
            return new SkippedStepResult($result->getSearchResult());
268
        } else {
269
            return $result;
270
        }
271
    }
272
 
273
    /**
274
     * Returns if cahined steps are used.
275
     * @return bool.
276
     */
277
    public static function is_chained_step_used() {
278
        return self::$chainedstepused;
279
    }
280
}