Passed
Push — develop ( 415154...b14201 )
by Andreas
03:08
created

JSONCatalogTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 320
Duplicated Lines 18.13 %

Coupling/Cohesion

Components 2
Dependencies 11

Importance

Changes 6
Bugs 0 Features 4
Metric Value
wmc 10
c 6
b 0
f 4
lcom 2
cbo 11
dl 58
loc 320
rs 10

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
use League\Flysystem\Adapter\Local;
4
use League\Flysystem\Filesystem;
5
use League\Flysystem\Memory\MemoryAdapter;
6
use Wambo\Catalog\JSONCatalogProvider;
7
use Wambo\Catalog\Mapper\CatalogMapper;
8
use Wambo\Catalog\Mapper\ContentMapper;
9
use Wambo\Catalog\Mapper\ProductMapper;
10
use Wambo\Catalog\Model\Catalog;
11
use Wambo\Catalog\Model\Product;
12
13
/**
14
 * Class JSONCatalogTest tests the JSONCatalog class.
15
 *
16
 * @package Wambo\Catalog\Tests
17
 */
18
class JSONCatalogTest extends \PHPUnit_Framework_TestCase
19
{
20
    /**
21
     * If the JSONCatalog is empty no products should be returned.
22
     *
23
     * @test
24
     */
25
    public function getCatalog_JSONIsEmpty_NoProductsAreReturned()
26
    {
27
        // arrange
28
        $filesystem = new Filesystem(new MemoryAdapter());
29
        $catalogMapperMock = $this->getMockBuilder(CatalogMapper::class)->disableOriginalConstructor()->getMock();
30
        /** @var $catalogMapperMock CatalogMapper A mock for the CatalogMapper class */
31
        $jsonCatalog = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapperMock);
32
33
        // act
34
        $catalog = $jsonCatalog->getCatalog();
35
36
        // assert
37
        $this->assertEmpty($catalog, "getCatalog should not have returned a catalog if the catalog JSON is empty");
38
    }
39
40
    /**
41
     * If the filesystem read fails a CatalogException should be thrown
42
     *
43
     * @test
44
     * @expectedException \Wambo\Catalog\Error\CatalogException
45
     */
46
    public function getCatalog_FilesystemReadFails_CatalogExceptionIsThrown()
47
    {
48
        // arrange
49
        $filesystemMock = $this->getMockBuilder(Filesystem::class)->disableOriginalConstructor()->getMock();
50
        $filesystemMock->method("read")->willReturn(false);
51
52
        $catalogMapperMock = $this->getMockBuilder(CatalogMapper::class)->disableOriginalConstructor()->getMock();
53
        /** @var Filesystem $filesystemMock */
54
        /** @var CatalogMapper $catalogMapperMock A mock for the CatalogMapper class */
55
        $jsonCatalog = new JSONCatalogProvider($filesystemMock, "catalog.json", $catalogMapperMock);
56
57
        // act
58
        $jsonCatalog->getCatalog();
59
    }
60
61
    /**
62
     * If the CatalogMapper returns a catalog, the provider should return that catalog.
63
     *
64
     * @test
65
     * @expectedException \Wambo\Catalog\Error\CatalogException
66
     */
67
    public function getCatalog_JSONIsInvalid_CatalogExceptionIsThrown()
68
    {
69
        // arrange
70
        $filesystem = new Filesystem(new MemoryAdapter());
71
        $catalogMapperMock = $this->getMockBuilder(CatalogMapper::class)->disableOriginalConstructor()->getMock();
72
        $catalogMapperMock->method("getCatalog")->willReturn(new Catalog(array()));
73
        /** @var $catalogMapperMock CatalogMapper A mock for the CatalogMapper class */
74
75
        $catalogJSON = <<<JSON
76
[
77
    {},,],,
78
]
79
JSON;
80
        $filesystem->write("catalog.json", $catalogJSON);
81
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapperMock);
82
83
        // act
84
        $jsonCatalogProvider->getCatalog();
85
    }
86
87
    /**
88
     * If the CatalogMapper throws an exception, the provider should throw a CatalogException.
89
     *
90
     * @test
91
     * @expectedException Wambo\Catalog\Error\CatalogException
92
     */
93
    public function getCatalog_JSONIsValid_MapperThrowsException_CatalogExceptionIsThrown()
94
    {
95
        // arrange
96
        $filesystem = new Filesystem(new MemoryAdapter());
97
        $catalogMapperMock = $this->getMockBuilder(CatalogMapper::class)->disableOriginalConstructor()->getMock();
98
        $catalogMapperMock->method("getCatalog")->willThrowException(new Exception("Some mapping error"));
99
        /** @var $catalogMapperMock CatalogMapper A mock for the CatalogMapper class */
100
101
        $catalogJSON = <<<JSON
102
[]
103
JSON;
104
        $filesystem->write("catalog.json", $catalogJSON);
105
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapperMock);
106
107
        // act
