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'); |
|
|
|
|
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']]); |
|
|
|
|
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']]); |
|
|
|
|
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
|
|
|
|
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.