Files
MapLibreParticleLab/test/annotations/sprite_parser.cpp
Thiago Marcos P. Santos 0ee9f21c56 Report Sprite parsing errors to Observers
Parsing errors will be reported to Observers. In practice this will
bubble all the way to the Map object.

This will make possible to identify possible corrupted data instead
of rendering without sprites like we do in case of semantic errors.
2015-07-10 10:48:46 +03:00

311 lines
13 KiB
C++

#include "../fixtures/util.hpp"
#include "../fixtures/fixture_log_observer.hpp"
#include <mbgl/annotation/sprite_parser.hpp>
#include <mbgl/annotation/sprite_image.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <algorithm>
using namespace mbgl;
TEST(Annotations, SpriteImageCreationInvalid) {
FixtureLog log;
const util::Image image_1x(util::read_file("test/fixtures/annotations/emerald.png"));
ASSERT_TRUE(image_1x);
ASSERT_EQ(200u, image_1x.getWidth());
ASSERT_EQ(299u, image_1x.getHeight());
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 0, 16, 1, false)); // width == 0
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 16, 0, 1, false)); // height == 0
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 1, 1, 0, false)); // ratio == 0
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 1, 1, 23, false)); // ratio too large
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 2048, 16, 1, false)); // too wide
ASSERT_EQ(nullptr, createSpriteImage(image_1x, 0, 0, 16, 1025, 1, false)); // too tall
EXPECT_EQ(6u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Can't create sprite with invalid metrics",
}));
}
TEST(Annotations, SpriteImageCreation1x) {
const util::Image image_1x(util::read_file("test/fixtures/annotations/emerald.png"));
ASSERT_TRUE(image_1x);
ASSERT_EQ(200u, image_1x.getWidth());
ASSERT_EQ(299u, image_1x.getHeight());
{ // "museum_icon":{"x":177,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false}
const auto sprite = createSpriteImage(image_1x, 177, 187, 18, 18, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(18, sprite->pixelWidth);
EXPECT_EQ(18, sprite->pixelHeight);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x7FCC5F263D1FFE16u, test::crc64(sprite->data));
}
{ // outside image == blank
const auto sprite = createSpriteImage(image_1x, 200, 0, 16, 16, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(16, sprite->width);
EXPECT_EQ(16, sprite->height);
EXPECT_EQ(16, sprite->pixelWidth);
EXPECT_EQ(16, sprite->pixelHeight);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->data)) << std::hex << test::crc64(sprite->data);
}
{ // outside image == blank
const auto sprite = createSpriteImage(image_1x, 0, 300, 16, 16, 1, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(16, sprite->width);
EXPECT_EQ(16, sprite->height);
EXPECT_EQ(16, sprite->pixelWidth);
EXPECT_EQ(16, sprite->pixelHeight);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0x0000000000000000u, test::crc64(sprite->data)) << std::hex << test::crc64(sprite->data);
}
}
TEST(Annotations, SpriteImageCreation2x) {
const util::Image image_2x(util::read_file("test/fixtures/annotations/emerald@2x.png"));
ASSERT_TRUE(image_2x);
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite = createSpriteImage(image_2x, 354, 374, 36, 36, 2, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(36, sprite->pixelWidth);
EXPECT_EQ(36, sprite->pixelHeight);
EXPECT_EQ(2, sprite->pixelRatio);
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->data));
}
TEST(Annotations, SpriteImageCreation1_5x) {
const util::Image image_2x(util::read_file("test/fixtures/annotations/emerald@2x.png"));
ASSERT_TRUE(image_2x);
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite = createSpriteImage(image_2x, 354, 374, 36, 36, 1.5, false);
ASSERT_TRUE(sprite.get());
EXPECT_EQ(24, sprite->width);
EXPECT_EQ(24, sprite->height);
EXPECT_EQ(36, sprite->pixelWidth);
EXPECT_EQ(36, sprite->pixelHeight);
EXPECT_EQ(1.5, sprite->pixelRatio);
EXPECT_EQ(0x85F345098DD4F9E3u, test::crc64(sprite->data));
// "hospital_icon":{"x":314,"y":518,"width":36,"height":36,"pixelRatio":2,"sdf":false}
const auto sprite2 = createSpriteImage(image_2x, 314, 518, 35, 35, 1.5, false);
ASSERT_TRUE(sprite2.get());
EXPECT_EQ(24, sprite2->width);
EXPECT_EQ(24, sprite2->height);
EXPECT_EQ(36, sprite2->pixelWidth);
EXPECT_EQ(36, sprite2->pixelHeight);
EXPECT_EQ(1.5, sprite2->pixelRatio);
EXPECT_EQ(0x134A530C742DD141u, test::crc64(sprite2->data));
}
TEST(Annotations, SpriteParsing) {
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = util::read_file("test/fixtures/annotations/emerald.json");
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
std::set<std::string> names;
std::transform(images.begin(), images.end(), std::inserter(names, names.begin()),
[](const auto& pair) { return pair.first; });
EXPECT_EQ(std::set<std::string>({ "airfield_icon",
"airport_icon",
"background",
"cemetery_icon",
"college_icon",
"default_1",
"default_2",
"default_3",
"default_4",
"default_5",
"default_6",
"default_marker",
"dlr",
"dlr.london-overground.london-underground.national-rail",
"dlr.london-underground",
"dlr.london-underground.national-rail",
"dlr.national-rail",
"dot",
"embassy_icon",
"fire-station_icon",
"generic-metro",
"generic-rail",
"generic_icon",
"golf_icon",
"government_icon",
"grass_pattern",
"harbor_icon",
"hospital_icon",
"hospital_striped",
"interstate_1",
"interstate_2",
"interstate_3",
"library_icon",
"london-overground",
"london-overground.london-underground",
"london-overground.london-underground.national-rail",
"london-overground.national-rail",
"london-underground",
"london-underground.national-rail",
"marker_icon",
"metro",
"metro.rer",
"monument_icon",
"moscow-metro",
"museum_icon",
"national-rail",
"oneway_motorway",
"oneway_road",
"park_icon",
"police_icon",
"post_icon",
"prison_icon",
"religious-christian_icon",
"religious-jewish_icon",
"religious-muslim_icon",
"rer",
"rer.transilien",
"s-bahn",
"s-bahn.u-bahn",
"sand_noise",
"school_icon",
"school_striped",
"secondary_marker",
"u-bahn",
"us_highway_1",
"us_highway_2",
"us_highway_3",
"us_state_1",
"us_state_2",
"us_state_3",
"washington-metro",
"wiener-linien",
"zoo_icon" }),
names);
{
auto sprite = images.find("generic-metro")->second;
EXPECT_EQ(18, sprite->width);
EXPECT_EQ(18, sprite->height);
EXPECT_EQ(18, sprite->pixelWidth);
EXPECT_EQ(18, sprite->pixelHeight);
EXPECT_EQ(1, sprite->pixelRatio);
EXPECT_EQ(0xFF56F5F48F707147u, test::crc64(sprite->data));
}
}
TEST(Annotations, SpriteParsingInvalidJSON) {
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": " })JSON";
const auto error = parseSprite(image_1x, json_1x).get<std::string>();
EXPECT_EQ(error,
std::string("Failed to parse JSON: lacks ending quotation before the end of string at offset 10"));
}
TEST(Annotations, SpriteParsingEmptyImage) {
FixtureLog log;
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": {} })JSON";
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
EXPECT_EQ(0u, images.size());
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Can't create sprite with invalid metrics",
}));
}
TEST(Annotations, SpriteParsingSimpleWidthHeight) {
FixtureLog log;
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": { "width": 32, "height": 32 } })JSON";
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
EXPECT_EQ(1u, images.size());
}
TEST(Annotations, SpriteParsingWidthTooBig) {
FixtureLog log;
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": { "width": 65536, "height": 32 } })JSON";
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
EXPECT_EQ(0u, images.size());
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Value of 'width' must be an integer between 0 and 65535",
}));
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Can't create sprite with invalid metrics",
}));
}
TEST(Annotations, SpriteParsingNegativeWidth) {
FixtureLog log;
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": { "width": -1, "height": 32 } })JSON";
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
EXPECT_EQ(0u, images.size());
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Value of 'width' must be an integer between 0 and 65535",
}));
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Can't create sprite with invalid metrics",
}));
}
TEST(Annotations, SpriteParsingNullRatio) {
FixtureLog log;
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
const auto json_1x = R"JSON({ "image": { "width": 32, "height": 32, "pixelRatio": 0 } })JSON";
const auto images = parseSprite(image_1x, json_1x).get<Sprites>();
EXPECT_EQ(0u, images.size());
EXPECT_EQ(1u, log.count({
EventSeverity::Warning,
Event::Sprite,
int64_t(-1),
"Can't create sprite with invalid metrics",
}));
}