Passed
Push — master ( 2aa04c...969584 )
by Adrien
08:04
created

ImporterTest   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 348
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 227
dl 0
loc 348
rs 10
c 3
b 0
f 0
wmc 20

20 Methods

Rating   Name   Duplication   Size   Complexity  
A testInvalidFilename() 0 4 1
A testInvalidPattern() 0 4 1
A testInvalidEmail() 0 4 1
A testInvalidSubscriptionType() 0 4 1
A testInvalidColumnCount() 0 4 1
A testInvalidDuplicatedEmail() 0 4 1
A testFuzzyCountry() 0 5 1
A testInvalidMissingReviewNumber() 0 4 1
A testInvalidReviewNumber() 0 4 1
A testInvalidDuplicatedPattern() 0 4 1
A testInvalidEmpty() 0 4 1
A testEscapedSequences() 0 18 1
A assertUser() 0 6 1
A testImportBothInOneLine() 0 39 1
A testCountryWithAccent() 0 50 1
A testBomIsSkipped() 0 18 1
B testImport() 0 108 1
A assertShouldDeleteUserCount() 0 6 1
A import() 0 6 1
A assertOrganization() 0 6 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->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 testInvalidEmpty(): void
34
    {
35
        $this->expectErrorMessage('A la ligne 1 : Il faut soit un email, soit un pattern, mais aucun existe');
36
        $this->import('tests/data/importer/invalid-empty.csv');
37
    }
38
39
    public function testInvalidDuplicatedEmail(): void
40
    {
41
        $this->expectErrorMessage("A la ligne 3 : L'email \"[email protected]\" est dupliqué et a déjà été vu à la ligne 1");
42
        $this->import('tests/data/importer/invalid-duplicated-email.csv');
43
    }
44
45
    public function testInvalidDuplicatedPattern(): void
46
    {
47
        $this->expectErrorMessage('A la ligne 2 : Le pattern ".*@university\.com" est dupliqué et a déjà été vu à la ligne 1');
48
        $this->import('tests/data/importer/invalid-duplicated-pattern.csv');
49
    }
50
51
    public function testInvalidReviewNumber(): void
52
    {
53
        $this->expectErrorMessage('A la ligne 1 : Un numéro de revue doit être entièrement numérique, mais est : foo');
54
        $this->import('tests/data/importer/invalid-review-number.csv');
55
    }
56
57
    public function testInvalidMissingReviewNumber(): void
58
    {
59
        $this->expectErrorMessage('A la ligne 1 : Revue introuvable pour le numéro de revue : 123');
60
        $this->import('tests/data/importer/invalid-missing-review-number.csv');
61
    }
62
63
    public function testInvalidColumnCount(): void
64
    {
65
        $this->expectErrorMessage('A la ligne 1 : Doit avoir exactement 14 colonnes, mais en a 5');
66
        $this->import('tests/data/importer/invalid-column-count.csv');
67
    }
68
69
    public function testInvalidSubscriptionType(): void
70
    {
71
        $this->expectErrorMessage('A la ligne 1 : Le subscriptionType est invalide : foo');
72
        $this->import('tests/data/importer/invalid-subscription-type.csv');
73
    }
74
75
    public function testFuzzyCountry(): void
76
    {
77
        $this->expectErrorMessage('A la ligne 1 : Pays "suise" introuvable. Vouliez-vous dire "SUISSE" ?');
78
79
        $this->import('tests/data/importer/invalid-country.csv');
80
    }
81
82
    public function testCountryWithAccent(): void
