Reporter::appendEventOverview()   C
last analyzed

Complexity

Conditions 10
Paths 66

Size

Total Lines 65
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 65
ccs 0
cts 47
cp 0
rs 6.2553
cc 10
eloc 44
nc 66
nop 4
crap 110

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * The software is based on the Axon Framework project which is
17
 * licensed under the Apache 2.0 license. For more information on the Axon Framework
18
 * see <http://www.axonframework.org/>.
19
 * 
20
 * This software consists of voluntary contributions made by many individuals
21
 * and is licensed under the MIT license. For more information, see
22
 * <http://www.governor-framework.org/>.
23
 */
24
25
namespace Governor\Framework\Test;
26
27
use Hamcrest\Description;
28
use Governor\Framework\Domain\EventMessageInterface;
29
30
/**
31
 * The reporter generates extensive human readable reports of what the expected outcome of a test was, and what the
32
 * actual results were.
33
 *
34
 * @author    "David Kalosi" <[email protected]>
35
 * @license   <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>
36
 */
37
class Reporter
38
{
39
40
    /**
41
     * Report a failed assertion due to a difference in the stored versus the published events.
42
     *
43
     * @param array $storedEvents    The events that were stored
44
     * @param array $publishedEvents The events that were published
45
     * @param \Exception $probableCause   An exception that might be the cause of the failure
46
     * @throws GovernorAssertionError
47
     */
48 View Code Duplication
    public function reportDifferenceInStoredVsPublished(array $storedEvents,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
49
        array $publishedEvents, \Exception $probableCause = null)
50
    {
51
        $str = "The stored events do not match the published events.";
52
        $str .= $this->appendEventOverview($storedEvents, $publishedEvents,
53
            "Stored events", "Published events");
54
        $str .= $this->appendProbableCause($probableCause);
55
56
        throw new GovernorAssertionError($str);
57
    }
58
59
    /**
60
     * Report an error in the ordering or count of events. This is typically a difference that can be shown to the user
61
     * by enumerating the expected and actual events
62
     *
63
     * @param array $actualEvents   The events that were found
64
     * @param array $expectedEvents The events that were expected
65
     * @param \Exception $probableCause  An optional exception that might be the reason for wrong events
66
     * @throws GovernorAssertionError
67
     */
68 View Code Duplication
    public function reportWrongEvent(array $actualEvents, array $expectedEvents,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
        \Exception $probableCause = null)
70
    {
71
        $str = "The published events do not match the expected events";
72
        $str .= $this->appendEventOverview($expectedEvents, $actualEvents,
73
            "Expected", "Actual");
74
        $str .= $this->appendProbableCause($probableCause);
75
76
        throw new GovernorAssertionError($str);
77
    }
78
79
    /**
80
     * Report an error in the ordering or count of events. This is typically a difference that can be shown to the user
81
     * by enumerating the expected and actual events
82
     *
83
     * @param array $actualEvents  The events that were found
84
     * @param string $expectation   A Description of what was expected
85
     * @param \Exception $probableCause An optional exception that might be the reason for wrong events
86
     * @throws GovernorAssertionError
87
     */
88
    public function reportWrongEventDescription(array $actualEvents, $expectation,
89
        \Exception $probableCause = null)
90
    {
91
        $str = "The published events do not match the expected events.";
92
        $str .= "Expected :\n";
93
        $str .= $expectation . "\n";
94
        $str .= "But got";
95
96
        $str .= empty($actualEvents) ? " none" : ":";
97
98
        foreach ($actualEvents as $event) {
99
            $str .= "\n" . get_class($event);
100
        }
101
102
        $this->appendProbableCause($probableCause);
103
104
        throw new GovernorAssertionError($str);
105
    }
106
107
    /**
108
     * Reports an error due to an unexpected exception. This means a return value was expected, but an exception was
109
     * thrown by the command handler
110
     *
111
     * @param \Exception  $actualException The actual exception
112
     * @param Description $expectation     A text describing what was expected
113
     * @throws GovernorAssertionError
114
     */
115 View Code Duplication
    public function reportUnexpectedException(\Exception $actualException,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
        Description $expectation)
117
    {
118
        $str = "The command handler threw an unexpected exception";
119
        $str .= PHP_EOL . PHP_EOL;
120
        $str .= "Expected <" . $expectation . "> but got <exception of type [";
121
        $str .= get_class($actualException) . "]>. Stack trace follows:" . PHP_EOL;
122
        $str .= $this->writeStackTrace($actualException) . PHP_EOL;
123
124
        throw new GovernorAssertionError($str);
125
    }
126
127
    /**
128
     * Reports an error due to a wrong return value.
129
     *
130
     * @param mixed $actualReturnValue The actual return value
131
     * @param Description $expectation       A description of the expected value
132
     * @throws GovernorAssertionError
133
     */
134 View Code Duplication
    public function reportWrongResult($actualReturnValue,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
        Description $expectation)
136
    {
137
        $str = "The command handler returned an unexpected value";
138
        $str .= PHP_EOL . PHP_EOL;
139
        $str .= "Expected <" . $expectation . "> but got <";
140
        $str .= $this->describe($actualReturnValue) . ">";
141
        $str .= PHP_EOL;
142
143
        throw new GovernorAssertionError($str);
144
    }
145
146
    /**
147
     * Report an error due to an unexpected return value, while an exception was expected.
148
     *
149
     * @param mixed $actualReturnValue The actual return value
150
     * @param Description $description       A description describing the expected value
151
     * @throws GovernorAssertionError
152
     */
153 View Code Duplication
    public function reportUnexpectedReturnValue($actualReturnValue,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
        Description $description)
155
    {
156
        $str = "The command handler returned normally, but an exception was expected";
157
        $str .= PHP_EOL . PHP_EOL;
158
        $str .= "Expected <" . $description . "> but returned with <" . $actualReturnValue;
159
        $str .= $this->describe($actualReturnValue) . ">";
160
        $str .= PHP_EOL;
161
162
        throw new GovernorAssertionError($str);
163
    }
164
165
    /**
166
     * Report an error due to a an exception of an unexpected type.
167
     *
168
     * @param \Exception $actualException The actual exception
169
     * @param Description $description     A description describing the expected value
170
     * @throws GovernorAssertionError
171
     */
172 View Code Duplication
    public function reportWrongException(\Exception $actualException,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
        Description $description)
174
    {
175
        $str = "The command handler threw an exception, but not of the expected type";
176
        $str .= PHP_EOL . PHP_EOL;
177
        $str .= "Expected <" . $description . "> but got <exception of type [";
178
        $str .= get_class($actualException) . "]>. Stacktrace follows: ";
179
        $str .= PHP_EOL . $this->writeStackTrace($actualException) . PHP_EOL;
180
181
        throw new GovernorAssertionError($str);
182
    }
183
184
    /**
185
     * Report an error due to a difference in on of the fields of an event.
186
     *
187
     * @param string $eventType The (runtime) type of event the difference was found in
188
     * @param string $field     The field that contains the difference
189
     * @param mixed $actual    The actual value of the field
190
     * @param mixed $expected  The expected value of the field
191
     * @throws GovernorAssertionError
192
     */
193
    public function reportDifferentEventContents($eventType, $field, $actual,
194
        $expected)
195
    {
196
        $str = "One of the events contained different values than expected";
197
        $str .= PHP_EOL . PHP_EOL;
198
        $str .= "In an event of type [" . $eventType . "], the property [";
199
        $str .= $field . "] ";
200
201
        /* if (!strcmp($eventType.equals(field.getDeclaringClass())) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
202
          sb.append("(declared in [")
203
          .append(field.getDeclaringClass().getSimpleName())
204
          .append("]) ");
205
          } */
206
207
        $str .= "was not as expected." . PHP_EOL;
208
        $str .= "Expected <" .
209
            $this->nullSafeToString($expected) .
210
            "> but got <" .
211
            $this->nullSafeToString($actual) .
212
            ">" .
213
            PHP_EOL;
214
215
        throw new GovernorAssertionError($str);
216
    }
217
218
    private function appendProbableCause(\Exception $probableCause = null)
219
    {
220
        $str = "";
221
222
        if (null !== $probableCause) {
223
            $str .= PHP_EOL;
224
            $str .= "A probable cause for the wrong chain of events is an "
225
                . "exception that occurred while handling the command.";
226
            $str .= PHP_EOL;
227
            $str .= $probableCause->getTraceAsString();
228
        }
229
230
        return $str;
231
    }
232
233
    private function writeStackTrace(\Exception $actualException)
234
    {
235
        return $actualException->getTraceAsString();
236
    }
237
238
    private function nullSafeToString($value)
239
    {
240
        if (null === $value) {
241
            return "<null>";
242
        }
243
244
        if (is_array($value)) {
245
            return print_r($value, true);
246
        }
247
248
        return $value;
249
    }
250
251
    private function describe($value)
252
    {
253
        if (null === $value) {
254
            return "null";
255
        } else {
256
            return $value;
257
        }
258
    }
259
260
    private function appendEventOverview(array $leftColumnEvents,
261
        array $rightColumnEvents, $leftColumnName, $rightColumnName)
262
    {
263
        $actualTypes = array();
264
        $expectedTypes = array();
265
        $largestExpectedSize = strlen($leftColumnName);
266
267
        foreach ($rightColumnEvents as $event) {
268
            $actualTypes[] = $this->payloadContentType($event);
269
        }
270
271
        foreach ($leftColumnEvents as $event) {
272
            $simpleName = $this->payloadContentType($event);
273
            if (strlen($simpleName) > $largestExpectedSize) {
274
                $largestExpectedSize = strlen($simpleName);
275
            }
276
            $expectedTypes[] = $simpleName;
277
        }
278
279
        $str = PHP_EOL . PHP_EOL;
280
        $str .= $leftColumnName . $this->pad(strlen($leftColumnName),
281
                $largestExpectedSize, " ");
282
        $str .= "  |  " . $rightColumnName . PHP_EOL;
283
        $str .= $this->pad(0, $largestExpectedSize, "-") . "--|--";
284
        $str .= $this->pad(0, $largestExpectedSize, "-") . PHP_EOL;
285
286
        $actualIterator = new \ArrayIterator($actualTypes);
287
        $expectedIterator = new \ArrayIterator($expectedTypes);
288
289
        while ($actualIterator->valid() || $expectedIterator->valid()) {
290
            $expected = "";
291
            $difference = false;
292
293
            if (null !== $expectedIterator->current()) {
294
                $expected = $expectedIterator->current();
295
                $str .= $expected;
296
                $str .= $this->pad(strlen($expected), $largestExpectedSize, " ");
297
            } else {
298
                $str .= $this->pad(0, $largestExpectedSize, " ");
299
                $difference = true;
300
            }
301
302
            if (null !== $actualIterator->current()) {
303
                $actual = $actualIterator->current();
304
                $difference = $difference || !strcmp($expected, $actual) === 0;
305
306
                if ($difference) {
307
                    $str .= " <|> ";
308
                } else {
309
                    $str .= "  |  ";
310
                }
311
312
                $str .= $actual;
313
            } else {
314
                $str .= " <|> ";
315
            }
316
317
            $str .= PHP_EOL;
318
319
            $actualIterator->next();
320
            $expectedIterator->next();
321
        }
322
323
        return $str;
324
    }
325
326
    private function payloadContentType($event)
327
    {
328
        if ($event instanceof EventMessageInterface) {
329
            return $event->getPayloadType();
330
        } else {
331
            return get_class($event);
332
        }
333
    }
334
335
    private function pad($currentLength, $targetLength, $character)
336
    {
337
        $str = "";
338
        for ($t = $currentLength; $t < $targetLength; $t++) {
339
            $str .= $character;
340
        }
341
342
        return $str;
343
    }
344
345
}
346