Failed Conditions
Branch feature/init (0e876c)
by Yo
04:41 queued 01:07
created

BehatStepLoggerSubscriber::resolveNodeLine()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 23
c 0
b 0
f 0
ccs 0
cts 16
cp 0
rs 8.5906
cc 5
eloc 11
nc 3
nop 1
crap 30
1
<?php
2
namespace Yoanm\BehatUtilsExtension\Subscriber;
3
4
use Behat\Behat\EventDispatcher\Event\BackgroundTested;
5
use Behat\Behat\EventDispatcher\Event\ExampleTested;
6
use Behat\Behat\EventDispatcher\Event\FeatureTested;
7
use Behat\Behat\EventDispatcher\Event\GherkinNodeTested;
8
use Behat\Behat\EventDispatcher\Event\OutlineTested;
9
use Behat\Behat\EventDispatcher\Event\ScenarioTested;
10
use Behat\Behat\EventDispatcher\Event\StepTested;
11
use Behat\Gherkin\Node\ExampleNode;
12
use Behat\Gherkin\Node\StepContainerInterface;
13
use Behat\Gherkin\Node\StepNode;
14
use Behat\Testwork\EventDispatcher\Event\AfterTested;
15
use Psr\Log\LoggerInterface;
16
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18
/**
19
 * Class BehatStepLoggerSubscriber
20
 */
21
class BehatStepLoggerSubscriber implements EventSubscriberInterface
22
{
23
    const HEADER_ACTION_IN = 'IN';
24
    const HEADER_ACTION_OUT = 'OUT';
25
26
    const HEADER_NODE_FEATURE = 'FEATURE';
27
    const HEADER_NODE_BACKGROUND = 'BACKGROUND';
28
    const HEADER_NODE_SCENARIO = 'SCENARIO';
29
    const HEADER_NODE_OUTLINE = 'OUTLINE';
30
    const HEADER_NODE_EXAMPLE = 'EXAMPLE';
31
    const HEADER_NODE_STEP = 'STEP';
32
33
    /** @var LoggerInterface */
34
    private $logger;
35
36
    /**
37
     * @param LoggerInterface $logger
38
     */
39
    public function __construct(LoggerInterface $logger)
40
    {
41
        $this->logger = $logger;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public static function getSubscribedEvents()
48
    {
49
        // Use high priority to log event at beginning
50
        $listener = ['logEvent', ListenerPriority::HIGH_PRIORITY];
51
        return [
52
            FeatureTested::BEFORE => $listener,
53
            BackgroundTested::BEFORE => $listener,
54
            ScenarioTested::BEFORE => $listener,
55
            OutlineTested::BEFORE => $listener,
56
            ExampleTested::BEFORE => $listener,
57
            StepTested::BEFORE => $listener,
58
59
            FeatureTested::AFTER => $listener,
60
            BackgroundTested::AFTER => $listener,
61
            ScenarioTested::AFTER => $listener,
62
            OutlineTested::AFTER => $listener,
63
            ExampleTested::AFTER => $listener,
64
            StepTested::AFTER => $listener,
65
        ];
66
    }
67
68
    /**
69
     * @param GherkinNodeTested $event
70
     */
71
    public function logEvent(GherkinNodeTested $event)
72
    {
73
        list($header, $context) = $this->processNodeEvent($event);
74
75
        $this->logger->debug($header, $context);
76
    }
77
78
    /**
79
     * @param GherkinNodeTested $event
80
     *
81
     * @return array
82
     */
83
    protected function processNodeEvent(GherkinNodeTested $event)
84
    {
85
        list($context, $nodeHeader) = $this->resolveContextAndNodeHeader($event);
86
87
        return [
88
            sprintf(
89
                '[%s][%s]',
90
                $nodeHeader,
91
                $this->resolveActionType($event)
92
            ),
93
            $context
94
        ];
95
    }
96
97
    /**
98
     * @param GherkinNodeTested $event
99
     *
100
     * @return string
101
     */
102
    protected function resolveActionType(GherkinNodeTested $event)
103
    {
104
        return $event instanceof AfterTested
105
            ? self::HEADER_ACTION_OUT
106
            : self::HEADER_ACTION_IN;
107
    }
108
109
    /**
110
     * @param GherkinNodeTested $event
111
     *
112
     * @return array
113
     */
114
    protected function resolveContextAndNodeHeader(GherkinNodeTested $event)
115
    {
116
        $context = [];
117
        switch (true) {
118
            case $event instanceof StepTested:
119
                $nodeHeader = self::HEADER_NODE_STEP;
120
                $context['text'] = $event->getStep()->getText();
121
                break;
122
            case $event instanceof BackgroundTested:
123
                $nodeHeader = self::HEADER_NODE_BACKGROUND;
124
                $context['title'] = $event->getBackground()->getTitle();
125
                break;
126
            case $event instanceof ScenarioTested:
127
                $scenario = $event->getScenario();
128
                $nodeHeader = self::HEADER_NODE_SCENARIO;
129
                if ($scenario instanceof ExampleNode) {
130
                    $nodeHeader = self::HEADER_NODE_EXAMPLE;
131
                    $context['tokens'] = $scenario->getTokens();
132
                }
133
                $context['title'] = $scenario->getTitle();
134
                break;
135
            case $event instanceof OutlineTested:
136
                $nodeHeader = self::HEADER_NODE_OUTLINE;
137
                $context['title'] = $event->getOutline()->getTitle();
138
                break;
139
            case $event instanceof FeatureTested:
140
                $nodeHeader = self::HEADER_NODE_FEATURE;
141
                $context['title'] = $event->getFeature()->getTitle();
142
                $context['file'] = $event->getFeature()->getFile();
143
                break;
144
            default:
145
                throw new \InvalidArgumentException(sprintf('"%s" not handled !', get_class($event)));
146
        }
147
148
        if (!$event instanceof FeatureTested) {
149
            $context['line'] = $this->resolveNodeLine($event);
150
        }
151
152
        return [
153
            $context,
154
            $nodeHeader
155
        ];
156
    }
157
158
    /**
159
     * @param GherkinNodeTested $event
160
     *
161
     * @return int
162
     */
163
    protected function resolveNodeLine(GherkinNodeTested $event)
164
    {
165
        $node = $event->getNode();
166
        $line = $node->getLine();
167
168
        if ($event instanceof AfterTested
169
            && !$event instanceof StepTested /* no need to process step event end line */
170
            && $node instanceof StepContainerInterface
171
        ) {
172
            // in case of end event, try to find the last line of the node
173
174
            /** @var StepContainerInterface $node*/
175
            $stepList = $node->getSteps();
176
            $lastStep = array_pop($stepList);
177
178
            // Check if StepContainer was not empty
179
            if ($lastStep instanceof StepNode) {
180
                $line = $lastStep->getLine();
181
            }
182
        }
183
184
        return $line;
185
    }
186
}
187