Passed
Pull Request — master (#100)
by
unknown
23:41 queued 21:10
created

ApiPhoneNumberTest   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 79
dl 0
loc 148
rs 10
c 3
b 0
f 0
wmc 9
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of the Numverify API Client for PHP.
7
 *
8
 * (c) 2024 Eric Sizemore <[email protected]>
9
 * (c) 2018-2021 Mark Rogoyski <[email protected]>
10
 *
11
 * This source file is subject to the MIT license. For the full copyright,
12
 * license information, and credits/acknowledgements, please view the LICENSE
13
 * and README files that were distributed with this source code.
14
 */
15
16
namespace Numverify\Tests;
17
18
use GuzzleHttp\ClientInterface;
19
use GuzzleHttp\Handler\MockHandler;
20
use GuzzleHttp\HandlerStack;
21
use GuzzleHttp\Psr7\Response;
22
use Iterator;
23
use Numverify\Api;
24
use Numverify\Exception\NumverifyApiFailureException;
25
use Numverify\Exception\NumverifyApiResponseException;
26
use Numverify\PhoneNumber\Factory;
27
use Numverify\PhoneNumber\InvalidPhoneNumber;
28
use Numverify\PhoneNumber\ValidPhoneNumber;
29
use PHPUnit\Framework\Attributes\CoversClass;
30
use PHPUnit\Framework\Attributes\DataProvider;
31
use PHPUnit\Framework\Attributes\TestDox;
32
use PHPUnit\Framework\MockObject\MockObject;
33
use PHPUnit\Framework\TestCase;
34
35
/**
36
 * @internal
37
 */
38
#[CoversClass(InvalidPhoneNumber::class)]
39
#[CoversClass(ValidPhoneNumber::class)]
40
#[CoversClass(Api::class)]
41
#[CoversClass(Factory::class)]
42
#[CoversClass(NumverifyApiFailureException::class)]
43
class ApiPhoneNumberTest extends TestCase
44
{
45
    private const ACCESS_KEY = 'SomeAccessKey';
46
47
    /**
48
     * Data to be used in MockResponse.
49
     *
50
     * @var string[]
51
     */
52
    private const RESPONSES = [
53
        'valid'        => '{"valid": true, "number": "14158586273", "local_format": "4158586273", "international_format": "+14158586273", "country_prefix": "+1", "country_code": "US", "country_name": "United States of America", "location": "Novato", "carrier": "AT&T Mobility LLC", "line_type": "mobile"}',
54
        'invalid'      => '{"valid":false, "number":"183155511", "local_format":"", "international_format":"", "country_prefix":"", "country_code":"", "country_name":"", "location":"", "carrier":"", "line_type":null}',
55
        'error'        => '{"success":false, "error":{"code":101, "type":"invalid_access_key", "info":"You have not supplied a valid API Access Key. [Technical Support: [email protected]]"}}',
56
        'missingField' => '{"valid": true, "number": "14158586273", "local_format": "4158586273", "international_format": "+14158586273", "country_prefix": "+1", "country_code": "US", "country_name": "United States of America", "location": "Novato", "line_type": "mobile"}',
57
    ];
58
59
    #[DataProvider('dataProviderForHttp')]
60
    #[TestDox('Given a response with missing \'carrier\' field, validatePhoneNumber returns appropriate exception with $useHttps.')]
61
    public function testValidatePhoneNumberApiResponseMissingData(bool $useHttps): void
62
    {
63
        $mockHandler = new MockHandler([
64
            new Response(200, body: self::RESPONSES['missingField']),
65
        ]);
66
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
67
68
        $this->expectException(NumverifyApiResponseException::class);
69
        $this->expectExceptionMessage('API response does not contain one or more expected fields: carrier');
70
        $phoneNumberToValidate = '14158586273';
71
        $apiStub->validatePhoneNumber($phoneNumberToValidate);
72
    }
73
74
    #[DataProvider('dataProviderForHttp')]
75
    #[TestDox('Given a non-200 response, validatePhoneNumber returns appropriate exception with $useHttps.')]
76
    public function testValidatePhoneNumberBadResponse(bool $useHttps): void
77
    {
78
        $mockHandler = new MockHandler([
79
            new Response(202, body: ''),
80
        ]);
81
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
82
83
        $phoneNumberToValidate = '18314262511';
84
        $this->expectException(NumverifyApiFailureException::class);
85
        $apiStub->validatePhoneNumber($phoneNumberToValidate);
86
    }
87
88
    #[DataProvider('dataProviderForHttp')]
89
    #[TestDox('Given an invalid api access key, validatePhoneNumber returns expected error information with $useHttps.')]
90
    public function testValidatePhoneNumberInvalidAccessKey(bool $useHttps): void
91
    {
92
        $mockHandler = new MockHandler([
93
            new Response(200, body: self::RESPONSES['error']),
94
        ]);
95
        $apiStub = $this->aClient('InvalidAccessKey', $useHttps, mockHandler: $mockHandler);
96
97
        $this->expectException(NumverifyApiFailureException::class);
98
        $this->expectExceptionMessage('Type:invalid_access_key Code:101 Info:You have not supplied a valid API Access Key. [Technical Support: [email protected]]');
99
        $phoneNumberToValidate = '18314262511';
100
        $apiStub->validatePhoneNumber($phoneNumberToValidate);
101
    }
102
103
    #[DataProvider('dataProviderForHttp')]
104
    #[TestDox('Given a response with an invalid result, validatePhoneNumber returns expected InvalidPhoneNumber instance with $useHttps.')]
105
    public function testValidatePhoneNumberInvalidPhoneNumber(bool $useHttps): void
106
    {
107
        $mockHandler = new MockHandler([
108
            new Response(200, body: self::RESPONSES['invalid']),
109
        ]);
110
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
111
112
        $phoneNumberToValidate = '18314262511';
113
        $phoneNumber           = $apiStub->validatePhoneNumber($phoneNumberToValidate);
114
        self::assertInstanceOf(InvalidPhoneNumber::class, $phoneNumber);
115
    }
116
117
    #[DataProvider('dataProviderForHttp')]
118
    #[TestDox('Given a 500 server error response, validatePhoneNumber returns appropriate exception with $useHttps.')]
119
    public function testValidatePhoneNumberServerError(bool $useHttps): void
120
    {
121
        $mockHandler = new MockHandler([
122
            new Response(500, body: ''),
123
        ]);
124
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
125
126
        $phoneNumberToValidate = '18314262511';
127
        $this->expectException(NumverifyApiFailureException::class);
128
        $apiStub->validatePhoneNumber($phoneNumberToValidate);
129
    }
130
131
    #[DataProvider('dataProviderForHttp')]
132
    #[TestDox('Given a response with a valid result, validatePhoneNumber returns expected ValidPhoneNumber instance with $useHttps.')]
133
    public function testValidatePhoneNumberValidPhoneNumber(bool $useHttps): void
134
    {
135
        $mockHandler = new MockHandler([
136
            new Response(200, body: self::RESPONSES['valid']),
137
        ]);
138
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
139
140
        $phoneNumberToValidate = '14158586273';
141
        $phoneNumber           = $apiStub->validatePhoneNumber($phoneNumberToValidate);
142
        self::assertInstanceOf(ValidPhoneNumber::class, $phoneNumber);
143
    }
144
145
    #[DataProvider('dataProviderForHttp')]
146
    #[TestDox('Given a response with a valid result, and using country code, validatePhoneNumber returns expected ValidPhoneNumber instance with $useHttps.')]
147
    public function testValidatePhoneNumberValidPhoneNumberUsingLocalFormatAndCountryCode(bool $useHttps): void
148
    {
149
        $mockHandler = new MockHandler([
150
            new Response(200, body: self::RESPONSES['valid']),
151
        ]);
152
        $apiStub = $this->aClient(self::ACCESS_KEY, $useHttps, mockHandler: $mockHandler);
153
154
        $phoneNumberToValidate = '4158586273';
155
        $countryCode           = 'US';
156
        $phoneNumber           = $apiStub->validatePhoneNumber($phoneNumberToValidate, $countryCode);
157
        self::assertInstanceOf(ValidPhoneNumber::class, $phoneNumber);
158
    }
159
160
    /**
161
     * @psalm-suppress PossiblyUnusedMethod
162
     */
163
    public static function dataProviderForHttp(): Iterator
164
    {
165
        yield [true];
166
        yield [false];
167
    }
168
169
    /**
170
     * Creates a mock client for testing.
171
     */
172
    private function aClient(
173
        string $accessKey = self::ACCESS_KEY,
174
        bool $useHttps = false,
175
        ?ClientInterface $client = null,
176
        ?MockHandler $mockHandler = null
177
    ): Api&MockObject {
178
        // Create a mock
179
        $handlerStack = HandlerStack::create($mockHandler);
180
181
        return $this
182
            ->getMockBuilder(Api::class)
183
            ->setConstructorArgs([$accessKey, $useHttps, $client, ['handler' => $handlerStack]])
184
            ->onlyMethods([])
185
            ->getMock();
186
    }
187
}
188