ImporterTest::assertUser()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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->expectExceptionMessage('File not found: non-existing-filename.csv');
18
        $this->import('non-existing-filename.csv');
19
    }
20
21
    public function testInvalidEmail(): void
22
    {
23
        $this->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage("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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->expectExceptionMessage('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->fetchOne('SELECT COUNT(*) FROM user WHERE should_delete');
346
347
        self::assertSame($expected, $actual);
348
    }
349
350
    private function assertUser(array $expected): void
351
    {
352
        $connection = $this->getEntityManager()->getConnection();
353
        $actual = $connection->fetchAssociative('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']]);
354
355
        self::assertSame($expected, $actual);
356
    }
357
358
    private function assertOrganization(array $expected): void
359
    {
360
        $connection = $this->getEntityManager()->getConnection();
361
        $actual = $connection->fetchAssociative('SELECT pattern, subscription_last_review_id FROM organization WHERE pattern = ?', [$expected['pattern']]);
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