Failed Conditions
Push — master ( d2d721...8007f2 )
by Yo
02:30
created

BehatStepLoggerSubscriber::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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