108
        $jsonCatalogProvider->getCatalog();
109
    }
110
111
    /**
112
     * If the CatalogMapper returns a catalog, the provider should return that catalog.
113
     *
114
     * @test
115
     */
116
    public function getCatalog_JSONIsValid_MapperReturnsCatalog_CatalogIsReturned()
117
    {
118
        // arrange
119
        $filesystem = new Filesystem(new MemoryAdapter());
120
        $catalogMapperMock = $this->getMockBuilder(CatalogMapper::class)->disableOriginalConstructor()->getMock();
121
        $catalogMapperMock->method("getCatalog")->willReturn(new Catalog(array()));
122
        /** @var $catalogMapperMock CatalogMapper A mock for the CatalogMapper class */
123
124
        $catalogJSON = <<<JSON
125
[
126
    {}
127
]
128
JSON;
129
        $filesystem->write("catalog.json", $catalogJSON);
130
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapperMock);
131
132
        // act
133
        $catalog = $jsonCatalogProvider->getCatalog();
134
135
        // assert
136
        $this->assertNotNull($catalog, "getCatalog should return a catalog if the mapper returned one");
137
    }
138
139
    /**
140
     * Integration test with local filesystem
141
     *
142
     * @test
143
     */
144
    public function getCatalog_IntegrationTest_LocalSampleCatalogFile()
145
    {
146
        // arrange
147
        $sampleCatalogFilename = "sample-catalog.json";
148
        $testResourceFolderPath = realpath(__DIR__ . '/resources');
149
        $adapter = new Local($testResourceFolderPath);
150
        $filesystem = new Filesystem($adapter);
151
152
        $contentMapper = new ContentMapper();
153
        $productMapper = new ProductMapper($contentMapper);
154
        $catalogMapper = new CatalogMapper($productMapper);
155
156
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, $sampleCatalogFilename, $catalogMapper);
157
158
        // act
159
        $catalog = $jsonCatalogProvider->getCatalog();
160
161
        // assert
162
        foreach ($catalog->getProducts() as $product) {
163
            /** @var Product $product */
164
            $this->assertNotEmpty($product->getSku(), "The SKU should not be empty");
165
            $this->assertNotEmpty($product->getSlug(), "The slug should not be empty");
166
            $this->assertNotEmpty($product->getTitle(), "The title should not be empty");
167
            $this->assertNotEmpty($product->getSummaryText(), "The summary should not be empty");
168
            $this->assertNotEmpty($product->getProductDescription(), "The product description should not be empty");
169
        }
170
    }
171
172
    /**
173
     * Integration test
174
     *
175
     * @test
176
     */
177
    public function getCatalog_IntegrationTest_CatalogWithProductsIsReturned()
178
    {
179
        // arrange
180
        $filesystem = new Filesystem(new MemoryAdapter());
181
        $contentMapper = new ContentMapper();
182
        $productMapper = new ProductMapper($contentMapper);
183
        $catalogMapper = new CatalogMapper($productMapper);
184
185
        $catalogJSON = <<<JSON
186
[
187
    {
188
        "sku": "t-shirt-no-1",
189
        "slug": "t-shirt-no-1",
190
        "title": "T-Shirt No. 1",
191
        "summary": "Our T-Shirt No. 1",
192
        "description": "Our fancy T-Shirt No. 1 is ..."
193
    },
194
    {
195
        "sku": "t-shirt-no-2",
196
        "slug": "t-shirt-no-2",
197
        "title": "T-Shirt No. 2",
198
        "summary": "Our T-Shirt No. 2",
199
        "description": "Our fancy T-Shirt No. 2 is ..."
200
    },
201
    {
202
        "sku": "t-shirt-no-3",
203
        "slug": "t-shirt-no-3",
204
        "title": "T-Shirt No. 3",
205
        "summary": "Our T-Shirt No. 3",
206
        "description": "Our fancy T-Shirt No. 3 is ..."
207
    }
208
]
209
JSON;
210
        $filesystem->write("catalog.json", $catalogJSON);
211
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapper);
212
213
        // act
214
        $catalog = $jsonCatalogProvider->getCatalog();
215
216
        // assert
217
        $this->assertCount(3, $catalog, "getCatalog should return a catalog with 3 products");
218
    }
