Issues (300)

src/Block/Specification.php (3 issues)

1
<?php
2
namespace Kahlan\Block;
3
4
use Kahlan\Block;
5
use Closure;
6
use Exception;
7
use Kahlan\Expectation;
8
use Kahlan\Log;
9
use Kahlan\Scope\Specification as Scope;
10
use Kahlan\Suite;
11
12
class Specification extends Block
13
{
14
    /**
15
     * List of expectations.
16
     * @var Expectation[]
17
     */
18
    protected $_expectations = [];
19
20
    /**
21
     * Constructor.
22
     *
23
     * @param array $config The Suite config array. Options are:
24
     *                      -`'closure'` _Closure_ : the closure of the test.
25
     *                      -`'message'` _string_  : the spec message.
26
     *                      -`'scope'`   _string_  : supported scope are `'normal'` & `'focus'`.
27
     */
28
    public function __construct($config = [])
29
    {
30
        $defaults = [
31
            'message' => 'passes'
32
        ];
33 59
        $config += $defaults;
34 59
        $config['message'] = 'it ' . $config['message'];
35 59
36
        parent::__construct($config);
37 59
38
        $this->_scope = new Scope(['block' => $this]);
39 59
        $this->_closure = $this->_bindScope($this->_closure);
40 59
    }
41
42
    /**
43
     * Reset the specification.
44
     *
45
     * @return Expectation
46
     */
47
    public function reset()
48
    {
49
        $this->_passed = null;
50 8
        $this->_expectations = [];
51 8
        $this->_log = new Log([
52
            'block' => $this,
53
            'backtrace' => $this->_backtrace
54
        ]);
55 8
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Kahlan\Block\Specification which is incompatible with the documented return type Kahlan\Expectation.
Loading history...
56 8
    }
57
58
    /**
59
     * The assert statement.
60
     *
61
     * @param array $config The config array. Options are:
62
     *                       -`'actual'`  _mixed_   : the actual value.
63
     *                       -`'timeout'` _integer_ : the timeout value.
64
     *                       Or:
65
     *                       -`'handler'` _Closure_ : a delegated handler to execute.
66
     *                       -`'type'`    _string_  : delegated handler supported exception type.
67
     *
68
     * @return Expectation
69
     */
70
    public function assert($config = [])
71
    {
72
        return $this->_expectations[] = new Expectation($config);
73 2
    }
74
75
    /**
76
     * The expect statement (assert shortcut).
77
     *
78
     * @param  mixed       $actual The expression to check
79
     *
80
     * @return Expectation
81
     */
82
    public function expect($actual, $timeout = 0)
83
    {
84
        return $this->_expectations[] = new Expectation(compact('actual', 'timeout'));
85 694
    }
86
87
    /**
88
     * The waitsFor statement.
89
     *
90
     * @param  mixed $actual The expression to check
91
     *
92
     * @return mixed
93
     */
94
    public function waitsFor($actual, $timeout = 0)
95
    {
96
        $timeout = $timeout ?: $this->timeout();
97 4
        $closure = $actual instanceof Closure ? $actual : function () use ($actual) {
98
            return $actual;
99 2
        };
100
        $spec = new static(['closure' => $closure]);
101 4
102
        return $this->expect($spec, $timeout);
103 4
    }
104
105
    /**
106
     * Spec execution helper.
107
     */
108
    protected function _execute()
109
    {
110
        $result = null;
111 686
        $spec = function () {
112
            $this->_expectations = [];
113 686
            $closure = $this->_closure;
114 686
            $result = $this->_suite->runBlock($this, $closure, 'specification');
115 705
            foreach ($this->_expectations as $expectation) {
116
                $this->_passed = $expectation->process() && $this->_passed;
117 692
            }
118
            return $result;
119 692
        };
120
121
        $suite = $this->suite();
122 686
        return $spec();
123 705
    }
124
125
    /**
126
     * Start spec execution helper.
127
     */
128
    protected function _blockStart()
129
    {
130
        $this->report('specStart', $this);
131 687
        if ($this->_parent) {
132
            $this->_parent->runCallbacks('beforeEach');
0 ignored issues
show
The method runCallbacks() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

132
            $this->_parent->/** @scrutinizer ignore-call */ 
133
                            runCallbacks('beforeEach');
Loading history...
133 687
        }
134
    }
135
136
    /**
137
     * End spec execution helper.
138
     */
139
    protected function _blockEnd($runAfterEach = true)
140
    {
141
        $type = $this->log()->type();
142 694
        foreach ($this->_expectations as $expectation) {
143
            if (!($logs = $expectation->logs()) && $type !== 'errored') {
144
                $this->log()->type('pending');
145 3
            }
146
            foreach ($logs as $log) {
147
                $this->log($log['type'], $log);
148 692
            }
149
        }
150
151
        if ($type === 'passed' && empty($this->_expectations)) {
152
            $this->log()->type('pending');
153 25
        }
154
        $type = $this->log()->type();
155 694
156
        if ($type === 'failed' || $type === 'errored') {
157
            $this->_passed = false;
158 12
            $this->suite()->failure();
159 12
        }
160
161
        if ($this->_parent && $runAfterEach) {
162
            try {
163
                $this->_parent->runCallbacks('afterEach');
164 692
            } catch (Exception $exception) {
165
                $this->_exception($exception, true);
166 2
            }
167
        }
168
169
        $this->summary()->log($this->log());
170 694
171
        $this->report('specEnd', $this->log());
172 694
173
        Suite::current()->scope()->clear();
0 ignored issues
show
The method scope() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
        Suite::current()->/** @scrutinizer ignore-call */ scope()->clear();
Loading history...
174 694
        $this->suite()->autoclear();
175 694
    }
176
177
    /**
178
     * Returns execution log.
179
     *
180
     * @return array
181
     */
182
    public function logs()
183
    {
184
        $logs = [];
185 8
        foreach ($this->_expectations as $expectation) {
186
            foreach ($expectation->logs() as $log) {
187
                $logs[] = $log;
188 8
            }
189
        }
190
        return $logs;
191 8
    }
192
}
193