Passed
Push — main ( d1c8bb...2cd0ba )
by Daniel
12:40
created

BannedUserAgentHeaderFilterTest::testIsAFilter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace DanBettles\Defence\Tests\Filter;
6
7
use DanBettles\Defence\Envelope;
8
use DanBettles\Defence\Filter\AbstractFilter;
9
use DanBettles\Defence\Filter\BannedUserAgentHeaderFilter;
10
use DanBettles\Defence\Logger\NullLogger;
11
use DanBettles\Defence\Tests\AbstractTestCase;
12
use InvalidArgumentException;
13
use Symfony\Component\HttpFoundation\Request;
14
15
use function array_merge;
16
17
use const false;
18
use const null;
19
use const true;
20
21
/**
22
 * @phpstan-import-type Selector from BannedUserAgentHeaderFilter
23
 */
24
class BannedUserAgentHeaderFilterTest extends AbstractTestCase
25
{
26
    public function testIsAFilter(): void
27
    {
28
        $this->assertSubclassOf(AbstractFilter::class, BannedUserAgentHeaderFilter::class);
29
    }
30
31
    /** @return array<mixed[]> */
32
    public function providesRequestsFromBannedUserAgents(): array
33
    {
34
        $requestFactory = $this->getRequestFactory();
35
36
        $requestByPythonRequests = $requestFactory->createWithHeaders(['User-Agent' => 'python-requests/2.23.0']);
37
38
        return [
39
            [
40
                true,
41
                $requestByPythonRequests,
42
                [
43
                    '~python-requests/~',
44
                ],
45
            ],
46
            [
47
                true,
48
                $requestByPythonRequests,
49
                [
50
                    '~foo~',
51
                    '~python-requests/~',
52
                ],
53
            ],
54
            [
55
                true,
56
                $requestByPythonRequests,
57
                '~python-requests/~',
58
            ],
59
        ];
60
    }
61
62
    /** @return array<mixed[]> */
63
    public function providesRequestsFromPermittedUserAgents(): array
64
    {
65
        $requestFactory = $this->getRequestFactory();
66
67
        $requestByMozilla = $requestFactory->createWithHeaders(['User-Agent' => 'Mozilla/5.0 ...']);
68
        $requestByUnknown = $requestFactory->createGet();
69
70
        return [
71
            [
72
                false,
73
                $requestByMozilla,
74
                [
75
                    '~python-requests/~',
76
                ],
77
            ],
78
            [
79
                false,
80
                $requestByMozilla,
81
                '~python-requests/~',
82
            ],
83
            // "Not suspicious *in this context*, no".  The request is suspicious because it has no UA, but the UA is
84
            // not blacklisted.
85
            [
86
                false,
87
                $requestByUnknown,
88
                '~python-requests/~',
89
            ],
90
        ];
91
    }
92
93
    /** @return array<mixed[]> */
94
    public function providesRequests(): array
95
    {
96
        return array_merge(
97
            $this->providesRequestsFromBannedUserAgents(),
98
            $this->providesRequestsFromPermittedUserAgents()
99
        );
100
    }
101
102
    /**
103
     * @dataProvider providesRequests
104
     * @phpstan-param Selector $selector
105
     */
106
    public function testInvokeReturnsTrueIfTheUserAgentIsBanned(
107
        bool $expected,
108
        Request $request,
109
        $selector
110
    ): void {
111
        $envelope = new Envelope($request, new NullLogger());
112
        $filter = new BannedUserAgentHeaderFilter($selector);
113
114
        $this->assertSame($expected, $filter($envelope));
115
    }
116
117
    /**
118
     * @dataProvider providesRequestsFromBannedUserAgents
119
     * @phpstan-param Selector $selector
120
     */
121
    public function testInvokeWillAddALogEntryIfTheRequestIsFromABannedUserAgent(
122
        bool $expected,
123
        Request $request,
124
        $selector
125
    ): void {
126
        $completeEnvelope = new Envelope($request, new NullLogger());
127
128
        $filterMock = $this
129
            ->getMockBuilder(BannedUserAgentHeaderFilter::class)
130
            ->setConstructorArgs([
131
                $selector,
132
            ])
133
            ->onlyMethods(['envelopeAddLogEntry'])
134
            ->getMock()
135
        ;
136
137
        $filterMock
138
            ->expects($this->once())
139
            ->method('envelopeAddLogEntry')
140
            ->with($completeEnvelope, 'The request was made via a banned user agent.')
141
        ;
142
143
        $this->assertSame($expected, $filterMock($completeEnvelope));
144
    }
145
146
    /**
147
     * @dataProvider providesRequestsFromPermittedUserAgents
148
     * @phpstan-param Selector $selector
149
     */
150
    public function testInvokeWillNotAddALogEntryIfTheRequestIsFromAPermittedUserAgent(
151
        bool $expected,
152
        Request $request,
153
        $selector
154
    ): void {
155
        $completeEnvelope = new Envelope($request, new NullLogger());
156
157
        $filterMock = $this
158
            ->getMockBuilder(BannedUserAgentHeaderFilter::class)
159
            ->setConstructorArgs([
160
                $selector,
161
            ])
162
            ->onlyMethods(['envelopeAddLogEntry'])
163
            ->getMock()
164
        ;
165
166
        $filterMock
167
            ->expects($this->never())
168
            ->method('envelopeAddLogEntry')
169
        ;
170
171
        $this->assertSame($expected, $filterMock($completeEnvelope));
172
    }
173
174
    /** @return array<mixed[]> */
175
    public function providesInvalidSelectors(): array
176
    {
177
        return [
178
            [
179
                [],
180
            ],
181
            [
182
                '',
183
            ],
184
            [
185
                null,
186
            ],
187
            [
188
                123,
189
            ],
190
        ];
191
    }
192
193
    /**
194
     * @dataProvider providesInvalidSelectors
195
     * @param mixed $invalidSelector
196
     */
197
    public function testThrowsAnExceptionIfTheSelectorIsInvalid($invalidSelector): void
198
    {
199
        $this->expectException(InvalidArgumentException::class);
200
        $this->expectExceptionMessage('The selector is invalid');
201
202
        /** @phpstan-ignore-next-line */
203
        new BannedUserAgentHeaderFilter($invalidSelector);
204
    }
205
}
206