Passed
Push — master ( 80ad96...45165d )
by Alexey
03:00
created

GPlayAppsTest   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 537
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 51
eloc 207
dl 0
loc 537
rs 7.92
c 0
b 0
f 0

37 Methods

Rating   Name   Duplication   Size   Complexity  
A testGetCategoriesInAvailableLocales() 0 9 2
A testSuggest() 0 4 1
A testDeveloperInfoIncorrectArgument() 0 6 1
A testGetAppWithEmptyAppId() 0 6 1
A testNotFoundApp() 0 6 1
A testGetAppInAvailableLocales() 0 18 1
A testExistsApp() 0 3 1
A testGetAppWithNull() 0 6 1
A testGetAppInAvailableLocalesWithEmptyAppId() 0 6 1
A testDevInfoInLocales() 0 6 1
A testUseProxy() 0 15 2
A testDeveloperInfoNotFound() 0 6 1
A testDevInfoInAvailableLocales() 0 6 1
A testReviews() 0 12 1
A testAppsByCategory() 0 6 1
A testDeveloperInfoIncorrectArgument2() 0 7 1
A testPermission() 0 5 1
A setUp() 0 6 1
A provideConstruct() 0 6 1
A testGetApp() 0 27 1
A testDeveloperApps() 0 10 1
A testGetCategoriesInLocales() 0 7 2
A testGetCategories() 0 6 1
A testConstruct() 0 5 1
A testExistsApps() 0 13 3
B isSocks5Proxy() 0 19 7
A testDeveloperInfoIncorrectArgument3() 0 7 1
A testGetApps2() 0 21 2
A testGetApps() 0 18 2
A testDeveloperInfo() 0 13 1
A testGetAppsWithEmptyListIds() 0 5 1
A providePackageExistsAsync() 0 7 2
A testSearch() 0 7 1
A testGetAppsWithAppNotFound() 0 13 1
A providePackageExists() 0 8 1
A testSimilarApps() 0 7 1
A testAllReviews() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like GPlayAppsTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GPlayAppsTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
4
namespace Nelexa\GPlay\Tests;
5
6
use Nelexa\GPlay\Enum\AgeEnum;
7
use Nelexa\GPlay\Enum\CategoryEnum;
8
use Nelexa\GPlay\Enum\CollectionEnum;
9
use Nelexa\GPlay\Enum\PriceEnum;
10
use Nelexa\GPlay\Enum\SortEnum;
11
use Nelexa\GPlay\Exception\GooglePlayException;
12
use Nelexa\GPlay\GPlayApps;
13
use Nelexa\GPlay\Model\App;
14
use Nelexa\GPlay\Model\AppDetail;
15
use Nelexa\GPlay\Model\Category;
16
use Nelexa\GPlay\Model\Developer;
17
use Nelexa\GPlay\Model\Permission;
18
use Nelexa\GPlay\Model\Review;
19
use Nelexa\GPlay\Request\RequestApp;
20
use Nelexa\GPlay\Util\LocaleHelper;
21
use PHPUnit\Framework\TestCase;
22
use Symfony\Component\Cache\Simple\ArrayCache;
23
24
class GPlayAppsTest extends TestCase
25
{
26
    /**
27
     * @var GPlayApps
28
     */
29
    private $gplay;
30
31
    protected function setUp()
32
    {
33
        $gplay = new GPlayApps();
34
        $cache = new ArrayCache();
35
        $gplay->setCache($cache);
36
        $this->gplay = $gplay;
37
    }
38
39
    /**
40
     * @dataProvider provideConstruct
41
     * @param string|null $defaultLocale
42
     * @param string|null $defaultCountry
43
     * @param string $actualLocale
44
     * @param string $actualCountry
45
     */
46
    public function testConstruct($defaultLocale, $defaultCountry, $actualLocale, $actualCountry): void
47
    {
48
        $gplay = new GPlayApps($defaultLocale, $defaultCountry);
49
        $this->assertSame($gplay->getDefaultLocale(), $actualLocale);
50
        $this->assertSame($gplay->getDefaultCountry(), $actualCountry);
51
    }
52
53
    /**
54
     * @return array
55
     */
56
    public function provideConstruct(): array
57
    {
58
        return [
59
            [null, null, GPlayApps::DEFAULT_LOCALE, GPlayApps::DEFAULT_COUNTRY],
60
            ['ru', null, 'ru_RU', GPlayApps::DEFAULT_COUNTRY],
61
            ['ru_RU', 'ru', 'ru_RU', 'ru'],
62
        ];
63
    }
64
65
    /**
66
     * @throws GooglePlayException
67
     */
68
    public function testGetApp(): void
69
    {
70
        $appId = 'com.google.android.googlequicksearchbox';
71
        $locale = 'es';
72
        $country = 'ca';
73
74
        $app = $this->gplay->getApp(new RequestApp(
75
            $appId,
76
            $locale,
77
            $country
78
        ));
79
80
        $this->assertEquals($app->getId(), $appId);
81
        $this->assertEquals($app->getLocale(), LocaleHelper::getNormalizeLocale($locale));
82
83
        $app2 = $this->gplay->getApp($appId);
84
        $this->assertEquals($app2->getId(), $appId);
85
        $this->assertEquals($app2->getLocale(), GPlayApps::DEFAULT_LOCALE);
86
        $this->assertNotEquals($app2, $app);
87
88
        $this->gplay
89
            ->setDefaultLocale($locale)
90
            ->setDefaultCountry($country);
91
        $app3 = $this->gplay->getApp($appId);
92
        $this->assertEquals($app3->getId(), $appId);
93
        $this->assertEquals($app3->getLocale(), LocaleHelper::getNormalizeLocale($locale));
94
        $this->assertEquals($app3, $app);
95
    }
96
97
    /**
98
     * @throws GooglePlayException
99
     */
100
    public function testNotFoundApp(): void
101
    {
102
        $this->expectException(GooglePlayException::class);
103
        $this->expectExceptionMessage('404 Not Found');
104
105
        $this->gplay->getApp(new RequestApp('com.example'));
106
    }
107
108
    /**
109
     * @throws GooglePlayException
110
     */
111
    public function testGetAppWithEmptyAppId(): void
112
    {
113
        $this->expectException(\InvalidArgumentException::class);
114
        $this->expectExceptionMessage('$id is empty');
115
116
        $this->gplay->getApp(new RequestApp(''));
117
    }
118
119
    /**
120
     * @throws GooglePlayException
121
     */
122
    public function testGetAppWithNull(): void
123
    {
124
        $this->expectException(\InvalidArgumentException::class);
125
        $this->expectExceptionMessage('$requestApp is null');
126
127
        $this->gplay->getApp(null);
128
    }
129
130
    /**
131
     * @throws GooglePlayException
132
     */
133
    public function testGetApps(): void
134
    {
135
        /**
136
         * @var RequestApp[] $requests
137
         */
138
        $requests = [
139
            'com.google.android.googlequicksearchbox' => new RequestApp('com.vkontakte.android'),
140
            'com.android.chrome' => new RequestApp('com.android.chrome'),
141
        ];
142
143
        $apps = $this->gplay->getApps($requests);
144
145
        $this->assertCount(count($requests), $apps);
146
        $this->assertContainsOnlyInstancesOf(AppDetail::class, $apps);
147
148
        foreach ($requests as $key => $request) {
149
            $this->assertArrayHasKey($key, $apps);
150
            $this->assertEquals($apps[$key]->getId(), $request->getId());
151
        }
152
    }
153
154
    /**
155
     * @throws GooglePlayException
156
     */
157
    public function testGetApps2(): void
158
    {
159
        /**
160
         * @var RequestApp[] $requests
161
         */
162
        $requests = [
163
            /* 0 => */
164
            'com.google.android.googlequicksearchbox',
165
            /* 1 => */
166
            'com.android.chrome',
167
        ];
168
169
        $apps = $this->gplay->getApps($requests);
170
171
        $this->assertCount(count($requests), $apps);
172
        $this->assertContainsOnlyInstancesOf(AppDetail::class, $apps);
173
174
        foreach ($requests as $key => $appId) {
175
            $this->assertIsInt($key);
176
            $this->assertArrayHasKey($key, $apps);
177
            $this->assertEquals($apps[$key]->getId(), $appId);
178
        }
179
    }
180
181
182
    /**
183
     * @throws GooglePlayException
184
     */
185
    public function testGetAppsWithEmptyListIds(): void
186
    {
187
        $appDetails = $this->gplay->getApps([]);
188
        $this->assertIsArray($appDetails);
189
        $this->assertEmpty($appDetails);
190
    }
191
192
    /**
193
     * @throws GooglePlayException
194
     */
195
    public function testGetAppsWithAppNotFound(): void
196
    {
197
        $this->expectException(GooglePlayException::class);
198
        $this->expectExceptionMessage('404 Not Found');
199
200
        $this->gplay->setConcurrency(1);
201
        $ids = [
202
            'com.google.android.webview',
203
            'com.google.android.apps.authenticator2',
204
            'com.example',
205
            'com.android.chrome',
206
        ];
207
        $this->gplay->getApps($ids);
208
    }
209
210
    /**
211
     * @throws GooglePlayException
212
     */
213
    public function testGetAppInAvailableLocales(): void
214
    {
215
        $this->gplay->setConcurrency(10);
216
217
        $id = 'ru.yandex.metro';
218
        $apps = $this->gplay->getAppInAvailableLocales($id);
219
        $this->assertContainsOnlyInstancesOf(AppDetail::class, $apps);
220
221
        $this->assertTrue(count(LocaleHelper::SUPPORTED_LOCALES) > count($apps));
222
223
        $this->assertArrayHasKey('ru_RU', $apps);
224
        $this->assertArrayHasKey('uk', $apps);
225
        $this->assertArrayHasKey('tr_TR', $apps);
226
        $this->assertArrayHasKey('en_US', $apps);
227
228
        $this->assertArrayNotHasKey('th', $apps);
229
        $this->assertArrayNotHasKey('fr_FR', $apps);
230
        $this->assertArrayNotHasKey('fil', $apps);
231
    }
232
233
    /**
234
     * @throws GooglePlayException
235
     */
236
    public function testGetAppInAvailableLocalesWithEmptyAppId(): void
237
    {
238
        $this->expectException(\InvalidArgumentException::class);
239
        $this->expectExceptionMessage('$id is empty');
240
241
        $this->gplay->getAppInAvailableLocales('');
242
    }
243
244
    /**
245
     * @dataProvider providePackageExists
246
     *
247
     * @param string $appId
248
     * @param bool $exists
249
     */
250
    public function testExistsApp(string $appId, bool $exists): void
251
    {
252
        $this->assertEquals($this->gplay->existsApp($appId), $exists);
253
    }
254
255
    /**
256
     * @return array
257
     */
258
    public function providePackageExists(): array
259
    {
260
        return [
261
            ['com.google.android.gm', true],
262
            ['com.google.android.googlequicksearchbox', true],
263
            ['dc.bloo_free', false],
264
            ['com.test', false],
265
            ['mobi.mgeek.AppToSD', false],
266
        ];
267
    }
268
269
    /**
270
     * @throws GooglePlayException
271
     */
272
    public function testExistsApps(): void
273
    {
274
        $resultsProvider = [];
275
        $requests = [];
276
        foreach ($this->providePackageExists() as $provider) {
277
            [$appId, $actualResult] = $provider;
278
            $resultsProvider[$appId] = $actualResult;
279
            $requests[$appId] = $appId;
280
        }
281
282
        $existsApps = $this->gplay->existsApps($requests);
283
        foreach ($existsApps as $appId => $result) {
284
            $this->assertEquals($result, $resultsProvider[$appId]);
285
        }
286
    }
287
288
    /**
289
     * @return array
290
     */
291
    public function providePackageExistsAsync(): array
292
    {
293
        $data = [];
294
        foreach ($this->providePackageExists() as $provider) {
295
            $data[][$provider[0]] = $provider[1];
296
        }
297
        return $data;
298
    }
299
300
    /**
301
     * @throws GooglePlayException
302
     */
303
    public function testReviews(): void
304
    {
305
        $reviews = $this->gplay->getAppReviews('com.google.android.googlequicksearchbox', 0, SortEnum::NEWEST());
306
        $reviewsNext = $this->gplay->getAppReviews('com.google.android.googlequicksearchbox', 1, SortEnum::NEWEST());
307
308
        $this->assertNotEmpty($reviews);
309
        $this->assertNotEmpty($reviewsNext);
310
311
        $this->assertContainsOnlyInstancesOf(Review::class, $reviews);
312
        $this->assertContainsOnlyInstancesOf(Review::class, $reviewsNext);
313
314
        $this->assertNotEquals($reviews, $reviewsNext);
315
    }
316
317
    public function testAllReviews(): void
318
    {
319
        $allReviews = $this->gplay->getAppAllReviews('com.google.android.googlequicksearchbox', SortEnum::HELPFULNESS(), 300);
320
        $this->assertCount(300, $allReviews);
321
        $this->assertContainsOnlyInstancesOf(Review::class, $allReviews);
322
    }
323
324
    /**
325
     * @throws GooglePlayException
326
     */
327
    public function testGetCategories(): void
328
    {
329
        $categories = $this->gplay->getCategories('ru');
330
331
        $this->assertNotEmpty($categories);
332
        $this->assertContainsOnlyInstancesOf(Category::class, $categories);
333
    }
334
335
    /**
336
     * @throws GooglePlayException
337
     */
338
    public function testGetCategoriesInLocales(): void
339
    {
340
        $categoriesInLocales = $this->gplay->getCategoriesInLocales(['ru', 'en', 'es', 'be', 'fil', 'zh-TW']);
341
342
        $this->assertNotEmpty($categoriesInLocales);
343
        foreach ($categoriesInLocales as $categories) {
344
            $this->assertContainsOnlyInstancesOf(Category::class, $categories);
345
        }
346
    }
347
348
    /**
349
     * @throws GooglePlayException
350
     */
351
    public function testGetCategoriesInAvailableLocales(): void
352
    {
353
        $this->gplay->setConcurrency(10);
354
355
        $categoriesInAvailableLocales = $this->gplay->getCategoriesInAvailableLocales();
356
357
        $this->assertNotEmpty($categoriesInAvailableLocales);
358
        foreach ($categoriesInAvailableLocales as $categories) {
359
            $this->assertContainsOnlyInstancesOf(Category::class, $categories);
360
        }
361
    }
362
363
    /**
364
     * @throws GooglePlayException
365
     */
366
    public function testDeveloperInfo(): void
367
    {
368
        $devInfo = $this->gplay->getDeveloperInfo(7935948260069539271, 'ru_RU');
369
370
        $this->assertNotEmpty($devInfo->getId());
371
        $this->assertNotEmpty($devInfo->getUrl());
372
        $this->assertNotEmpty($devInfo->getName());
373
        $this->assertNotEmpty($devInfo->getDescription());
374
        $this->assertNotEmpty($devInfo->getWebsite());
375
        $this->assertNotNull($devInfo->getIcon());
376
        $this->assertNotNull($devInfo->getHeaderImage());
377
        $this->assertNull($devInfo->getEmail());
378
        $this->assertNull($devInfo->getAddress());
379
    }
380
381
    /**
382
     * @throws GooglePlayException
383
     */
384
    public function testDeveloperInfoIncorrectArgument(): void
385
    {
386
        $this->expectException(GooglePlayException::class);
387
        $this->expectExceptionMessage('Developer "Facebook" does not have a personalized page on Google Play.');
388
389
        $this->gplay->getDeveloperInfo('Facebook');
390
    }
391
392
    /**
393
     * @throws GooglePlayException
394
     */
395
    public function testDeveloperInfoIncorrectArgument2(): void
396
    {
397
        $this->expectException(GooglePlayException::class);
398
        $this->expectExceptionMessage('Developer "Facebook" does not have a personalized page on Google Play.');
399
400
        $app = $this->gplay->getApp(new RequestApp('com.facebook.katana'));
401
        $this->gplay->getDeveloperInfo($app);
402
    }
403
404
    /**
405
     * @throws GooglePlayException
406
     */
407
    public function testDeveloperInfoIncorrectArgument3(): void
408
    {
409
        $this->expectException(GooglePlayException::class);
410
        $this->expectExceptionMessage('Developer "Facebook" does not have a personalized page on Google Play.');
411
412
        $app = $this->gplay->getApp(new RequestApp('com.facebook.katana'));
413
        $this->gplay->getDeveloperInfo($app->getDeveloper());
414
    }
415
416
    /**
417
     * @throws GooglePlayException
418
     */
419
    public function testDeveloperInfoNotFound(): void
420
    {
421
        $this->expectException(GooglePlayException::class);
422
        $this->expectExceptionMessage('404 Not Found');
423
424
        $this->gplay->getDeveloperInfo('353464543535');
425
    }
426
427
    /**
428
     * @throws GooglePlayException
429
     */
430
    public function testDevInfoInLocales(): void
431
    {
432
        $devInfo = $this->gplay->getDeveloperInfoInLocales(5627378377477294831, ['ru_RU', 'uk', 'en', 'fr', 'be']);
433
434
        $this->assertNotEmpty($devInfo);
435
        $this->assertContainsOnlyInstancesOf(Developer::class, $devInfo);
436
    }
437
438
    /**
439
     * @throws GooglePlayException
440
     */
441
    public function testDevInfoInAvailableLocales(): void
442
    {
443
        $developer = $this->gplay->getDeveloperInfoInAvailableLocales(5627378377477294831);
444
445
        $this->assertNotEmpty($developer);
446
        $this->assertContainsOnlyInstancesOf(Developer::class, $developer);
447
    }
448
449
    /**
450
     * @throws GooglePlayException
451
     */
452
    public function testSuggest(): void
453
    {
454
        $suggest = $this->gplay->getSuggest('Maps', 'ar');
455
        $this->assertNotEmpty($suggest);
456
    }
457
458
    /**
459
     * @throws GooglePlayException
460
     */
461
    public function testSearch(): void
462
    {
463
        $results = $this->gplay->search('Mario', 500, PriceEnum::ALL());
464
        $this->assertNotEmpty($results);
465
        $this->assertCount(GPlayApps::MAX_SEARCH_RESULTS, $results);
466
467
        $this->assertContainsOnlyInstancesOf(App::class, $results);
468
    }
469
470
    /**
471
     * @throws GooglePlayException
472
     */
473
    public function testSimilarApps(): void
474
    {
475
        $count = 70;
476
        $similarApps = $this->gplay->getSimilarApps('com.google.android.apps.docs.editors.docs', $count);
477
        $this->assertNotEmpty($similarApps);
478
        $this->assertCount($count, $similarApps);
479
        $this->assertContainsOnlyInstancesOf(App::class, $similarApps);
480
    }
481
482
    /**
483
     * @throws GooglePlayException
484
     */
485
    public function testAppsByCategory(): void
486
    {
487
        $apps = $this->gplay->getAppsByCategory(CategoryEnum::GAME(), CollectionEnum::TOP_FREE(), 140, AgeEnum::FIVE_UNDER(), 'ru', 'ru');
488
        $this->assertNotEmpty($apps);
489
        $this->assertCount(140, $apps);
490
        $this->assertContainsOnlyInstancesOf(App::class, $apps);
491
    }
492
493
    /**
494
     * @throws GooglePlayException
495
     */
496
    public function testPermission(): void
497
    {
498
        $permissions = $this->gplay->getPermissions('com.google.android.apps.docs.editors.docs');
499
        $this->assertNotEmpty($permissions);
500
        $this->assertContainsOnlyInstancesOf(Permission::class, $permissions);
501
    }
502
503
    /**
504
     * @throws GooglePlayException
505
     */
506
    public function testDeveloperApps(): void
507
    {
508
        $developerApps = $this->gplay->getDeveloperApps('5700313618786177705', 'ru_RU', 'by');
509
        $developerApps2 = $this->gplay->getDeveloperApps('Google LLC', 'ru_RU', 'by');
510
511
        $this->assertNotEmpty($developerApps);
512
        $this->assertNotEmpty($developerApps2);
513
514
        $this->assertContainsOnly(App::class, $developerApps);
515
        $this->assertContainsOnly(App::class, $developerApps2);
516
    }
517
518
    /**
519
     * @throws GooglePlayException
520
     */
521
    public function testUseProxy(): void
522
    {
523
        $torProxy = 'socks5://127.0.0.1:9050';
524
525
        if (!$this->isSocks5Proxy($torProxy)) {
526
            $this->markTestSkipped('Tor is not available');
527
            return;
528
        }
529
530
        $appId = 'com.google.android.googlequicksearchbox';
531
        $appDetail = $this->gplay
532
            ->setProxy($torProxy)
533
            ->setCache(null)
534
            ->getApp($appId);
535
        $this->assertSame($appDetail->getId(), $appId);
536
    }
537
538
    /**
539
     * @param string $proxy
540
     * @return bool
541
     */
542
    private function isSocks5Proxy(string $proxy): bool
543
    {
544
        $urlComponents = parse_url($proxy);
545
        if ($urlComponents === false || empty($urlComponents['host']) || empty($urlComponents['port'])) {
546
            return false;
547
        }
548
        if ($socket = @fsockopen($urlComponents['host'], $urlComponents['port'])) {
549
            try {
550
                fwrite($socket, pack('C3', 0x05, 0x01, 0x00));
551
                $buffer = fread($socket, 2);
552
                $response = unpack('Cversion/Cmethod', $buffer);
553
                if ($response['version'] === 0x05 && $response['method'] === 0x00) {
554
                    return true;
555
                }
556
            } finally {
557
                fclose($socket);
558
            }
559
        }
560
        return false;
561
    }
562
}
563