Passed
Push — master ( d44e36...c2d6d5 )
by Johnny
02:21
created

TestCase::input()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 35
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 23
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 35
rs 8.4444
1
<?php
2
/*
3
 * This file is part of RSTS
4
 *
5
 * (c) Johnny Mast <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace App;
12
13
use Axiom\Rivescript\Rivescript;
14
use AssertionError;
15
16
/**
17
 * TestCase trait
18
 *
19
 * The TestCase class will test a single file
20
 * with tests.
21
 *
22
 * PHP version 7.4 and higher.
23
 *
24
 * @category Core
25
 * @package  Tests
26
 * @author   Johnny Mast <[email protected]>
27
 * @license  https://opensource.org/licenses/MIT MIT
28
 * @link     https://github.com/axiom-labs/rivescript-php
29
 * @since    0.1.0
30
 */
31
class TestCase
32
{
33
34
    /**
35
     * @var string
36
     */
37
    protected string $file;
38
39
    /**
40
     * @var string
41
     */
42
    protected string $name;
43
44
    /**
45
     * Instance of the rivescript interpreter.
46
     *
47
     * @var \Axiom\Rivescript\Rivescript
48
     */
49
    protected Rivescript $rs;
50
51
    /**
52
     * The test client id.
53
     *
54
     * @var string
55
     */
56
    protected string $client_id = "test-user";
57
58
    /**
59
     * Stores the cases for this test.
60
     *
61
     * @var mixed
62
     */
63
    private array $cases;
64
65
    /**
66
     * TestCase constructor.
67
     *
68
     * @param string $file  The test file to load.
69
     * @param string $name  The name of the test.
70
     * @param array  $cases The testcases to run.
71
     */
72
    public function __construct(string $file, string $name, array $cases)
73
    {
74
        $this->rs = new Rivescript();
75
        $this->rs->setClientId($this->client_id);
76
77
        $this->rs->onSay = function ($msg) {
0 ignored issues
show
Unused Code introduced by
The parameter $msg is not used and could be removed. ( Ignorable by Annotation )

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

77
        $this->rs->onSay = function (/** @scrutinizer ignore-unused */ $msg) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
78
            //   echo "{$msg}\n";
79
        };
80
81
82
        $this->rs->onWarn = function ($msg) {
0 ignored issues
show
Unused Code introduced by
The parameter $msg is not used and could be removed. ( Ignorable by Annotation )

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

82
        $this->rs->onWarn = function (/** @scrutinizer ignore-unused */ $msg) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
83
            //    echo "{$msg}\n";
84
        };
85
        $this->file = $file;
86
        $this->name = ucfirst(str_replace("_", " ", $name));
87
88
        $this->cases = $cases['tests'];
89
    }
90
91
    /**
92
     * @param string $source
93
     *
94
     * @return void
95
     */
96
    private function source(string $source): void
97
    {
98
        $this->rs->stream($source);
99
    }
100
101
    /**
102
     * Input tests an input string against the interpreter.
103
     *
104
     * @param array $step The input step to test.
105
     *
106
     * @return void
107
     */
108
    private function input(array $step): void
109
    {
110
111
        $reply = $this->rs->reply($step['input'], $this->client_id);
112
113
        if (!isset($step['reply'])) {
114
            return;
115
        }
116
117
        $expected = $step['reply'];
118
119
        if (is_string($expected) === true) {
120
            $expected = rtrim($expected, "\n");
121
            if (strtolower($reply) !== strtolower($expected)) {
122
                throw new AssertionError(
123
                    "Got unexpected exception from reply() for input: {$step['input']}\n\n" .
124
                    " Expected: {$expected}\n" .
125
                    " Got: {$reply}"
126
                );
127
            }
128
        } elseif (is_array($expected) === true) {
129
            $correct = 0;
130
            foreach ($expected as $item) {
131
                $item = rtrim($item, "\n");
132
                if (strtolower($reply) === strtolower($item)) {
133
                    $correct++;
134
                }
135
            }
136
137
            if ($correct === 0) {
138
                $expected = implode(' or ', $expected);
139
                throw new AssertionError(
140
                    "Got unexpected exception from reply() for input: {$step['input']}\n\n" .
141
                    " Expected: {$expected}\n" .
142
                    " Got: {$reply}"
143
                );
144
            }
145
        }
146
    }
147
148
    /**
149
     * Ser a user variable.
150
     *
151
     * @param array $vars The variables to set.
152
     *
153
     * @return void
154
     */
155
    public function set(array $vars): void
156
    {
157
        if (count($vars) > 0) {
158
            foreach ($vars as $key => $value) {
159
                $this->rs->set_uservar($key, $value);
160
            }
161
        }
162
    }
163
164
    /**
165
     * Assert the value of a user variable.
166
     *
167
     * @param array $vars The variables to test.
168
     *
169
     * @return void
170
     */
171
    private function assert(array $vars): void
172
    {
173
        foreach ($vars as $key => $value) {
174
            $expected = $value;
175
            $actual = $this->rs->get_uservar($key);
176
177
            if ($actual != $value) {
178
                throw new AssertionError(
179
                    "Failed to assert that the value of user variable: {$key}\n\n" .
180
                    " Expected: {$expected}\n" .
181
                    " Got: {$actual}"
182
                );
183
            }
184
        }
185
    }
186
187
    /**
188
     * @return array
189
     */
190
    public function run(): array
191
    {
192
        $stats = [
193
            'success' => 0,
194
            'failed' => 0,
195
            'asserts' => 0,
196
        ];
197
198
        try {
199
200
            foreach ($this->cases as $step) {
201
                $key = key($step);
202
203
                switch ($key) {
204
                    case "assert":
205
                        $this->assert($step[$key]);
206
                        $stats['asserts']++;
207
                        break;
208
                    case "source":
209
                        $this->source($step[$key]);
210
                        break;
211
212
                    case "input":
213
                        $this->input($step);
214
                        $stats['success']++;
215
                        break;
216
217
                    case "set":
218
                        $this->set($step[$key]);
219
                        break;
220
221
                    default:
222
                        throw new AssertionError("Unsupported test step called \"{$key}\"");
223
                }
224
            }
225
226
            $sym = "✓";
227
            $name = ucfirst(str_replace("_", " ", $this->name));
228
            echo " {$sym} {$name}\n";
229
        } catch (AssertionError $e) {
230
            $stats['failed']++;
231
            $this->fail($e);
232
        }
233
234
        return $stats;
235
    }
236
237
    /**
238
     * Show a failure message.
239
     *
240
     * @param \AssertionError $e
241
     *
242
     * @return void
243
     */
244
    private function fail(AssertionError $e): void
245
    {
246
        $banner = "x {$this->name}";
247
        $banner .= "\n " . str_repeat("=", strlen($banner)) . "\n";
248
249
        echo " {$banner} {$e->getMessage()} \n\n";
250
    }
251
}
252