TEST(Sprite, SpriteAtlas) { FixtureLog log; auto spriteParseResult = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"), util::read_file("test/fixtures/annotations/emerald.json")); SpriteStore store(1); store.setSprites(spriteParseResult.get<Sprites>()); SpriteAtlas atlas(63, 112, 1, store); EXPECT_EQ(1.0f, atlas.getPixelRatio()); EXPECT_EQ(63, atlas.getWidth()); EXPECT_EQ(112, atlas.getHeight()); EXPECT_EQ(63, atlas.getTextureWidth()); EXPECT_EQ(112, atlas.getTextureHeight()); // Image hasn't been created yet. EXPECT_FALSE(atlas.getData()); auto metro = *atlas.getImage("metro", false); EXPECT_EQ(0, metro.pos.x); EXPECT_EQ(0, metro.pos.y); EXPECT_EQ(20, metro.pos.w); EXPECT_EQ(20, metro.pos.h); EXPECT_EQ(18, metro.spriteImage->getWidth()); EXPECT_EQ(18, metro.spriteImage->getHeight()); EXPECT_EQ(18, metro.spriteImage->image.width); EXPECT_EQ(18, metro.spriteImage->image.height); EXPECT_EQ(1.0f, metro.spriteImage->pixelRatio); EXPECT_TRUE(atlas.getData()); auto pos = *atlas.getPosition("metro", false); EXPECT_DOUBLE_EQ(18, pos.size[0]); EXPECT_DOUBLE_EQ(18, pos.size[1]); EXPECT_DOUBLE_EQ(1.0f / 63, pos.tl[0]); EXPECT_DOUBLE_EQ(1.0f / 112, pos.tl[1]); EXPECT_DOUBLE_EQ(19.0f / 63, pos.br[0]); EXPECT_DOUBLE_EQ(19.0f / 112, pos.br[1]); auto missing = atlas.getImage("doesnotexist", false); EXPECT_FALSE(missing); EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Sprite, int64_t(-1), "Can't find sprite named 'doesnotexist'", })); // Different wrapping mode produces different image. auto metro2 = *atlas.getImage("metro", true); EXPECT_EQ(20, metro2.pos.x); EXPECT_EQ(0, metro2.pos.y); EXPECT_EQ(20, metro2.pos.w); EXPECT_EQ(20, metro2.pos.h); EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlas.png"), imageFromAtlas(atlas)); }
TEST(SpriteStore, ReplaceWithDifferentDimensions) { FixtureLog log; PremultipliedImage image(16, 16); PremultipliedImage image2(18, 18); const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2); const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(18, 18), 2); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; SpriteStore store(1); store.setSprite("sprite", sprite1); store.setSprite("sprite", sprite2); EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Sprite, int64_t(-1), "Can't change sprite dimensions for 'sprite'", })); EXPECT_EQ(sprite1, store.getSprite("sprite")); EXPECT_EQ(Sprites({ { "sprite", sprite1 } }), store.getDirty()); }
TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) { FixtureLog log; // Should return a CANTOPEN exception when the database doesn't exist, // make sure all the backends behave the same way. auto result = mapbox::sqlite::Database::tryOpen("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly); ASSERT_TRUE(result.is<mapbox::sqlite::Exception>()); ASSERT_EQ(result.get<mapbox::sqlite::Exception>().code, mapbox::sqlite::ResultCode::CantOpen); EXPECT_EQ(0u, log.uncheckedCount()); }
TEST(ImageManager, RemoveReleasesBinPackRect) { FixtureLog log; ImageManager imageManager; imageManager.addImage(makeMutable<style::Image::Impl>("big", PremultipliedImage({ 32, 32 }), 1)); EXPECT_TRUE(imageManager.getImage("big")); imageManager.removeImage("big"); imageManager.addImage(makeMutable<style::Image::Impl>("big", PremultipliedImage({ 32, 32 }), 1)); EXPECT_TRUE(imageManager.getImage("big")); EXPECT_TRUE(log.empty()); }
TEST(Sprite, CustomSpriteImages) { FixtureLog log; auto display = std::make_shared<mbgl::HeadlessDisplay>(); HeadlessView view(display, 1); view.resize(256, 256); DefaultFileSource fileSource(nullptr); const auto style = util::read_file("test/fixtures/headless/pois.json"); Map map(view, fileSource, MapMode::Still); map.setLatLngZoom(LatLng{ 52.499167, 13.418056 }, 15); map.setStyleJSON(style, ""); map.setSprite("cafe", std::make_shared<SpriteImage>(12, 12, 1, std::string(12 * 12 * 4, '\xFF'))); std::promise<std::unique_ptr<const StillImage>> promise; map.renderStill([&promise](std::exception_ptr error, std::unique_ptr<const StillImage> image) { if (error) { promise.set_exception(error); } else { promise.set_value(std::move(image)); } }); auto result = promise.get_future().get(); ASSERT_EQ(256, result->width); ASSERT_EQ(256, result->height); EXPECT_EQ( 21u, log.count({ EventSeverity::Info, Event::Sprite, int64_t(-1), "Can't find sprite named 'bakery'", })); // const size_t bytes = result->width * result->height * 4; // const auto hash = test::crc64(reinterpret_cast<const char*>(result->pixels.get()), bytes); // EXPECT_EQ(0xC40A4BCD76AEC564u, hash) << std::hex << hash; // const std::string png = util::compress_png(result->width, result->height, // result->pixels.get()); // util::write_file("test/fixtures/headless/1.actual.png", png); }
TEST(Sprite, SpriteStoreReplaceWithDifferentDimensions) { FixtureLog log; const auto sprite1 = std::make_shared<SpriteImage>(8, 8, 2, std::string(16 * 16 * 4, '\0')); const auto sprite2 = std::make_shared<SpriteImage>(9, 9, 2, std::string(18 * 18 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; SpriteStore store(1); store.setSprite("sprite", sprite1); store.setSprite("sprite", sprite2); EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Sprite, int64_t(-1), "Can't change sprite dimensions for 'sprite'", })); EXPECT_EQ(sprite1, store.getSprite("sprite")); EXPECT_EQ(Sprites({ { "sprite", sprite1 } }), store.getDirty()); }
TEST(SpriteStore, SpriteStore) { FixtureLog log; const auto sprite1 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2); const auto sprite2 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2); const auto sprite3 = std::make_shared<SpriteImage>(PremultipliedImage(16, 16), 2); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; SpriteStore store(1); // Adding single store.setSprite("one", sprite1); EXPECT_EQ(Sprites({ { "one", sprite1 }, }), store.getDirty()); EXPECT_EQ(Sprites(), store.getDirty()); // Adding multiple store.setSprite("two", sprite2); store.setSprite("three", sprite3); EXPECT_EQ(Sprites({ { "two", sprite2 }, { "three", sprite3 }, }), store.getDirty()); EXPECT_EQ(Sprites(), store.getDirty()); // Removing store.removeSprite("one"); store.removeSprite("two"); EXPECT_EQ(Sprites({ { "one", nullptr }, { "two", nullptr }, }), store.getDirty()); EXPECT_EQ(Sprites(), store.getDirty()); // Accessing EXPECT_EQ(sprite3, store.getSprite("three")); EXPECT_TRUE(log.empty()); EXPECT_EQ(nullptr, store.getSprite("two")); EXPECT_EQ(nullptr, store.getSprite("four")); EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Sprite, int64_t(-1), "Can't find sprite named 'two'", })); EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Sprite, int64_t(-1), "Can't find sprite named 'four'", })); // Overwriting store.setSprite("three", sprite1); EXPECT_EQ(Sprites({ { "three", sprite1 }, }), store.getDirty()); EXPECT_EQ(Sprites(), store.getDirty()); }
TEST(Annotations, SpriteAtlas) { FixtureLog log; SpriteStore store; store.setSprites(parseSprite(util::read_file("test/fixtures/annotations/emerald.png"), util::read_file("test/fixtures/annotations/emerald.json"))); SpriteAtlas atlas(63, 112, 1, store); EXPECT_EQ(1.0f, atlas.getPixelRatio()); EXPECT_EQ(63, atlas.getWidth()); EXPECT_EQ(112, atlas.getHeight()); EXPECT_EQ(63, atlas.getTextureWidth()); EXPECT_EQ(112, atlas.getTextureHeight()); // Image hasn't been created yet. EXPECT_TRUE(atlas.getData()); auto metro = atlas.getImage("metro", false); EXPECT_EQ(0, metro.pos.x); EXPECT_EQ(0, metro.pos.y); EXPECT_EQ(20, metro.pos.w); EXPECT_EQ(20, metro.pos.h); EXPECT_EQ(18, metro.pos.originalW); EXPECT_EQ(18, metro.pos.originalH); EXPECT_EQ(18, metro.texture->width); EXPECT_EQ(18, metro.texture->height); EXPECT_EQ(18, metro.texture->pixelWidth); EXPECT_EQ(18, metro.texture->pixelHeight); EXPECT_EQ(1.0f, metro.texture->pixelRatio); auto pos = atlas.getPosition("metro", false); EXPECT_DOUBLE_EQ(20, pos.size[0]); EXPECT_DOUBLE_EQ(20, pos.size[1]); EXPECT_DOUBLE_EQ(1.0f / 63, pos.tl[0]); EXPECT_DOUBLE_EQ(1.0f / 112, pos.tl[1]); EXPECT_DOUBLE_EQ(21.0f / 63, pos.br[0]); EXPECT_DOUBLE_EQ(21.0f / 112, pos.br[1]); auto missing = atlas.getImage("doesnotexist", false); EXPECT_FALSE(missing.pos.hasArea()); EXPECT_EQ(0, missing.pos.x); EXPECT_EQ(0, missing.pos.y); EXPECT_EQ(0, missing.pos.w); EXPECT_EQ(0, missing.pos.h); EXPECT_EQ(0, missing.pos.originalW); EXPECT_EQ(0, missing.pos.originalH); EXPECT_FALSE(missing.texture); EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Sprite, int64_t(-1), "Can't find sprite named 'doesnotexist'", })); // Different wrapping mode produces different image. auto metro2 = atlas.getImage("metro", true); EXPECT_EQ(20, metro2.pos.x); EXPECT_EQ(0, metro2.pos.y); EXPECT_EQ(20, metro2.pos.w); EXPECT_EQ(20, metro2.pos.h); EXPECT_EQ(18, metro2.pos.originalW); EXPECT_EQ(18, metro2.pos.originalH); const size_t bytes = atlas.getTextureWidth() * atlas.getTextureHeight() * 4; const auto hash = test::crc64(reinterpret_cast<const char*>(atlas.getData()), bytes); EXPECT_EQ(0x9875FC0595489A9Fu, hash) << std::hex << hash; // util::write_file( // "test/fixtures/annotations/atlas1.png", // util::compress_png(atlas.getTextureWidth(), atlas.getTextureHeight(), atlas.getData())); }