1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/manifest/manifest_parser.h"
7 #include "base/strings/string_util.h"
8 #include "content/public/common/manifest.h"
9 #include "testing/gtest/include/gtest/gtest.h"
13 class ManifestParserTest
: public testing::Test
{
15 ManifestParserTest() {}
16 virtual ~ManifestParserTest() {}
18 Manifest
ParseManifest(const base::StringPiece
& json
,
19 const GURL
& document_url
= default_document_url
,
20 const GURL
& manifest_url
= default_manifest_url
) {
21 return ManifestParser::Parse(json
, document_url
, manifest_url
);
24 static const GURL default_document_url
;
25 static const GURL default_manifest_url
;
28 DISALLOW_COPY_AND_ASSIGN(ManifestParserTest
);
31 const GURL
ManifestParserTest::default_document_url(
32 "http://foo.com/index.html");
33 const GURL
ManifestParserTest::default_manifest_url(
34 "http://foo.com/manifest.json");
36 TEST_F(ManifestParserTest
, EmptyStringNull
) {
37 Manifest manifest
= ParseManifest("");
39 // A parsing error is equivalent to an empty manifest.
40 ASSERT_TRUE(manifest
.IsEmpty());
41 ASSERT_TRUE(manifest
.name
.is_null());
42 ASSERT_TRUE(manifest
.short_name
.is_null());
43 ASSERT_TRUE(manifest
.start_url
.is_empty());
44 ASSERT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_UNSPECIFIED
);
45 ASSERT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockDefault
);
48 TEST_F(ManifestParserTest
, ValidNoContentParses
) {
49 Manifest manifest
= ParseManifest("{}");
51 // Check that all the fields are null in that case.
52 ASSERT_TRUE(manifest
.IsEmpty());
53 ASSERT_TRUE(manifest
.name
.is_null());
54 ASSERT_TRUE(manifest
.short_name
.is_null());
55 ASSERT_TRUE(manifest
.start_url
.is_empty());
56 ASSERT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_UNSPECIFIED
);
57 ASSERT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockDefault
);
60 TEST_F(ManifestParserTest
, NameParseRules
) {
63 Manifest manifest
= ParseManifest("{ \"name\": \"foo\" }");
64 ASSERT_TRUE(EqualsASCII(manifest
.name
.string(), "foo"));
65 ASSERT_FALSE(manifest
.IsEmpty());
70 Manifest manifest
= ParseManifest("{ \"name\": \" foo \" }");
71 ASSERT_TRUE(EqualsASCII(manifest
.name
.string(), "foo"));
74 // Don't parse if name isn't a string.
76 Manifest manifest
= ParseManifest("{ \"name\": {} }");
77 ASSERT_TRUE(manifest
.name
.is_null());
80 // Don't parse if name isn't a string.
82 Manifest manifest
= ParseManifest("{ \"name\": 42 }");
83 ASSERT_TRUE(manifest
.name
.is_null());
87 TEST_F(ManifestParserTest
, ShortNameParseRules
) {
90 Manifest manifest
= ParseManifest("{ \"short_name\": \"foo\" }");
91 ASSERT_TRUE(EqualsASCII(manifest
.short_name
.string(), "foo"));
92 ASSERT_FALSE(manifest
.IsEmpty());
97 Manifest manifest
= ParseManifest("{ \"short_name\": \" foo \" }");
98 ASSERT_TRUE(EqualsASCII(manifest
.short_name
.string(), "foo"));
101 // Don't parse if name isn't a string.
103 Manifest manifest
= ParseManifest("{ \"short_name\": {} }");
104 ASSERT_TRUE(manifest
.short_name
.is_null());
107 // Don't parse if name isn't a string.
109 Manifest manifest
= ParseManifest("{ \"short_name\": 42 }");
110 ASSERT_TRUE(manifest
.short_name
.is_null());
114 TEST_F(ManifestParserTest
, StartURLParseRules
) {
117 Manifest manifest
= ParseManifest("{ \"start_url\": \"land.html\" }");
118 ASSERT_EQ(manifest
.start_url
.spec(),
119 default_document_url
.Resolve("land.html").spec());
120 ASSERT_FALSE(manifest
.IsEmpty());
125 Manifest manifest
= ParseManifest("{ \"start_url\": \" land.html \" }");
126 ASSERT_EQ(manifest
.start_url
.spec(),
127 default_document_url
.Resolve("land.html").spec());
130 // Don't parse if property isn't a string.
132 Manifest manifest
= ParseManifest("{ \"start_url\": {} }");
133 ASSERT_TRUE(manifest
.start_url
.is_empty());
136 // Don't parse if property isn't a string.
138 Manifest manifest
= ParseManifest("{ \"start_url\": 42 }");
139 ASSERT_TRUE(manifest
.start_url
.is_empty());
142 // Absolute start_url, same origin with document.
145 ParseManifest("{ \"start_url\": \"http://foo.com/land.html\" }",
146 GURL("http://foo.com/manifest.json"),
147 GURL("http://foo.com/index.html"));
148 ASSERT_EQ(manifest
.start_url
.spec(), "http://foo.com/land.html");
151 // Absolute start_url, cross origin with document.
154 ParseManifest("{ \"start_url\": \"http://bar.com/land.html\" }",
155 GURL("http://foo.com/manifest.json"),
156 GURL("http://foo.com/index.html"));
157 ASSERT_TRUE(manifest
.start_url
.is_empty());
160 // Resolving has to happen based on the manifest_url.
163 ParseManifest("{ \"start_url\": \"land.html\" }",
164 GURL("http://foo.com/landing/manifest.json"),
165 GURL("http://foo.com/index.html"));
166 ASSERT_EQ(manifest
.start_url
.spec(), "http://foo.com/landing/land.html");
170 TEST_F(ManifestParserTest
, DisplayParserRules
) {
173 Manifest manifest
= ParseManifest("{ \"display\": \"browser\" }");
174 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_BROWSER
);
175 EXPECT_FALSE(manifest
.IsEmpty());
180 Manifest manifest
= ParseManifest("{ \"display\": \" browser \" }");
181 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_BROWSER
);
184 // Don't parse if name isn't a string.
186 Manifest manifest
= ParseManifest("{ \"display\": {} }");
187 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_UNSPECIFIED
);
190 // Don't parse if name isn't a string.
192 Manifest manifest
= ParseManifest("{ \"display\": 42 }");
193 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_UNSPECIFIED
);
196 // Parse fails if string isn't known.
198 Manifest manifest
= ParseManifest("{ \"display\": \"browser_something\" }");
199 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_UNSPECIFIED
);
202 // Accept 'fullscreen'.
204 Manifest manifest
= ParseManifest("{ \"display\": \"fullscreen\" }");
205 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_FULLSCREEN
);
208 // Accept 'fullscreen'.
210 Manifest manifest
= ParseManifest("{ \"display\": \"standalone\" }");
211 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_STANDALONE
);
214 // Accept 'minimal-ui'.
216 Manifest manifest
= ParseManifest("{ \"display\": \"minimal-ui\" }");
217 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_MINIMAL_UI
);
222 Manifest manifest
= ParseManifest("{ \"display\": \"browser\" }");
223 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_BROWSER
);
228 Manifest manifest
= ParseManifest("{ \"display\": \"BROWSER\" }");
229 EXPECT_EQ(manifest
.display
, Manifest::DISPLAY_MODE_BROWSER
);
233 TEST_F(ManifestParserTest
, OrientationParserRules
) {
236 Manifest manifest
= ParseManifest("{ \"orientation\": \"natural\" }");
237 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockNatural
);
238 EXPECT_FALSE(manifest
.IsEmpty());
243 Manifest manifest
= ParseManifest("{ \"orientation\": \"natural\" }");
244 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockNatural
);
247 // Don't parse if name isn't a string.
249 Manifest manifest
= ParseManifest("{ \"orientation\": {} }");
250 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockDefault
);
253 // Don't parse if name isn't a string.
255 Manifest manifest
= ParseManifest("{ \"orientation\": 42 }");
256 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockDefault
);
259 // Parse fails if string isn't known.
261 Manifest manifest
= ParseManifest("{ \"orientation\": \"naturalish\" }");
262 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockDefault
);
267 Manifest manifest
= ParseManifest("{ \"orientation\": \"any\" }");
268 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockAny
);
273 Manifest manifest
= ParseManifest("{ \"orientation\": \"natural\" }");
274 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockNatural
);
277 // Accept 'landscape'.
279 Manifest manifest
= ParseManifest("{ \"orientation\": \"landscape\" }");
280 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockLandscape
);
283 // Accept 'landscape-primary'.
286 ParseManifest("{ \"orientation\": \"landscape-primary\" }");
287 EXPECT_EQ(manifest
.orientation
,
288 blink::WebScreenOrientationLockLandscapePrimary
);
291 // Accept 'landscape-secondary'.
294 ParseManifest("{ \"orientation\": \"landscape-secondary\" }");
295 EXPECT_EQ(manifest
.orientation
,
296 blink::WebScreenOrientationLockLandscapeSecondary
);
299 // Accept 'portrait'.
301 Manifest manifest
= ParseManifest("{ \"orientation\": \"portrait\" }");
302 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockPortrait
);
305 // Accept 'portrait-primary'.
308 ParseManifest("{ \"orientation\": \"portrait-primary\" }");
309 EXPECT_EQ(manifest
.orientation
,
310 blink::WebScreenOrientationLockPortraitPrimary
);
313 // Accept 'portrait-secondary'.
316 ParseManifest("{ \"orientation\": \"portrait-secondary\" }");
317 EXPECT_EQ(manifest
.orientation
,
318 blink::WebScreenOrientationLockPortraitSecondary
);
323 Manifest manifest
= ParseManifest("{ \"orientation\": \"LANDSCAPE\" }");
324 EXPECT_EQ(manifest
.orientation
, blink::WebScreenOrientationLockLandscape
);
328 TEST_F(ManifestParserTest
, IconsParseRules
) {
329 // Smoke test: if no icon, empty list.
331 Manifest manifest
= ParseManifest("{ \"icons\": [] }");
332 EXPECT_EQ(manifest
.icons
.size(), 0u);
333 EXPECT_TRUE(manifest
.IsEmpty());
336 // Smoke test: if empty icon, empty list.
338 Manifest manifest
= ParseManifest("{ \"icons\": [ {} ] }");
339 EXPECT_EQ(manifest
.icons
.size(), 0u);
340 EXPECT_TRUE(manifest
.IsEmpty());
343 // Smoke test: icon with invalid src, empty list.
345 Manifest manifest
= ParseManifest("{ \"icons\": [ { \"icons\": [] } ] }");
346 EXPECT_EQ(manifest
.icons
.size(), 0u);
347 EXPECT_TRUE(manifest
.IsEmpty());
350 // Smoke test: if icon with empty src, it will be present in the list.
352 Manifest manifest
= ParseManifest("{ \"icons\": [ { \"src\": \"\" } ] }");
353 EXPECT_EQ(manifest
.icons
.size(), 1u);
354 EXPECT_EQ(manifest
.icons
[0].src
.spec(), "http://foo.com/index.html");
355 EXPECT_FALSE(manifest
.IsEmpty());
358 // Smoke test: if one icons with valid src, it will be present in the list.
361 ParseManifest("{ \"icons\": [{ \"src\": \"foo.jpg\" }] }");
362 EXPECT_EQ(manifest
.icons
.size(), 1u);
363 EXPECT_EQ(manifest
.icons
[0].src
.spec(), "http://foo.com/foo.jpg");
364 EXPECT_FALSE(manifest
.IsEmpty());
368 TEST_F(ManifestParserTest
, IconSrcParseRules
) {
372 ParseManifest("{ \"icons\": [ {\"src\": \"foo.png\" } ] }");
373 EXPECT_EQ(manifest
.icons
[0].src
.spec(),
374 default_document_url
.Resolve("foo.png").spec());
380 ParseManifest("{ \"icons\": [ {\"src\": \" foo.png \" } ] }");
381 EXPECT_EQ(manifest
.icons
[0].src
.spec(),
382 default_document_url
.Resolve("foo.png").spec());
385 // Don't parse if property isn't a string.
387 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": {} } ] }");
388 EXPECT_TRUE(manifest
.icons
.empty());
391 // Don't parse if property isn't a string.
393 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": 42 } ] }");
394 EXPECT_TRUE(manifest
.icons
.empty());
397 // Resolving has to happen based on the document_url.
400 ParseManifest("{ \"icons\": [ {\"src\": \"icons/foo.png\" } ] }",
401 GURL("http://foo.com/landing/index.html"));
402 EXPECT_EQ(manifest
.icons
[0].src
.spec(),
403 "http://foo.com/landing/icons/foo.png");
407 TEST_F(ManifestParserTest
, IconTypeParseRules
) {
411 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": \"foo\" } ] }");
412 EXPECT_TRUE(EqualsASCII(manifest
.icons
[0].type
.string(), "foo"));
417 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
418 " \"type\": \" foo \" } ] }");
419 EXPECT_TRUE(EqualsASCII(manifest
.icons
[0].type
.string(), "foo"));
422 // Don't parse if property isn't a string.
425 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": {} } ] }");
426 EXPECT_TRUE(manifest
.icons
[0].type
.is_null());
429 // Don't parse if property isn't a string.
432 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": 42 } ] }");
433 EXPECT_TRUE(manifest
.icons
[0].type
.is_null());
437 TEST_F(ManifestParserTest
, IconDensityParseRules
) {
441 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 42 } ] }");
442 EXPECT_EQ(manifest
.icons
[0].density
, 42);
448 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 2.5 } ] }");
449 EXPECT_EQ(manifest
.icons
[0].density
, 2.5);
452 // Parse fail if it isn't a float.
455 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": {} } ] }");
456 EXPECT_EQ(manifest
.icons
[0].density
, Manifest::Icon::kDefaultDensity
);
459 // Parse fail if it isn't a float.
462 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\":\"2\" } ] }");
463 EXPECT_EQ(manifest
.icons
[0].density
, Manifest::Icon::kDefaultDensity
);
469 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 1.00 } ] }");
470 EXPECT_EQ(manifest
.icons
[0].density
, 1);
473 // Edge case: values between 0.0 and 1.0 are allowed.
476 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 0.42 } ] }");
477 EXPECT_EQ(manifest
.icons
[0].density
, 0.42);
480 // 0 is an invalid value.
483 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": 0.0 } ] }");
484 EXPECT_EQ(manifest
.icons
[0].density
, Manifest::Icon::kDefaultDensity
);
487 // Negative values are invalid.
490 ParseManifest("{ \"icons\": [ {\"src\": \"\", \"density\": -2.5 } ] }");
491 EXPECT_EQ(manifest
.icons
[0].density
, Manifest::Icon::kDefaultDensity
);
495 TEST_F(ManifestParserTest
, IconSizesParseRules
) {
498 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
499 "\"sizes\": \"42x42\" } ] }");
500 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 1u);
505 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
506 "\"sizes\": \" 42x42 \" } ] }");
507 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 1u);
510 // Don't parse if name isn't a string.
512 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
513 "\"sizes\": {} } ] }");
514 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 0u);
517 // Don't parse if name isn't a string.
519 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
520 "\"sizes\": 42 } ] }");
521 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 0u);
524 // Smoke test: value correctly parsed.
526 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
527 "\"sizes\": \"42x42 48x48\" } ] }");
528 EXPECT_EQ(manifest
.icons
[0].sizes
[0], gfx::Size(42, 42));
529 EXPECT_EQ(manifest
.icons
[0].sizes
[1], gfx::Size(48, 48));
532 // <WIDTH>'x'<HEIGHT> and <WIDTH>'X'<HEIGHT> are equivalent.
534 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
535 "\"sizes\": \"42X42 48X48\" } ] }");
536 EXPECT_EQ(manifest
.icons
[0].sizes
[0], gfx::Size(42, 42));
537 EXPECT_EQ(manifest
.icons
[0].sizes
[1], gfx::Size(48, 48));
540 // Twice the same value is parsed twice.
542 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
543 "\"sizes\": \"42X42 42x42\" } ] }");
544 EXPECT_EQ(manifest
.icons
[0].sizes
[0], gfx::Size(42, 42));
545 EXPECT_EQ(manifest
.icons
[0].sizes
[1], gfx::Size(42, 42));
548 // Width or height can't start with 0.
550 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
551 "\"sizes\": \"004X007 042x00\" } ] }");
552 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 0u);
555 // Width and height MUST contain digits.
557 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
558 "\"sizes\": \"e4X1.0 55ax1e10\" } ] }");
559 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 0u);
562 // 'any' is correctly parsed and transformed to gfx::Size(0,0).
564 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
565 "\"sizes\": \"any AnY ANY aNy\" } ] }");
566 gfx::Size any
= gfx::Size(0, 0);
567 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 4u);
568 EXPECT_EQ(manifest
.icons
[0].sizes
[0], any
);
569 EXPECT_EQ(manifest
.icons
[0].sizes
[1], any
);
570 EXPECT_EQ(manifest
.icons
[0].sizes
[2], any
);
571 EXPECT_EQ(manifest
.icons
[0].sizes
[3], any
);
574 // Some invalid width/height combinations.
576 Manifest manifest
= ParseManifest("{ \"icons\": [ {\"src\": \"\","
577 "\"sizes\": \"x 40xx 1x2x3 x42 42xx42\" } ] }");
578 gfx::Size any
= gfx::Size(0, 0);
579 EXPECT_EQ(manifest
.icons
[0].sizes
.size(), 0u);
583 TEST_F(ManifestParserTest
, GCMSenderIDParseRules
) {
586 Manifest manifest
= ParseManifest("{ \"gcm_sender_id\": \"foo\" }");
587 EXPECT_TRUE(EqualsASCII(manifest
.gcm_sender_id
.string(), "foo"));
592 Manifest manifest
= ParseManifest("{ \"gcm_sender_id\": \" foo \" }");
593 EXPECT_TRUE(EqualsASCII(manifest
.gcm_sender_id
.string(), "foo"));
596 // Don't parse if property isn't a string.
598 Manifest manifest
= ParseManifest("{ \"gcm_sender_id\": {} }");
599 EXPECT_TRUE(manifest
.gcm_sender_id
.is_null());
602 Manifest manifest
= ParseManifest("{ \"gcm_sender_id\": 42 }");
603 EXPECT_TRUE(manifest
.gcm_sender_id
.is_null());
607 } // namespace content