blob: 91e2f749b4baac28951e756866ad9795074704ee [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/doodle/doodle_types.h"
#include <memory>
#include <string>
#include "base/json/json_reader.h"
#include "base/optional.h"
#include "base/values.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using testing::Eq;
namespace doodle {
namespace {
// Parses the given |json| string into a base::DictionaryValue and creates a
// DoodleImage out of that. |json| must be a valid json string.
base::Optional<DoodleImage> DoodleImageFromJson(
const std::string& json,
const base::Optional<GURL>& base_url) {
std::unique_ptr<base::DictionaryValue> value =
base::DictionaryValue::From(base::JSONReader::Read(json));
DCHECK(value);
return DoodleImage::FromDictionary(*value, base_url);
}
// Parses the given |json| string into a base::DictionaryValue and creates a
// DoodleConfig out of that. |json| must be a valid json string.
base::Optional<DoodleConfig> DoodleConfigFromJson(
const std::string& json,
const base::Optional<GURL>& base_url) {
std::unique_ptr<base::DictionaryValue> value =
base::DictionaryValue::From(base::JSONReader::Read(json));
DCHECK(value);
return DoodleConfig::FromDictionary(*value, base_url);
}
} // namespace
TEST(DoodleImageTest, ParsesMinimalImage) {
std::string json = R"json({
"url":"https://www.doodle.com/doodle"
})json";
base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
ASSERT_TRUE(image.has_value());
EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/doodle")));
EXPECT_THAT(image->height, Eq(0));
EXPECT_THAT(image->width, Eq(0));
EXPECT_THAT(image->is_animated_gif, Eq(false));
EXPECT_THAT(image->is_cta, Eq(false));
}
TEST(DoodleImageTest, ParsesFullImage) {
std::string json = R"json({
"url":"https://www.doodle.com/doodle",
"height":100,
"width":50,
"is_animated_gif":true,
"is_cta":true
})json";
base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
ASSERT_TRUE(image.has_value());
EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/doodle")));
EXPECT_THAT(image->height, Eq(100));
EXPECT_THAT(image->width, Eq(50));
EXPECT_THAT(image->is_animated_gif, Eq(true));
EXPECT_THAT(image->is_cta, Eq(true));
}
TEST(DoodleImageTest, ResolvesRelativeUrl) {
std::string json = R"json({
"url":"/the_doodle_path"
})json";
base::Optional<DoodleImage> image =
DoodleImageFromJson(json, GURL("https://doodle.dood/"));
ASSERT_TRUE(image.has_value());
EXPECT_THAT(image->url, Eq(GURL("https://doodle.dood/the_doodle_path")));
}
TEST(DoodleImageTest, DoesNotResolveAbsoluteUrl) {
std::string json = R"json({
"url":"https://www.doodle.com/the_doodle_path"
})json";
base::Optional<DoodleImage> image =
DoodleImageFromJson(json, GURL("https://other.com/"));
ASSERT_TRUE(image.has_value());
EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/the_doodle_path")));
}
TEST(DoodleImageTest, RequiresUrl) {
std::string json = R"json({
"height":100,
"width":50,
"is_animated_gif":true,
"is_cta":true
})json";
base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
EXPECT_FALSE(image.has_value());
}
TEST(DoodleImageTest, HandlesInvalidUrl) {
std::string json = R"json({
"url":"not_a_url"
})json";
base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
// The URL is required, and invalid should be treated like missing.
EXPECT_FALSE(image.has_value());
}
TEST(DoodleImageTest, PreservesFieldsOverRoundtrip) {
// Set all fields to non-default values.
DoodleImage image(GURL("https://www.doodle.com/doodle"));
image.height = 100;
image.width = 50;
image.is_animated_gif = true;
image.is_cta = true;
// Convert to a dictionary and back.
base::Optional<DoodleImage> after_roundtrip =
DoodleImage::FromDictionary(*image.ToDictionary(), base::nullopt);
// Make sure everything survived.
ASSERT_TRUE(after_roundtrip.has_value());
EXPECT_THAT(*after_roundtrip, Eq(image));
}
TEST(DoodleConfigTest, ParsesMinimalConfig) {
std::string json = R"json({
"large_image":{"url":"https://doodle.com/img.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, base::nullopt);
ASSERT_TRUE(config.has_value());
EXPECT_THAT(config->doodle_type, Eq(DoodleType::UNKNOWN));
EXPECT_THAT(config->alt_text, Eq(std::string()));
EXPECT_THAT(config->interactive_html, Eq(std::string()));
EXPECT_THAT(config->target_url, Eq(GURL()));
EXPECT_FALSE(config->large_cta_image.has_value());
EXPECT_FALSE(config->transparent_large_image.has_value());
}
TEST(DoodleConfigTest, ParsesFullConfig) {
std::string json = R"json({
"doodle_type":"SLIDESHOW",
"alt_text":"some text",
"interactive_html":"<div id='dood'></div>",
"target_url":"https://doodle.com/target",
"large_image":{"url":"https://doodle.com/img.jpg"},
"large_cta_image":{"url":"https://doodle.com/cta.jpg"},
"transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, base::nullopt);
ASSERT_TRUE(config.has_value());
EXPECT_THAT(config->doodle_type, Eq(DoodleType::SLIDESHOW));
EXPECT_THAT(config->alt_text, Eq("some text"));
EXPECT_THAT(config->interactive_html, Eq("<div id='dood'></div>"));
EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
EXPECT_THAT(config->large_image.url, Eq(GURL("https://doodle.com/img.jpg")));
ASSERT_TRUE(config->large_cta_image.has_value());
EXPECT_THAT(config->large_cta_image->url,
Eq(GURL("https://doodle.com/cta.jpg")));
ASSERT_TRUE(config->transparent_large_image.has_value());
EXPECT_THAT(config->transparent_large_image->url,
Eq(GURL("https://doodle.com/transparent.jpg")));
}
TEST(DoodleConfigTest, RequiresLargeImage) {
std::string json = R"json({
"doodle_type":"SLIDESHOW",
"alt_text":"some text",
"interactive_html":"<div id='dood'></div>",
"target_url":"https://doodle.com/target",
"large_cta_image":{"url":"https://doodle.com/cta.jpg"},
"transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, base::nullopt);
EXPECT_FALSE(config.has_value());
}
TEST(DoodleConfigTest, RequiresValidLargeImage) {
std::string json = R"json({
"doodle_type":"SLIDESHOW",
"alt_text":"some text",
"interactive_html":"<div id='dood'></div>",
"target_url":"https://doodle.com/target",
"large_image":{"no_url":"asdf"},
"large_cta_image":{"url":"https://doodle.com/cta.jpg"},
"transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, base::nullopt);
EXPECT_FALSE(config.has_value());
}
TEST(DoodleConfigTest, ResolvesRelativeUrls) {
std::string json = R"json({
"target_url":"/target",
"large_image":{"url":"/large.jpg"},
"large_cta_image":{"url":"/cta.jpg"},
"transparent_large_image":{"url":"/transparent.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, GURL("https://doodle.com/"));
ASSERT_TRUE(config.has_value());
EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
EXPECT_THAT(config->large_image.url,
Eq(GURL("https://doodle.com/large.jpg")));
ASSERT_TRUE(config->large_cta_image.has_value());
EXPECT_THAT(config->large_cta_image->url,
Eq(GURL("https://doodle.com/cta.jpg")));
ASSERT_TRUE(config->transparent_large_image.has_value());
EXPECT_THAT(config->transparent_large_image->url,
Eq(GURL("https://doodle.com/transparent.jpg")));
}
TEST(DoodleConfigTest, HandlesInvalidUrls) {
std::string json = R"json({
"target_url":"not_a_url",
"large_image":{"url":"https://doodle.com/img.jpg"}
})json";
base::Optional<DoodleConfig> config =
DoodleConfigFromJson(json, base::nullopt);
// All the URLs are optional, so invalid ones shouldn't matter.
ASSERT_TRUE(config.has_value());
EXPECT_TRUE(config->target_url.is_empty());
}
TEST(DoodleConfigTest, PreservesFieldsOverRoundtrip) {
// Set all fields to non-default values.
DoodleConfig config(DoodleType::SLIDESHOW,
DoodleImage(GURL("https://www.doodle.com/img.jpg")));
config.alt_text = "some text";
config.interactive_html = "<div id='dood'></div>";
config.target_url = GURL("https://doodle.com/target");
config.large_cta_image = DoodleImage(GURL("https://www.doodle.com/cta.jpg"));
config.transparent_large_image =
DoodleImage(GURL("https://www.doodle.com/transparent.jpg"));
// Convert to a dictionary and back.
// Note: The different |base_url| should make no difference, since all
// persisted URLs are absolute already.
base::Optional<DoodleConfig> after_roundtrip = DoodleConfig::FromDictionary(
*config.ToDictionary(), GURL("https://other.com"));
// Make sure everything survived.
ASSERT_TRUE(after_roundtrip.has_value());
EXPECT_THAT(*after_roundtrip, Eq(config));
}
} // namespace doodle