83
    {
84
        $this->import('tests/data/importer/valid-country.csv');
85
86
        $this->assertUser([
87
            'email' => '[email protected]',
88
            'subscription_type' => null,
89
            'subscription_last_review_id' => null,
90
            'membership' => 'none',
91
            'first_name' => '',
92
            'last_name' => '',
93
            'street' => '',
94
            'postcode' => '',
95
            'locality' => '',
96
            'country_id' => '51',
97
            'phone' => '',
98
            'web_temporary_access' => '0',
99
            'password' => '',
100
        ]);
101
102
        $this->assertUser([
103
            'email' => '[email protected]',
104
            'subscription_type' => null,
105
            'subscription_last_review_id' => null,
106
            'membership' => 'none',
107
            'first_name' => '',
108
            'last_name' => '',
109
            'street' => '',
110
            'postcode' => '',
111
            'locality' => '',
112
            'country_id' => '51',
113
            'phone' => '',
114
            'web_temporary_access' => '0',
115
            'password' => '',
116
        ]);
117
118
        $this->assertUser([
119
            'email' => '[email protected]',
120
            'subscription_type' => null,
121
            'subscription_last_review_id' => null,
122
            'membership' => 'none',
123
            'first_name' => '',
124
            'last_name' => '',
125
            'street' => '',
126
            'postcode' => '',
127
            'locality' => '',
128
            'country_id' => '29',
129
            'phone' => '',
130
            'web_temporary_access' => '0',
131
            'password' => '',
132
        ]);
133
    }
134
135
    public function testImport(): void
136
    {
137
        $this->assertUser([
138
            'email' => '[email protected]',
139
            'subscription_type' => null,
140
            'subscription_last_review_id' => null,
141
            'membership' => 'none',
142
            'first_name' => 'Hector',
143
            'last_name' => 'Barbossa',
144
            'street' => '',
145
            'postcode' => '',
146
            'locality' => '',
147
            'country_id' => '1',
148
            'phone' => '',
149
            'web_temporary_access' => '0',
150
            'password' => 'aa08769cdcb26674c6706093503ff0a3',
151
        ]);
152
153
        $otherMember = [
154
            'email' => '[email protected]',
155
            'subscription_type' => 'digital',
156
            'subscription_last_review_id' => '3001',
157
            'membership' => 'member',
158
            'first_name' => 'Elizabeth',
159
            'last_name' => 'Swann',
160
            'street' => '',
161
            'postcode' => '',
162
            'locality' => '',
163
            'country_id' => '1',
164
            'phone' => '',
165
            'web_temporary_access' => '0',
166
            'password' => '1895eaf4aad48bd97ec1a2fd15336591',
167
        ];
168
        $this->assertUser($otherMember);
169
170
        $this->assertShouldDeleteUserCount(0);
171
        $actual = $this->import('tests/data/importer/normal.csv');
172
173
        self::assertArrayHasKey('time', $actual);
174
        unset($actual['time']);
175
176
        $expected = [
177
            'updatedUsers' => 4,
178
            'updatedOrganizations' => 1,
179
            'deletedOrganizations' => 2,
180
            'totalUsers' => 6,
181
            'totalOrganizations' => 1,
182
            'totalLines' => 5,
183
        ];
184
        self::assertSame($expected, $actual);
185
186
        $this->assertShouldDeleteUserCount(2);
187
188
        $this->assertUser([
189
            'email' => '[email protected]',
190
            'subscription_type' => null,
191
            'subscription_last_review_id' => null,
192
            'membership' => 'none',
193
            'first_name' => '',
194
            'last_name' => '',
195
            'street' => '',
196
            'postcode' => '',
197
            'locality' => '',
198
            'country_id' => null,
199
            'phone' => '',
200
            'web_temporary_access' => '0',
201
            'password' => '',
202
        ]);
203
204
        $this->assertUser([
205
            'email' => 'thé[email protected]',
206
            'subscription_type' => 'paper',
207
            'subscription_last_review_id' => '3000',
208
            'membership' => 'member',
209
            'first_name' => '',
210
            'last_name' => '',
211
            'street' => '',
212
            'postcode' => '',
213
            'locality' => '',
214
            'country_id' => null,
215
            'phone' => '',
216
            'web_temporary_access' => '0',
217
            'password' => '',
218
        ]);
219
220
        $this->assertUser([
221
            'email' => '[email protected]',
222
            'subscription_type' => 'both',
223
            'subscription_last_review_id' => null,
224
            'membership' => 'member',
225
            'first_name' => 'Roger "Bob"',
226
            'last_name' => 'Doe',
227
            'street' => 'Main street',
228
            'postcode' => '2000',
229
            'locality' => 'New York',
230
            'country_id' => '2',
231
            'phone' => '032 987 65 43',
232
            'web_temporary_access' => '0',
233
            'password' => 'aa08769cdcb26674c6706093503ff0a3',
234
        ]);
235
236
        $this->assertOrganization([
237
            'pattern' => '.*@university\.com',
238
            'subscription_last_review_id' => '3001',
239
        ]);
240
241
        // Unchanged
242
        $this->assertUser($otherMember);
243
    }