219
220
    /**
221
     * Integration test: invalid JSON
222
     *
223
     * @test
224
     * @dataProvider                   getInvalidCatalogJSON
225
     *
226
     * @param string $json
227
     *
228
     * @expectedException Wambo\Catalog\Error\CatalogException
229
     * @expectedExceptionMessageRegExp /Unable to read catalog/
230
     */
231
    public function getCatalog_IntegrationTest_ValidCatalog_CatalogExceptionIsThrown($json)
232
    {
233
        // arrange
234
        $filesystem = new Filesystem(new MemoryAdapter());
235
        $contentMapper = new ContentMapper();
236
        $productMapper = new ProductMapper($contentMapper);
237
        $catalogMapper = new CatalogMapper($productMapper);
238
239
        $filesystem->write("catalog.json", $json);
240
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapper);
241
242
        // act
243
        $jsonCatalogProvider->getCatalog();
244
    }
245
246
    /**
247
     * Integration test: valid catalog
248
     *
249
     * @test
250
     */
251
    public function getCatalog_IntegrationTest_ValidCatalog_AllProductAttributesAreSet()
252
    {
253
        // arrange
254
        $filesystem = new Filesystem(new MemoryAdapter());
255
        $contentMapper = new ContentMapper();
256
        $productMapper = new ProductMapper($contentMapper);
257
        $catalogMapper = new CatalogMapper($productMapper);
258
259
        $catalogJSON = <<<JSON
260
[
261
    {
262
        "sku": "t-shirt-no-1",
263
        "slug": "t-shirt-no-1-slug",
264
        "title": "T-Shirt No. 1",
265
        "summary": "Our T-Shirt No. 1",
266
        "description": "Our fancy T-Shirt No. 1 is ..."
267
    }
268
]
269
JSON;
270
        $filesystem->write("catalog.json", $catalogJSON);
271
        $jsonCatalogProvider = new JSONCatalogProvider($filesystem, "catalog.json", $catalogMapper);
272
273
        // act
274
        $catalog = $jsonCatalogProvider->getCatalog();
275
276
        // assert
277
        $products = $catalog->getProducts();
278
        $this->assertCount(1, $products, "getCatalog should return a catalog with one product");
279
280
        /** @var Product $firstProduct */
281
        $firstProduct = $products[0];
282
        $this->assertEquals("t-shirt-no-1", $firstProduct->getSku(), "Wrong SKU");
283
        $this->assertEquals("t-shirt-no-1-slug", $firstProduct->getSlug(), "Wrong slug");
284
        $this->assertEquals("T-Shirt No. 1", $firstProduct->getTitle(), "Wrong title");
285
        $this->assertEquals("Our T-Shirt No. 1", $firstProduct->getSummaryText(), "Wrong summary");
286
        $this->assertEquals("Our fancy T-Shirt No. 1 is ...", $firstProduct->getProductDescription(),
287
            "Wrong description");
288
    }
289
290
    /**
291
     * Get invalid catalog JSON for testing
292
     *
293
     * @return array
294
     */
295
    public static function getInvalidCatalogJSON()
296
    {
297
        return array(
298
299
            // JavaScript instead of JSON
300
            [
301
                <<<JSON
302
                var test = {
303
    "sku": "t-shirt-no-1",
304
    "slug": "t-shirt-no-1-slug",
305
    "title": "T-Shirt No. 1",
306
    "summary": "Our T-Shirt No. 1",
307
    "description": "Our fancy T-Shirt No. 1 is ..."
308
};
309
JSON
310
            ],
311
312
            // Missing attribute quotes
313
            [
314
                <<<JSON
315
                [
316
    {
317
        sku: "t-shirt-no-1",
318
        slug: "t-shirt-no-1-slug",
319
        title: "T-Shirt No. 1",
320
        summary: "Our T-Shirt No. 1",
321
        description: "Our fancy T-Shirt No. 1 is ..."
322
    }
323
]
324
JSON
325
            ],
326
327
            // Missing comma
328
            [
329
                <<<JSON
330
                [
331
    {
332
        "sku": "t-shirt-no-1"
333
        "slug": "t-shirt-no-1-slug"
334
        "title": "T-Shirt No. 1"
335
        "summary": "Our T-Shirt No. 1"
336
        "description": "Our fancy T-Shirt No. 1 is ..."
337
    }
338
]
339
JSON
340
            ],
341
342
            // Control Character
343
            [
344
                <<<JSON
345
                [
346
    {
347
        "sku": "t-shirt-no-1"
348
        "slug": "t-shirt-no-1-slug"
349
        "title": "T-Shirt No. 1"
350
        "summary": "Our T-Shirt No. 1"
351
        "���": "Our fancy T-Shirt No. 1 is ..."
352
    }
353
]
354
JSON
355
            ]
356
        );
357
    }
358
}
359