Passed
Push — master ( b43cdb...04749e )
by Adrien
07:45
created

ImporterTest::testBomIsSkipped()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 18
rs 9.7666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Service;
6
7
use Application\Service\Importer;
8
use ApplicationTest\Traits\TestWithTransactionAndUser;
9
use PHPUnit\Framework\TestCase;
10
11
class ImporterTest extends TestCase
12
{
13
    use TestWithTransactionAndUser;
14
15
    public function testInvalidFilename(): void
16
    {
17
        $this->expectErrorMessage('File not found: non-existing-filename.csv');
18
        $this->import('non-existing-filename.csv');
19
    }
20
21
    public function testInvalidEmail(): void
22
    {
23
        $this->expectErrorMessage('A la ligne 1 : Ce n\'est pas une addresse email valide : "fo[o"');
24
        $this->import('tests/data/importer/invalid-email.csv');
25
    }
26
27
    public function testInvalidPattern(): void
28
    {
29
        $this->expectErrorMessage('A la ligne 1 : Ce n\'est pas une expression régulière valide : "fo[o"');
30
        $this->import('tests/data/importer/invalid-pattern.csv');
31
    }
32
33
    public function testInvalidPatternEnding(): void
34
    {
35
        $this->expectErrorMessage('A la ligne 1 : L\'expression régulière ne peut pas commencer ou terminer par `|`, car c\'est trop dangeureux: "foo|"');
36
        $this->import('tests/data/importer/invalid-pattern-ending.csv');
37
    }
38
39
    public function testInvalidEmpty(): void
40
    {
41
        $this->expectErrorMessage('A la ligne 1 : Il faut soit un email, soit un pattern, mais aucun existe');
42
        $this->import('tests/data/importer/invalid-empty.csv');
43
    }
44
45
    public function testInvalidDuplicatedEmail(): void
46
    {
47
        $this->expectErrorMessage("A la ligne 3 : L'email \"[email protected]\" est dupliqué et a déjà été vu à la ligne 1");
48
        $this->import('tests/data/importer/invalid-duplicated-email.csv');
49
    }
50
51
    public function testInvalidDuplicatedPattern(): void
52
    {
53
        $this->expectErrorMessage('A la ligne 2 : Le pattern ".*@university\.com" est dupliqué et a déjà été vu à la ligne 1');
54
        $this->import('tests/data/importer/invalid-duplicated-pattern.csv');
55
    }
56
57
    public function testInvalidReviewNumber(): void
58
    {
59
        $this->expectErrorMessage('A la ligne 1 : Un numéro de revue doit être entièrement numérique, mais est : "foo"');
60
        $this->import('tests/data/importer/invalid-review-number.csv');
61
    }
62
63
    public function testInvalidMissingReviewNumber(): void
64
    {
65
        $this->expectErrorMessage('A la ligne 1 : Revue introuvable pour le numéro de revue : 123');
66
        $this->import('tests/data/importer/invalid-missing-review-number.csv');
67
    }
68
69
    public function testInvalidColumnCount(): void
70
    {
71
        $this->expectErrorMessage('A la ligne 1 : Doit avoir exactement 14 colonnes, mais en a 5');
72
        $this->import('tests/data/importer/invalid-column-count.csv');
73
    }
74
75
    public function testInvalidSubscriptionType(): void
76
    {
77
        $this->expectErrorMessage('A la ligne 1 : Le subscriptionType est invalide : "foo"');
78
        $this->import('tests/data/importer/invalid-subscription-type.csv');
79
    }
80
81
    public function testInvalidMultipleErrors(): void
82
    {
83
        $this->expectErrorMessage('A la ligne 1 : Pays "suise" introuvable. Vouliez-vous dire "SUISSE" ?
84
A la ligne 2 : Revue introuvable pour le numéro de revue : 123');
85
        $this->import('tests/data/importer/invalid-multiple-errors.csv');
86
    }
87
88
    public function testFuzzyCountry(): void
89
    {
90
        $this->expectErrorMessage('A la ligne 1 : Pays "suise" introuvable. Vouliez-vous dire "SUISSE" ?');
91
92
        $this->import('tests/data/importer/invalid-country.csv');
93
    }
94
95
    public function testCountryWithAccent(): void
96
    {
97
        $this->import('tests/data/importer/valid-country.csv');
98
99
        $this->assertUser([
100
            'email' => '[email protected]',
101
            'subscription_type' => null,
102
            'subscription_last_review_id' => null,
103
            'membership' => 'none',
104
            'first_name' => '',
105
            'last_name' => '',
106
            'street' => '',
107
            'postcode' => '',
108
            'locality' => '',
109
            'country_id' => '51',
110
            'phone' => '',
111
            'web_temporary_access' => '0',
112
            'password' => '',
113
        ]);
114
115
        $this->assertUser([
116
            'email' => '[email protected]',
117
            'subscription_type' => null,
118
            'subscription_last_review_id' => null,
119
            'membership' => 'none',
120
            'first_name' => '',
121
            'last_name' => '',
122
            'street' => '',
123
            'postcode' => '',
124
            'locality' => '',
125
            'country_id' => '51',
126
            'phone' => '',
127
            'web_temporary_access' => '0',
128
            'password' => '',
129
        ]);
130
131
        $this->assertUser([
132
            'email' => '[email protected]',
133
            'subscription_type' => null,
134
            'subscription_last_review_id' => null,
135
            'membership' => 'none',
136
            'first_name' => '',
137
            'last_name' => '',
138
            'street' => '',
139
            'postcode' => '',
140
            'locality' => '',
141
            'country_id' => '29',
142
            'phone' => '',
143
            'web_temporary_access' => '0',
144
            'password' => '',
145
        ]);
146
    }
147
148
    public function testImport(): void
149
    {
150
        $this->assertUser([
151
            'email' => '[email protected]',
152
            'subscription_type' => null,
153
            'subscription_last_review_id' => null,
154
            'membership' => 'none',
155
            'first_name' => 'Hector',
156
            'last_name' => 'Barbossa',
157
            'street' => '',
158
            'postcode' => '',
159
            'locality' => '',
160
            'country_id' => '1',
161
            'phone' => '',
162
            'web_temporary_access' => '0',
163
            'password' => 'aa08769cdcb26674c6706093503ff0a3',
164
        ]);
165
166
        $otherMember = [
167
            'email' => '[email protected]',
168
            'subscription_type' => 'digital',
169
            'subscription_last_review_id' => '3001',
170
            'membership' => 'member',
171
            'first_name' => 'Elizabeth',
172
            'last_name' => 'Swann',
173
            'street' => '',
174
            'postcode' => '',
175
            'locality' => '',
176
            'country_id' => '1',
177
            'phone' => '',
178
            'web_temporary_access' => '0',
179
            'password' => '1895eaf4aad48bd97ec1a2fd15336591',
180
        ];
181
        $this->assertUser($otherMember);
182
183
        $this->assertShouldDeleteUserCount(0);
184
        $actual = $this->import('tests/data/importer/normal.csv');
185
186
        self::assertArrayHasKey('time', $actual);
187
        unset($actual['time']);
188
189
        $expected = [
190
            'updatedUsers' => 4,
191
            'updatedOrganizations' => 1,
192
            'deletedOrganizations' => 2,
193
            'totalUsers' => 6,
194
            'totalOrganizations' => 1,
195
            'totalLines' => 5,
196
        ];
197
        self::assertSame($expected, $actual);
198
199
        $this->assertShouldDeleteUserCount(2);
200
201
        $this->assertUser([
202
            'email' => '[email protected]',
203
            'subscription_type' => null,
204
            'subscription_last_review_id' => null,
205
            'membership' => 'none',
206
            'first_name' => '',
207
            'last_name' => '',
208
            'street' => '',
209
            'postcode' => '',
210
            'locality' => '',
211
            'country_id' => null,
212
            'phone' => '',
213
            'web_temporary_access' => '0',
214
            'password' => '',
215
        ]);
216
217
        $this->assertUser([
218
            'email' => '[email protected]',
219
            'subscription_type' => 'paper',
220
            'subscription_last_review_id' => null,
221
            'membership' => 'member',
222
            'first_name' => '',
223
            'last_name' => '',
224
            'street' => '',
225
            'postcode' => '',
226
            'locality' => '',
227
            'country_id' => null,
228
            'phone' => '',
229
            'web_temporary_access' => '0',
230
            'password' => '',
231
        ]);
232
233
        $this->assertUser([
234
            'email' => '[email protected]',
235
            'subscription_type' => 'both',
236
            'subscription_last_review_id' => null,
237
            'membership' => 'member',
238
            'first_name' => 'Roger "Bob"',
239
            'last_name' => 'Doe',
240
            'street' => 'Main street',
241
            'postcode' => '2000',
242
            'locality' => 'New York',
243
            'country_id' => '2',
244
            'phone' => '032 987 65 43',
245
            'web_temporary_access' => '0',
246
            'password' => 'aa08769cdcb26674c6706093503ff0a3',
247
        ]);
248
249
        $this->assertOrganization([
250
            'pattern' => '.*@university\.com',
251
            'subscription_last_review_id' => '3001',
252
        ]);
253
254
        // Unchanged
255
        $this->assertUser($otherMember);
256
    }
257
258
    public function testImportBothInOneLine(): void
259
    {
260
        $this->assertShouldDeleteUserCount(0);
261
        $actual = $this->import('tests/data/importer/both-in-one-line.csv');
262
263
        self::assertArrayHasKey('time', $actual);
264
        unset($actual['time']);
265
266
        $expected = [
267
            'updatedUsers' => 1,
268
            'updatedOrganizations' => 1,
269
            'deletedOrganizations' => 2,
270
            'totalUsers' => 5,
271
            'totalOrganizations' => 1,
272
            'totalLines' => 1,
273
        ];
274
        self::assertSame($expected, $actual);
275
276
        $this->assertShouldDeleteUserCount(4);
277
278
        $this->assertUser([
279
            'email' => '[email protected]',
280
            'subscription_type' => 'digital',
281
            'subscription_last_review_id' => '3001',
282
            'membership' => 'none',
283
            'first_name' => 'John',
284
            'last_name' => 'Doe',
285
            'street' => 'Main street',
286
            'postcode' => '8000',
287
            'locality' => 'Zurich',
288
            'country_id' => '1',
289
            'phone' => '837 28 73',
290
            'web_temporary_access' => '0',
291
            'password' => '',
292
        ]);
293
294
        $this->assertOrganization([
295
            'pattern' => '.*@university\.com',
296
            'subscription_last_review_id' => '3001',
297
        ]);
298
    }
299
300
    public function testBomIsSkipped(): void
301
    {
302
        $this->import('tests/data/importer/bom.csv');
303
304
        $this->assertUser([
305
            'email' => '[email protected]',
306
            'subscription_type' => null,
307
            'subscription_last_review_id' => null,
308
            'membership' => 'none',
309
            'first_name' => '',
310
            'last_name' => '',
311
            'street' => '',
312
            'postcode' => '',
313
            'locality' => '',
314
            'country_id' => null,
315
            'phone' => '',
316
            'web_temporary_access' => '0',
317
            'password' => '',
318
        ]);
319
    }
320
321
    public function testEscapedSequences(): void
322
    {
323
        $this->import('tests/data/importer/escaped.csv');
324
325
        $this->assertUser([
326
            'email' => '[email protected]',
327
            'subscription_type' => null,
328
            'subscription_last_review_id' => null,
329
            'membership' => 'none',
330
            'first_name' => 'test"test\'test\test',
331
            'last_name' => 'test"test\'test\test',
332
            'street' => '',
333
            'postcode' => '',
334
            'locality' => '',
335
            'country_id' => null,
336
            'phone' => '',
337
            'web_temporary_access' => '0',
338
            'password' => '',
339
        ]);
340
    }
341
342
    private function assertShouldDeleteUserCount(int $expected): void
343
    {
344
        $connection = $this->getEntityManager()->getConnection();
345
        $actual = (int) $connection->fetchColumn('SELECT COUNT(*) FROM user WHERE should_delete');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::fetchColumn() has been deprecated: Use fetchOne() instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

345
        $actual = (int) /** @scrutinizer ignore-deprecated */ $connection->fetchColumn('SELECT COUNT(*) FROM user WHERE should_delete');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
346
347
        self::assertSame($expected, $actual);
348
    }
349
350
    private function assertUser(array $expected): void
351
    {
352
        $connection = $this->getEntityManager()->getConnection();
353
        $actual = $connection->fetchAssoc('SELECT email, subscription_type, subscription_last_review_id, membership, first_name, last_name, street, postcode, locality, country_id, phone, web_temporary_access, password FROM user WHERE email = ?', [$expected['email']]);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::fetchAssoc() has been deprecated: Use fetchAssociative() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

353
        $actual = /** @scrutinizer ignore-deprecated */ $connection->fetchAssoc('SELECT email, subscription_type, subscription_last_review_id, membership, first_name, last_name, street, postcode, locality, country_id, phone, web_temporary_access, password FROM user WHERE email = ?', [$expected['email']]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
354
355
        self::assertSame($expected, $actual);
356
    }
357
358
    private function assertOrganization(array $expected): void
359
    {
360
        $connection = $this->getEntityManager()->getConnection();
361
        $actual = $connection->fetchAssoc('SELECT pattern, subscription_last_review_id FROM organization WHERE pattern = ?', [$expected['pattern']]);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::fetchAssoc() has been deprecated: Use fetchAssociative() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

361
        $actual = /** @scrutinizer ignore-deprecated */ $connection->fetchAssoc('SELECT pattern, subscription_last_review_id FROM organization WHERE pattern = ?', [$expected['pattern']]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
362
363
        self::assertSame($expected, $actual);
364
    }
365
366
    private function import(string $filename): array
367
    {
368
        $importer = new Importer();
369
        $actual = $importer->import($filename);
370
371
        return $actual;
372
    }
373
}
374