244
245
    public function testImportBothInOneLine(): void
246
    {
247
        $this->assertShouldDeleteUserCount(0);
248
        $actual = $this->import('tests/data/importer/both-in-one-line.csv');
249
250
        self::assertArrayHasKey('time', $actual);
251
        unset($actual['time']);
252
253
        $expected = [
254
            'updatedUsers' => 1,
255
            'updatedOrganizations' => 1,
256
            'deletedOrganizations' => 2,
257
            'totalUsers' => 5,
258
            'totalOrganizations' => 1,
259
            'totalLines' => 1,
260
        ];
261
        self::assertSame($expected, $actual);
262
263
        $this->assertShouldDeleteUserCount(4);
264
265
        $this->assertUser([
266
            'email' => '[email protected]',
267
            'subscription_type' => 'digital',
268
            'subscription_last_review_id' => '3001',
269
            'membership' => 'none',
270
            'first_name' => 'John',
271
            'last_name' => 'Doe',
272
            'street' => 'Main street',
273
            'postcode' => '8000',
274
            'locality' => 'Zurich',
275
            'country_id' => '1',
276
            'phone' => '837 28 73',
277
            'web_temporary_access' => '0',
278
            'password' => '',
279
        ]);
280
281
        $this->assertOrganization([
282
            'pattern' => '.*@university\.com',
283
            'subscription_last_review_id' => '3001',
284
        ]);
285
    }
286
287
    public function testBomIsSkipped(): void
288
    {
289
        $this->import('tests/data/importer/bom.csv');
290
291
        $this->assertUser([
292
            'email' => '[email protected]',
293
            'subscription_type' => null,
294
            'subscription_last_review_id' => null,
295
            'membership' => 'none',
296
            'first_name' => '',
297
            'last_name' => '',
298
            'street' => '',
299
            'postcode' => '',
300
            'locality' => '',
301
            'country_id' => null,
302
            'phone' => '',
303
            'web_temporary_access' => '0',
304
            'password' => '',
305
        ]);
306
    }
307
308
    public function testEscapedSequences(): void
309
    {
310
        $this->import('tests/data/importer/escaped.csv');
311
312
        $this->assertUser([
313
            'email' => '[email protected]',
314
            'subscription_type' => null,
315
            'subscription_last_review_id' => null,
316
            'membership' => 'none',
317
            'first_name' => 'test"test\'test\test',
318
            'last_name' => 'test"test\'test\test',
319
            'street' => '',
320
            'postcode' => '',
321
            'locality' => '',
322
            'country_id' => null,
323
            'phone' => '',
324
            'web_temporary_access' => '0',
325
            'password' => '',
326
        ]);
327
    }
328
329
    private function assertShouldDeleteUserCount(int $expected): void
330
    {
331
        $connection = $this->getEntityManager()->getConnection();
332
        $actual = (int) $connection->fetchColumn('SELECT COUNT(*) FROM user WHERE should_delete');
333
334
        self::assertSame($expected, $actual);
335
    }
336
337
    private function assertUser(array $expected): void
338
    {
339
        $connection = $this->getEntityManager()->getConnection();
340
        $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']]);
341
342
        self::assertSame($expected, $actual);
343
    }
344
345
    private function assertOrganization(array $expected): void
346
    {
347
        $connection = $this->getEntityManager()->getConnection();
348
        $actual = $connection->fetchAssoc('SELECT pattern, subscription_last_review_id FROM organization WHERE pattern = ?', [$expected['pattern']]);
349
350
        self::assertSame($expected, $actual);
351
    }
352
353
    private function import(string $filename): array
354
    {
355
        $importer = new Importer();
356
        $actual = $importer->import($filename);
357
358
        return $actual;
359
    }
360
}
361