summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.clang-tidy2
-rw-r--r--test/actor/actor.test.cpp223
-rw-r--r--test/actor/actor_ref.test.cpp80
-rw-r--r--test/algorithm/generate_clip_ids.test.cpp422
-rw-r--r--test/algorithm/update_renderables.test.cpp988
-rw-r--r--test/algorithm/update_tile_masks.test.cpp132
-rw-r--r--test/api/annotations.test.cpp172
-rw-r--r--test/api/api_misuse.test.cpp44
-rw-r--r--test/api/custom_layer.test.cpp22
-rw-r--r--test/api/query.test.cpp52
-rw-r--r--test/api/recycle_map.cpp58
-rw-r--r--test/api/render_missing.test.cpp64
-rw-r--r--test/api/repeated_render.test.cpp75
-rw-r--r--test/api/zoom_history.cpp71
-rw-r--r--test/fixtures/annotations/readd_image/expected.pngbin0 -> 1031 bytes
-rw-r--r--test/fixtures/api/empty-zoomed.json6
-rw-r--r--test/fixtures/image_manager/basic/expected.pngbin0 -> 646 bytes
-rw-r--r--test/fixtures/image_manager/updates_after/expected.pngbin0 -> 136 bytes
-rw-r--r--test/fixtures/image_manager/updates_before/expected.pngbin0 -> 123 bytes
-rw-r--r--test/fixtures/map/nocontent/expected.pngbin0 -> 1685 bytes
-rw-r--r--test/fixtures/map/prefetch/empty.json5
-rw-r--r--test/fixtures/map/prefetch/expected.pngbin0 -> 2198 bytes
-rw-r--r--test/fixtures/map/prefetch/style.json24
-rw-r--r--test/fixtures/map/prefetch/tile_green.pngbin0 -> 659 bytes
-rw-r--r--test/fixtures/map/prefetch/tile_red.pngbin0 -> 659 bytes
-rw-r--r--test/fixtures/offline_database/v5.dbbin0 -> 19456 bytes
-rw-r--r--test/fixtures/offline_download/radar.gifbin0 -> 10958 bytes
-rw-r--r--test/fixtures/offline_download/style.json10
-rw-r--r--test/fixtures/recycle_map/default_marker/expected.pngbin0 -> 1043 bytes
-rw-r--r--test/fixtures/recycle_map/flipped_marker/expected.pngbin0 -> 1031 bytes
-rw-r--r--test/fixtures/sprite_atlas/basic/expected.pngbin694 -> 0 bytes
-rw-r--r--test/fixtures/sprite_atlas/size/expected.pngbin1118 -> 0 bytes
-rw-r--r--test/fixtures/sprite_atlas/updates_after/expected.pngbin135 -> 0 bytes
-rw-r--r--test/fixtures/sprite_atlas/updates_before/expected.pngbin110 -> 0 bytes
-rw-r--r--test/fixtures/style_parser/center-not-latlong.info.json7
-rw-r--r--test/fixtures/style_parser/center-not-latlong.style.json4
-rw-r--r--test/fixtures/style_parser/geojson-missing-properties.info.json6
-rw-r--r--test/fixtures/style_parser/geojson-missing-properties.style.json9
-rw-r--r--test/fixtures/style_parser/image-coordinates.info.json7
-rw-r--r--test/fixtures/style_parser/image-coordinates.style.json14
-rw-r--r--test/fixtures/style_parser/image-url.info.json7
-rw-r--r--test/fixtures/style_parser/image-url.style.json9
-rw-r--r--test/fixtures/zoom_history/expected.pngbin0 -> 3894 bytes
-rw-r--r--test/geometry/binpack.test.cpp51
-rw-r--r--test/gl/bucket.test.cpp251
-rw-r--r--test/gl/object.test.cpp7
-rw-r--r--test/map/map.test.cpp523
-rw-r--r--test/map/prefetch.test.cpp89
-rw-r--r--test/map/transform.test.cpp21
-rw-r--r--test/programs/symbol_program.test.cpp57
-rw-r--r--test/renderer/backend_scope.test.cpp30
-rw-r--r--test/renderer/group_by_layout.test.cpp2
-rw-r--r--test/renderer/image_manager.test.cpp150
-rw-r--r--test/sprite/sprite_atlas.test.cpp373
-rw-r--r--test/sprite/sprite_loader.test.cpp179
-rw-r--r--test/sprite/sprite_parser.test.cpp88
-rw-r--r--test/src/mbgl/test/conversion_stubs.hpp9
-rw-r--r--test/src/mbgl/test/fake_file_source.hpp4
-rw-r--r--test/src/mbgl/test/fixture_log_observer.cpp9
-rw-r--r--test/src/mbgl/test/fixture_log_observer.hpp10
-rw-r--r--test/src/mbgl/test/getrss.cpp4
-rw-r--r--test/src/mbgl/test/getrss.hpp4
-rw-r--r--test/src/mbgl/test/stub_file_source.cpp3
-rw-r--r--test/src/mbgl/test/stub_file_source.hpp1
-rw-r--r--test/src/mbgl/test/stub_geometry_tile_feature.hpp11
-rw-r--r--test/src/mbgl/test/stub_layer_observer.hpp26
-rw-r--r--test/src/mbgl/test/stub_style_observer.hpp20
-rw-r--r--test/src/mbgl/test/util.cpp23
-rw-r--r--test/src/mbgl/test/util.hpp9
-rw-r--r--test/storage/asset_file_source.test.cpp19
-rw-r--r--test/storage/default_file_source.test.cpp213
-rw-r--r--test/storage/http_file_source.test.cpp9
-rw-r--r--test/storage/local_file_source.test.cpp2
-rw-r--r--test/storage/offline.test.cpp8
-rw-r--r--test/storage/offline_database.test.cpp64
-rw-r--r--test/storage/offline_download.test.cpp11
-rw-r--r--test/storage/online_file_source.test.cpp10
-rw-r--r--test/storage/resource.test.cpp7
-rwxr-xr-xtest/storage/server.js6
-rw-r--r--test/storage/sqlite.test.cpp11
-rw-r--r--test/style/conversion/function.test.cpp14
-rw-r--r--test/style/conversion/layer.test.cpp18
-rw-r--r--test/style/conversion/light.test.cpp14
-rw-r--r--test/style/conversion/stringify.test.cpp17
-rw-r--r--test/style/filter.test.cpp8
-rw-r--r--test/style/function/exponential_stops.test.cpp20
-rw-r--r--test/style/function/interval_stops.test.cpp20
-rw-r--r--test/style/function/source_function.test.cpp9
-rw-r--r--test/style/properties.test.cpp (renamed from test/style/paint_property.test.cpp)43
-rw-r--r--test/style/source.test.cpp231
-rw-r--r--test/style/style.test.cpp42
-rw-r--r--test/style/style_image.test.cpp26
-rw-r--r--test/style/style_layer.test.cpp47
-rw-r--r--test/style/style_parser.test.cpp4
-rw-r--r--test/text/glyph_loader.test.cpp (renamed from test/text/glyph_atlas.test.cpp)67
-rw-r--r--test/text/quads.test.cpp276
-rw-r--r--test/tile/annotation_tile.test.cpp42
-rw-r--r--test/tile/geojson_tile.test.cpp28
-rw-r--r--test/tile/raster_tile.test.cpp18
-rw-r--r--test/tile/tile_id.test.cpp146
-rw-r--r--test/tile/vector_tile.test.cpp24
-rw-r--r--test/util/async_task.test.cpp59
-rw-r--r--test/util/dtoa.test.cpp24
-rw-r--r--test/util/image.test.cpp52
-rw-r--r--test/util/memory.test.cpp71
-rw-r--r--test/util/merge_lines.test.cpp113
-rw-r--r--test/util/offscreen_texture.test.cpp35
-rw-r--r--test/util/thread.test.cpp273
-rw-r--r--test/util/thread_local.test.cpp73
-rw-r--r--test/util/tile_cover.test.cpp9
-rw-r--r--test/util/work_queue.test.cpp59
111 files changed, 3904 insertions, 2805 deletions
diff --git a/test/.clang-tidy b/test/.clang-tidy
new file mode 100644
index 0000000000..492d4affbd
--- /dev/null
+++ b/test/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'modernize-*,-modernize-use-equals-delete,-modernize-use-equals-default,misc-static-assert,llvm-namespace-comment,-clang-analyzer-security.insecureAPI.rand,-clang-analyzer-core.uninitialized.UndefReturn,-clang-analyzer-core.StackAddressEscape,-clang-analyzer-core.CallAndMessage,-clang-diagnostic-unused-command-line-argument,-clang-analyzer-core.uninitialized.*,-clang-analyzer-core.NullDereference,-clang-analyzer-core.NonNullParamChecker'
+HeaderFilterRegex: '\/mbgl\/'
diff --git a/test/actor/actor.test.cpp b/test/actor/actor.test.cpp
index 03f41a6e64..967dc152d9 100644
--- a/test/actor/actor.test.cpp
+++ b/test/actor/actor.test.cpp
@@ -6,6 +6,7 @@
#include <chrono>
#include <functional>
#include <future>
+#include <memory>
using namespace mbgl;
using namespace std::chrono_literals;
@@ -26,7 +27,7 @@ TEST(Actor, Construction) {
EXPECT_TRUE(constructed);
}
-TEST(Actor, DestructionClosesMailbox) {
+TEST(Actor, DestructionBlocksOnReceive) {
// Destruction blocks until the actor is not receiving.
struct Test {
@@ -67,6 +68,149 @@ TEST(Actor, DestructionClosesMailbox) {
exitingPromise.set_value();
}
+TEST(Actor, DestructionBlocksOnSend) {
+ // Destruction blocks until the actor is not being sent a message.
+
+ struct TestScheduler : public Scheduler {
+ std::promise<void> promise;
+ std::future<void> future;
+ std::atomic<bool> waited;
+
+ TestScheduler(std::promise<void> promise_, std::future<void> future_)
+ : promise(std::move(promise_)),
+ future(std::move(future_)),
+ waited(false) {
+ }
+
+ ~TestScheduler() {
+ EXPECT_TRUE(waited.load());
+ }
+
+ void schedule(std::weak_ptr<Mailbox>) final {
+ promise.set_value();
+ future.wait();
+ std::this_thread::sleep_for(1ms);
+ waited = true;
+ }
+ };
+
+ struct Test {
+ Test(ActorRef<Test>) {}
+ void message() {}
+ };
+
+ std::promise<void> enteredPromise;
+ std::future<void> enteredFuture = enteredPromise.get_future();
+
+ std::promise<void> exitingPromise;
+ std::future<void> exitingFuture = exitingPromise.get_future();
+
+ auto scheduler = std::make_unique<TestScheduler>(std::move(enteredPromise), std::move(exitingFuture));
+ auto actor = std::make_unique<Actor<Test>>(*scheduler);
+
+ std::thread thread {
+ [] (ActorRef<Test> ref) {
+ ref.invoke(&Test::message);
+ },
+ actor->self()
+ };
+
+ enteredFuture.wait();
+ exitingPromise.set_value();
+
+ actor.reset();
+ scheduler.reset();
+
+ thread.join();
+}
+
+TEST(Actor, DestructionAllowedInReceiveOnSameThread) {
+ // Destruction doesn't block if occurring on the same
+ // thread as receive(). This prevents deadlocks and
+ // allows for self-closing actors
+
+ struct Test {
+
+ Test(ActorRef<Test>){};
+
+ void callMeBack(std::function<void ()> callback) {
+ callback();
+ }
+ };
+
+ ThreadPool pool { 1 };
+
+ std::promise<void> callbackFiredPromise;
+
+ auto test = std::make_unique<Actor<Test>>(pool);
+
+ // Callback (triggered while mutex is locked in Mailbox::receive())
+ test->invoke(&Test::callMeBack, [&]() {
+ // Destroy the Actor/Mailbox in the same thread
+ test.reset();
+ callbackFiredPromise.set_value();
+ });
+
+ auto status = callbackFiredPromise.get_future().wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(std::future_status::ready, status);
+}
+
+TEST(Actor, SelfDestructionDoesntCrashWaitingReceivingThreads) {
+ // Ensures destruction doesn't cause waiting threads to
+ // crash when a actor closes it's own mailbox from a
+ // callback
+
+ struct Test {
+
+ Test(ActorRef<Test>){};
+
+ void callMeBack(std::function<void ()> callback) {
+ callback();
+ }
+ };
+
+
+ ThreadPool pool { 2 };
+
+ std::promise<void> actorClosedPromise;
+
+ auto closingActor = std::make_unique<Actor<Test>>(pool);
+ auto waitingActor = std::make_unique<Actor<Test>>(pool);
+
+ std::atomic<bool> waitingMessageProcessed {false};
+
+ // Callback (triggered while mutex is locked in Mailbox::receive())
+ closingActor->invoke(&Test::callMeBack, [&]() {
+
+ // Queue up another message from another thread
+ std::promise<void> messageQueuedPromise;
+ waitingActor->invoke(&Test::callMeBack, [&]() {
+ // This will be waiting on the mutex in
+ // Mailbox::receive(), holding a lock
+ // on the weak_ptr so the mailbox is not
+ // destroyed
+ closingActor->invoke(&Test::callMeBack, [&]() {
+ waitingMessageProcessed.store(true);
+ });
+ messageQueuedPromise.set_value();
+ });
+
+ // Wait for the message to be queued
+ ASSERT_EQ(
+ messageQueuedPromise.get_future().wait_for(std::chrono::seconds(1)),
+ std::future_status::ready
+ );
+
+ // Destroy the Actor/Mailbox in the same thread
+ closingActor.reset();
+ actorClosedPromise.set_value();
+ });
+
+ auto status = actorClosedPromise.get_future().wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(std::future_status::ready, status);
+ ASSERT_FALSE(waitingMessageProcessed.load());
+}
+
TEST(Actor, OrderedMailbox) {
// Messages are processed in order.
@@ -137,3 +281,80 @@ TEST(Actor, NonConcurrentMailbox) {
test.invoke(&Test::end);
endedFuture.wait();
}
+
+TEST(Actor, Ask) {
+ // Asking for a result
+
+ struct Test {
+
+ Test(ActorRef<Test>) {}
+
+ int doubleIt(int i) {
+ return i * 2;
+ }
+ };
+
+ ThreadPool pool { 2 };
+ Actor<Test> test(pool);
+
+ auto result = test.ask(&Test::doubleIt, 1);
+
+ ASSERT_TRUE(result.valid());
+
+ auto status = result.wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(std::future_status::ready, status);
+ ASSERT_EQ(2, result.get());
+}
+
+TEST(Actor, AskVoid) {
+ // Ask waits for void methods
+
+ struct Test {
+ bool& executed;
+
+ Test(bool& executed_) : executed(executed_) {
+ }
+
+ void doIt() {
+ executed = true;
+ }
+ };
+
+ ThreadPool pool { 1 };
+ bool executed = false;
+ Actor<Test> actor(pool, executed);
+
+ actor.ask(&Test::doIt).get();
+ EXPECT_TRUE(executed);
+}
+
+TEST(Actor, NoSelfActorRef) {
+ // Not all actors need a reference to self
+
+ // Trivially constructable
+ struct Trivial {};
+
+ ThreadPool pool { 2 };
+ Actor<Trivial> trivial(pool);
+
+
+ // With arguments
+ struct WithArguments {
+ std::promise<void> promise;
+
+ WithArguments(std::promise<void> promise_)
+ : promise(std::move(promise_)) {
+ }
+
+ void receive() {
+ promise.set_value();
+ }
+ };
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ Actor<WithArguments> withArguments(pool, std::move(promise));
+
+ withArguments.invoke(&WithArguments::receive);
+ future.wait();
+}
diff --git a/test/actor/actor_ref.test.cpp b/test/actor/actor_ref.test.cpp
index 78721c965e..20aa1c35c1 100644
--- a/test/actor/actor_ref.test.cpp
+++ b/test/actor/actor_ref.test.cpp
@@ -3,12 +3,9 @@
#include <mbgl/test/util.hpp>
-#include <chrono>
-#include <functional>
#include <future>
using namespace mbgl;
-using namespace std::chrono_literals;
TEST(ActorRef, CanOutliveActor) {
// An ActorRef can outlive its actor. Doing does not extend the actor's lifetime.
@@ -40,3 +37,80 @@ TEST(ActorRef, CanOutliveActor) {
EXPECT_TRUE(died);
test.invoke(&Test::receive);
}
+
+TEST(ActorRef, Ask) {
+ // Ask returns a Future eventually returning the result
+
+ struct Test {
+
+ Test(ActorRef<Test>) {}
+
+ int gimme() {
+ return 20;
+ }
+
+ int echo(int i) {
+ return i;
+ }
+ };
+
+ ThreadPool pool { 1 };
+ Actor<Test> actor(pool);
+ ActorRef<Test> ref = actor.self();
+
+ EXPECT_EQ(20, ref.ask(&Test::gimme).get());
+ EXPECT_EQ(30, ref.ask(&Test::echo, 30).get());
+}
+
+TEST(ActorRef, AskVoid) {
+ // Ask waits for void methods
+
+ struct Test {
+ bool& executed;
+
+ Test(bool& executed_) : executed(executed_) {
+ }
+
+ void doIt() {
+ executed = true;
+ }
+ };
+
+ ThreadPool pool { 1 };
+ bool executed = false;
+ Actor<Test> actor(pool, executed);
+ ActorRef<Test> ref = actor.self();
+
+ ref.ask(&Test::doIt).get();
+ EXPECT_TRUE(executed);
+}
+
+TEST(ActorRef, AskOnDestroyedActor) {
+ // Tests behavior when calling ask() after the
+ // Actor has gone away. Should set a exception_ptr.
+
+ struct Test {
+ bool& died;
+
+ Test(ActorRef<Test>, bool& died_) : died(died_) {}
+
+ ~Test() {
+ died = true;
+ }
+
+ int receive() {
+ return 1;
+ }
+ };
+ bool died = false;
+
+ ThreadPool pool { 1 };
+ auto actor = std::make_unique<Actor<Test>>(pool, died);
+ ActorRef<Test> ref = actor->self();
+
+ actor.reset();
+ EXPECT_TRUE(died);
+
+ auto result = ref.ask(&Test::receive);
+ EXPECT_ANY_THROW(result.get());
+}
diff --git a/test/algorithm/generate_clip_ids.test.cpp b/test/algorithm/generate_clip_ids.test.cpp
index 8ca0191b3a..1ebdccb99e 100644
--- a/test/algorithm/generate_clip_ids.test.cpp
+++ b/test/algorithm/generate_clip_ids.test.cpp
@@ -5,173 +5,150 @@
using namespace mbgl;
struct Renderable {
+ UnwrappedTileID id;
ClipID clip;
- bool used = true;
+ bool used;
+
+ Renderable(UnwrappedTileID id_,
+ ClipID clip_,
+ bool used_ = true)
+ : id(std::move(id_)),
+ clip(std::move(clip_)),
+ used(used_) {}
bool operator==(const Renderable& rhs) const {
- return clip == rhs.clip;
+ return id == rhs.id && clip == rhs.clip;
}
};
::std::ostream& operator<<(::std::ostream& os, const Renderable& rhs) {
- return os << "ClipID(" << rhs.clip << ")";
+ return os << "Renderable{ " << rhs.id << ", " << rhs.clip << " }";
}
-namespace {
-
-// void print(const std::map<UnwrappedTileID, Renderable>& renderables) {
-// std::cout << " EXPECT_EQ(decltype(renderables)({" << std::endl;
-// for (auto& pair : renderables) {
-// std::cout << " { UnwrappedTileID{ " << int(pair.first.canonical.z) << ", "
-// << (int64_t(pair.first.canonical.x) +
-// pair.first.wrap * (1ll << pair.first.canonical.z))
-// << ", " << pair.first.canonical.y << " }, Renderable{ ClipID{ \""
-// << pair.second.clip.mask << "\", \"" << pair.second.clip.reference << "\" } } },"
-// << std::endl;
-// }
-// std::cout << " })," << std::endl;
-// std::cout << " renderables);" << std::endl;
-// }
-
-// void print(const std::map<UnwrappedTileID, ClipID>& stencils) {
-// std::cout << " EXPECT_EQ(decltype(stencils)({" << std::endl;
-// for (auto& pair : stencils) {
-// std::cout << " { UnwrappedTileID{ " << int(pair.first.canonical.z) << ", "
-// << (int64_t(pair.first.canonical.x) +
-// pair.first.wrap * (1ll << pair.first.canonical.z))
-// << ", " << pair.first.canonical.y << " }, ClipID{ \"" << pair.second.mask
-// << "\", \"" << pair.second.reference << "\" } }," << std::endl;
-// }
-// std::cout << " })," << std::endl;
-// std::cout << " stencils);" << std::endl;
-// }
-
-} // end namespace
-
TEST(GenerateClipIDs, ParentAndFourChildren) {
- std::map<UnwrappedTileID, Renderable> renderables{
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables{
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
// All four covering children
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 0, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 0, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
EXPECT_EQ(decltype(renderables)({
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ ClipID{ "00000111", "00000001" } } },
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ ClipID{ "00000111", "00000010" } } },
- { UnwrappedTileID{ 1, 0, 1 }, Renderable{ ClipID{ "00000111", "00000011" } } },
- { UnwrappedTileID{ 1, 1, 0 }, Renderable{ ClipID{ "00000111", "00000100" } } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ ClipID{ "00000111", "00000101" } } },
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00000111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "00000111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 1, 0, 1 }, ClipID{ "00000111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 0 }, ClipID{ "00000111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, ClipID{ "00000111", "00000101" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
// 0/0/0 is missing because it is covered by children.
{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "00000111", "00000010" } },
{ UnwrappedTileID{ 1, 0, 1 }, ClipID{ "00000111", "00000011" } },
{ UnwrappedTileID{ 1, 1, 0 }, ClipID{ "00000111", "00000100" } },
{ UnwrappedTileID{ 1, 1, 1 }, ClipID{ "00000111", "00000101" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, ParentAndFourChildrenNegative) {
- std::map<UnwrappedTileID, Renderable> renderables{
- { UnwrappedTileID{ 1, -2, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, -2, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, -1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, -1, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 0, -1, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables{
+ Renderable{ UnwrappedTileID{ 1, -2, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, -2, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 1, -1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, -1, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 0, -1, 0 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
EXPECT_EQ(decltype(renderables)({
- { UnwrappedTileID{ 0, -1, 0 }, Renderable{ ClipID{ "00000111", "00000001" } } },
- { UnwrappedTileID{ 1, -2, 0 }, Renderable{ ClipID{ "00000111", "00000010" } } },
- { UnwrappedTileID{ 1, -2, 1 }, Renderable{ ClipID{ "00000111", "00000011" } } },
- { UnwrappedTileID{ 1, -1, 0 }, Renderable{ ClipID{ "00000111", "00000100" } } },
- { UnwrappedTileID{ 1, -1, 1 }, Renderable{ ClipID{ "00000111", "00000101" } } },
+ Renderable{ UnwrappedTileID{ 1, -2, 0 }, ClipID{ "00000111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 1, -2, 1 }, ClipID{ "00000111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 1, -1, 0 }, ClipID{ "00000111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 1, -1, 1 }, ClipID{ "00000111", "00000101" } },
+ Renderable{ UnwrappedTileID{ 0, -1, 0 }, ClipID{ "00000111", "00000001" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 1, -2, 0 }, ClipID{ "00000111", "00000010" } },
{ UnwrappedTileID{ 1, -2, 1 }, ClipID{ "00000111", "00000011" } },
{ UnwrappedTileID{ 1, -1, 0 }, ClipID{ "00000111", "00000100" } },
{ UnwrappedTileID{ 1, -1, 1 }, ClipID{ "00000111", "00000101" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, NegativeParentAndMissingLevel) {
- std::map<UnwrappedTileID, Renderable> renderables{
- { UnwrappedTileID{ 1, -1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, -1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, -2, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, -1, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, -2, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables{
+ Renderable{ UnwrappedTileID{ 1, -1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, -1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, -2, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, -1, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, -2, 0 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
EXPECT_EQ(decltype(renderables)({
- { UnwrappedTileID{ 1, -1, 0 }, Renderable{ ClipID{ "00000111", "00000001" } } },
- { UnwrappedTileID{ 2, -2, 0 }, Renderable{ ClipID{ "00000111", "00000010" } } },
- { UnwrappedTileID{ 2, -2, 1 }, Renderable{ ClipID{ "00000111", "00000011" } } },
- { UnwrappedTileID{ 2, -1, 0 }, Renderable{ ClipID{ "00000111", "00000100" } } },
- { UnwrappedTileID{ 2, -1, 1 }, Renderable{ ClipID{ "00000111", "00000101" } } },
+ Renderable{ UnwrappedTileID{ 1, -1, 0 }, ClipID{ "00000111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 2, -1, 0 }, ClipID{ "00000111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 2, -2, 1 }, ClipID{ "00000111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 2, -1, 1 }, ClipID{ "00000111", "00000101" } },
+ Renderable{ UnwrappedTileID{ 2, -2, 0 }, ClipID{ "00000111", "00000010" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 2, -2, 0 }, ClipID{ "00000111", "00000010" } },
{ UnwrappedTileID{ 2, -2, 1 }, ClipID{ "00000111", "00000011" } },
{ UnwrappedTileID{ 2, -1, 0 }, ClipID{ "00000111", "00000100" } },
{ UnwrappedTileID{ 2, -1, 1 }, ClipID{ "00000111", "00000101" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, SevenOnSameLevel) {
- std::map<UnwrappedTileID, Renderable> renderables{
+ std::vector<Renderable> renderables{
// first column
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 0, 2 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 0, 2 }, {} },
// second column
- { UnwrappedTileID{ 2, 1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 1, 2 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 1, 2 }, {} },
// third column
- { UnwrappedTileID{ 2, 2, 0 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 2, 0 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
EXPECT_EQ(decltype(renderables)({
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ ClipID{ "00000111", "00000001" } } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ ClipID{ "00000111", "00000010" } } },
- { UnwrappedTileID{ 2, 0, 2 }, Renderable{ ClipID{ "00000111", "00000011" } } },
- { UnwrappedTileID{ 2, 1, 0 }, Renderable{ ClipID{ "00000111", "00000100" } } },
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ ClipID{ "00000111", "00000101" } } },
- { UnwrappedTileID{ 2, 1, 2 }, Renderable{ ClipID{ "00000111", "00000110" } } },
- { UnwrappedTileID{ 2, 2, 0 }, Renderable{ ClipID{ "00000111", "00000111" } } },
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00000111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 2, 0, 2 }, ClipID{ "00000111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 0 }, ClipID{ "00000111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, ClipID{ "00000111", "00000101" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 2 }, ClipID{ "00000111", "00000110" } },
+ Renderable{ UnwrappedTileID{ 2, 2, 0 }, ClipID{ "00000111", "00000111" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00000111", "00000001" } },
{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000111", "00000010" } },
{ UnwrappedTileID{ 2, 0, 2 }, ClipID{ "00000111", "00000011" } },
@@ -180,51 +157,51 @@ TEST(GenerateClipIDs, SevenOnSameLevel) {
{ UnwrappedTileID{ 2, 1, 2 }, ClipID{ "00000111", "00000110" } },
{ UnwrappedTileID{ 2, 2, 0 }, ClipID{ "00000111", "00000111" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, MultipleLevels) {
- std::map<UnwrappedTileID, Renderable> renderables{
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables{
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, {} },
// begin subtiles of (2/0/0)
- { UnwrappedTileID{ 3, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 3, 0, 1 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 3, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 3, 0, 1 }, {} },
// begin subtiles of (3/0/1)
- { UnwrappedTileID{ 4, 0, 2 }, Renderable{ {} } },
- { UnwrappedTileID{ 4, 1, 2 }, Renderable{ {} } },
- { UnwrappedTileID{ 4, 0, 3 }, Renderable{ {} } },
- { UnwrappedTileID{ 4, 1, 3 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 4, 0, 2 }, {} },
+ Renderable{ UnwrappedTileID{ 4, 1, 2 }, {} },
+ Renderable{ UnwrappedTileID{ 4, 0, 3 }, {} },
+ Renderable{ UnwrappedTileID{ 4, 1, 3 }, {} },
// end subtiles of (3/0/1)
- { UnwrappedTileID{ 3, 1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 3, 1, 1 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 3, 1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 3, 1, 1 }, {} },
// end subtiles of (2/0/0)
- { UnwrappedTileID{ 2, 1, 0 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 1, 0 }, {} },
// begin subtiles of (2/1/0)
- { UnwrappedTileID{ 3, 2, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 3, 2, 1 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 3, 2, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 3, 2, 1 }, {} },
// end subtiles of (2/1/0)
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
ASSERT_EQ(decltype(renderables)({
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ ClipID{ "00001111", "00000001" } } },
- { UnwrappedTileID{ 2, 1, 0 }, Renderable{ ClipID{ "00001111", "00000010" } } },
- { UnwrappedTileID{ 3, 0, 0 }, Renderable{ ClipID{ "00001111", "00000011" } } },
- { UnwrappedTileID{ 3, 0, 1 }, Renderable{ ClipID{ "00001111", "00000100" } } },
- { UnwrappedTileID{ 3, 1, 0 }, Renderable{ ClipID{ "00001111", "00000101" } } },
- { UnwrappedTileID{ 3, 1, 1 }, Renderable{ ClipID{ "00001111", "00000110" } } },
- { UnwrappedTileID{ 3, 2, 0 }, Renderable{ ClipID{ "00001111", "00000111" } } },
- { UnwrappedTileID{ 3, 2, 1 }, Renderable{ ClipID{ "00001111", "00001000" } } },
- { UnwrappedTileID{ 4, 0, 2 }, Renderable{ ClipID{ "00001111", "00001001" } } },
- { UnwrappedTileID{ 4, 0, 3 }, Renderable{ ClipID{ "00001111", "00001010" } } },
- { UnwrappedTileID{ 4, 1, 2 }, Renderable{ ClipID{ "00001111", "00001011" } } },
- { UnwrappedTileID{ 4, 1, 3 }, Renderable{ ClipID{ "00001111", "00001100" } } },
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00001111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 3, 0, 0 }, ClipID{ "00001111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 3, 0, 1 }, ClipID{ "00001111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 4, 0, 2 }, ClipID{ "00001111", "00001001" } },
+ Renderable{ UnwrappedTileID{ 4, 1, 2 }, ClipID{ "00001111", "00001011" } },
+ Renderable{ UnwrappedTileID{ 4, 0, 3 }, ClipID{ "00001111", "00001010" } },
+ Renderable{ UnwrappedTileID{ 4, 1, 3 }, ClipID{ "00001111", "00001100" } },
+ Renderable{ UnwrappedTileID{ 3, 1, 0 }, ClipID{ "00001111", "00000101" } },
+ Renderable{ UnwrappedTileID{ 3, 1, 1 }, ClipID{ "00001111", "00000110" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 0 }, ClipID{ "00001111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 3, 2, 0 }, ClipID{ "00001111", "00000111" } },
+ Renderable{ UnwrappedTileID{ 3, 2, 1 }, ClipID{ "00001111", "00001000" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 2, 1, 0 }, ClipID{ "00001111", "00000010" } },
{ UnwrappedTileID{ 3, 0, 0 }, ClipID{ "00001111", "00000011" } },
{ UnwrappedTileID{ 3, 1, 0 }, ClipID{ "00001111", "00000101" } },
@@ -236,46 +213,46 @@ TEST(GenerateClipIDs, MultipleLevels) {
{ UnwrappedTileID{ 4, 1, 2 }, ClipID{ "00001111", "00001011" } },
{ UnwrappedTileID{ 4, 1, 3 }, ClipID{ "00001111", "00001100" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, Bug206) {
- std::map<UnwrappedTileID, Renderable> renderables{
- { UnwrappedTileID{ 10, 162, 395 }, Renderable{ {} } },
- { UnwrappedTileID{ 10, 162, 396 }, Renderable{ {} } },
- { UnwrappedTileID{ 10, 163, 395 }, Renderable{ {} } },
+ std::vector<Renderable> renderables{
+ Renderable{ UnwrappedTileID{ 10, 162, 395 }, {} },
+ Renderable{ UnwrappedTileID{ 10, 162, 396 }, {} },
+ Renderable{ UnwrappedTileID{ 10, 163, 395 }, {} },
// begin subtiles of (10/163/395)
- { UnwrappedTileID{ 11, 326, 791 }, Renderable{ {} } },
- { UnwrappedTileID{ 12, 654, 1582 }, Renderable{ {} } },
- { UnwrappedTileID{ 12, 654, 1583 }, Renderable{ {} } },
- { UnwrappedTileID{ 12, 655, 1582 }, Renderable{ {} } },
- { UnwrappedTileID{ 12, 655, 1583 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 11, 326, 791 }, {} },
+ Renderable{ UnwrappedTileID{ 12, 654, 1582 }, {} },
+ Renderable{ UnwrappedTileID{ 12, 654, 1583 }, {} },
+ Renderable{ UnwrappedTileID{ 12, 655, 1582 }, {} },
+ Renderable{ UnwrappedTileID{ 12, 655, 1583 }, {} },
// end subtiles of (10/163/395)
- { UnwrappedTileID{ 10, 163, 396 }, Renderable{ {} } },
- { UnwrappedTileID{ 10, 164, 395 }, Renderable{ {} } },
- { UnwrappedTileID{ 10, 164, 396 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 10, 163, 396 }, {} },
+ Renderable{ UnwrappedTileID{ 10, 164, 395 }, {} },
+ Renderable{ UnwrappedTileID{ 10, 164, 396 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables);
+ generator.update<Renderable>({ renderables.begin(), renderables.end() });
EXPECT_EQ(
decltype(renderables)({
- { UnwrappedTileID{ 10, 162, 395 }, Renderable{ ClipID{ "00001111", "00000001" } } },
- { UnwrappedTileID{ 10, 162, 396 }, Renderable{ ClipID{ "00001111", "00000010" } } },
- { UnwrappedTileID{ 10, 163, 395 }, Renderable{ ClipID{ "00001111", "00000011" } } },
- { UnwrappedTileID{ 10, 163, 396 }, Renderable{ ClipID{ "00001111", "00000100" } } },
- { UnwrappedTileID{ 10, 164, 395 }, Renderable{ ClipID{ "00001111", "00000101" } } },
- { UnwrappedTileID{ 10, 164, 396 }, Renderable{ ClipID{ "00001111", "00000110" } } },
- { UnwrappedTileID{ 11, 326, 791 }, Renderable{ ClipID{ "00001111", "00000111" } } },
- { UnwrappedTileID{ 12, 654, 1582 }, Renderable{ ClipID{ "00001111", "00001000" } } },
- { UnwrappedTileID{ 12, 654, 1583 }, Renderable{ ClipID{ "00001111", "00001001" } } },
- { UnwrappedTileID{ 12, 655, 1582 }, Renderable{ ClipID{ "00001111", "00001010" } } },
- { UnwrappedTileID{ 12, 655, 1583 }, Renderable{ ClipID{ "00001111", "00001011" } } },
+ Renderable{ UnwrappedTileID{ 10, 162, 395 }, ClipID{ "00001111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 10, 162, 396 }, ClipID{ "00001111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 10, 163, 395 }, ClipID{ "00001111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 11, 326, 791 }, ClipID{ "00001111", "00000111" } },
+ Renderable{ UnwrappedTileID{ 12, 654, 1582 }, ClipID{ "00001111", "00001000" } },
+ Renderable{ UnwrappedTileID{ 12, 654, 1583 }, ClipID{ "00001111", "00001001" } },
+ Renderable{ UnwrappedTileID{ 12, 655, 1582 }, ClipID{ "00001111", "00001010" } },
+ Renderable{ UnwrappedTileID{ 12, 655, 1583 }, ClipID{ "00001111", "00001011" } },
+ Renderable{ UnwrappedTileID{ 10, 163, 396 }, ClipID{ "00001111", "00000100" } },
+ Renderable{ UnwrappedTileID{ 10, 164, 395 }, ClipID{ "00001111", "00000101" } },
+ Renderable{ UnwrappedTileID{ 10, 164, 396 }, ClipID{ "00001111", "00000110" } },
}),
renderables);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 10, 162, 395 }, ClipID{ "00001111", "00000001" } },
{ UnwrappedTileID{ 10, 162, 396 }, ClipID{ "00001111", "00000010" } },
{ UnwrappedTileID{ 10, 163, 395 }, ClipID{ "00001111", "00000011" } },
@@ -288,62 +265,62 @@ TEST(GenerateClipIDs, Bug206) {
{ UnwrappedTileID{ 12, 655, 1582 }, ClipID{ "00001111", "00001010" } },
{ UnwrappedTileID{ 12, 655, 1583 }, ClipID{ "00001111", "00001011" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, MultipleSources) {
- std::map<UnwrappedTileID, Renderable> renderables1{
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ {} } },
+ std::vector<Renderable> renderables1{
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, {} },
// Differing children
- { UnwrappedTileID{ 2, 2, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 2, 2 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 2, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 2, 2 }, {} },
};
- std::map<UnwrappedTileID, Renderable> renderables2{
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ {} } },
+ std::vector<Renderable> renderables2{
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, {} },
// Differing children
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 2, 2 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 2, 2 }, {} },
};
- std::map<UnwrappedTileID, Renderable> renderables3{
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 0, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ {} } },
+ std::vector<Renderable> renderables3{
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 0, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, {} },
// Differing children
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables1);
- generator.update(renderables2);
- generator.update(renderables3);
+ generator.update<Renderable>({ renderables1.begin(), renderables1.end() });
+ generator.update<Renderable>({ renderables2.begin(), renderables2.end() });
+ generator.update<Renderable>({ renderables3.begin(), renderables3.end() });
EXPECT_EQ(decltype(renderables1)({
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ ClipID{ "00000111", "00000001" } } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ ClipID{ "00000111", "00000010" } } },
- { UnwrappedTileID{ 2, 2, 1 }, Renderable{ ClipID{ "00000111", "00000011" } } },
- { UnwrappedTileID{ 2, 2, 2 }, Renderable{ ClipID{ "00000111", "00000100" } } },
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00000111", "00000001" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, ClipID{ "00000111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 2, 2, 1 }, ClipID{ "00000111", "00000011" } },
+ Renderable{ UnwrappedTileID{ 2, 2, 2 }, ClipID{ "00000111", "00000100" } },
}),
renderables1);
EXPECT_EQ(decltype(renderables2)({
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ ClipID{ "00011000", "00001000" } } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ ClipID{ "00011111", "00000010" } } },
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ ClipID{ "00011000", "00010000" } } },
- { UnwrappedTileID{ 2, 2, 2 }, Renderable{ ClipID{ "00011111", "00000100" } } },
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00011000", "00001000" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, ClipID{ "00011111", "00000010" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, ClipID{ "00011000", "00010000" } },
+ Renderable{ UnwrappedTileID{ 2, 2, 2 }, ClipID{ "00011111", "00000100" } },
}),
renderables2);
EXPECT_EQ(decltype(renderables3)({
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ ClipID{ "11100000", "00100000" } } },
- { UnwrappedTileID{ 1, 0, 1 }, Renderable{ ClipID{ "11100000", "01000000" } } },
- { UnwrappedTileID{ 1, 1, 0 }, Renderable{ ClipID{ "11100000", "01100000" } } },
- { UnwrappedTileID{ 1, 1, 1 }, Renderable{ ClipID{ "11100000", "10000000" } } },
- { UnwrappedTileID{ 2, 1, 1 }, Renderable{ ClipID{ "11111000", "00010000" } } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "11100000", "00100000" } },
+ Renderable{ UnwrappedTileID{ 1, 0, 1 }, ClipID{ "11100000", "01000000" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 0 }, ClipID{ "11100000", "01100000" } },
+ Renderable{ UnwrappedTileID{ 1, 1, 1 }, ClipID{ "11100000", "10000000" } },
+ Renderable{ UnwrappedTileID{ 2, 1, 1 }, ClipID{ "11111000", "00010000" } },
}),
renderables3);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "11111111", "00101001" } },
{ UnwrappedTileID{ 1, 0, 1 }, ClipID{ "11111111", "01001001" } },
{ UnwrappedTileID{ 1, 1, 0 }, ClipID{ "11111111", "01101001" } },
@@ -352,77 +329,78 @@ TEST(GenerateClipIDs, MultipleSources) {
{ UnwrappedTileID{ 2, 2, 1 }, ClipID{ "11111111", "01101011" } },
{ UnwrappedTileID{ 2, 2, 2 }, ClipID{ "11111111", "10000100" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, DuplicateIDs) {
- std::map<UnwrappedTileID, Renderable> renderables1{
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ {} } },
+ std::vector<Renderable> renderables1{
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, {} },
};
- std::map<UnwrappedTileID, Renderable> renderables2{
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ {} } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ {} } },
+ std::vector<Renderable> renderables2{
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, {} },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables1);
- generator.update(renderables2);
+ generator.update<Renderable>({ renderables1.begin(), renderables1.end() });
+ generator.update<Renderable>({ renderables2.begin(), renderables2.end() });
EXPECT_EQ(decltype(renderables1)({
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ ClipID{ "00000011", "00000001" } } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ ClipID{ "00000011", "00000010" } } },
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00000011", "00000001" } },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000011", "00000010" } },
}),
renderables1);
EXPECT_EQ(decltype(renderables2)({
- { UnwrappedTileID{ 2, 0, 0 }, Renderable{ ClipID{ "00000011", "00000001" } } },
- { UnwrappedTileID{ 2, 0, 1 }, Renderable{ ClipID{ "00000011", "00000010" } } },
+ Renderable{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00000011", "00000001" } },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000011", "00000010" } },
+ Renderable{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000011", "00000010" } },
}),
renderables2);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 2, 0, 0 }, ClipID{ "00000011", "00000001" } },
{ UnwrappedTileID{ 2, 0, 1 }, ClipID{ "00000011", "00000010" } },
}),
- stencils);
+ clipIDs);
}
TEST(GenerateClipIDs, SecondSourceHasParentOfFirstSource) {
- std::map<UnwrappedTileID, Renderable> renderables1{
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables1{
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, {} },
};
- std::map<UnwrappedTileID, Renderable> renderables2{
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables2{
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
// Same as in renderables1, but has a parent that it knocks out.
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ {} } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, {} },
};
- std::map<UnwrappedTileID, Renderable> renderables3{
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ {} } },
+ std::vector<Renderable> renderables3{
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
};
algorithm::ClipIDGenerator generator;
- generator.update(renderables1);
- generator.update(renderables2);
- generator.update(renderables3);
+ generator.update<Renderable>({ renderables1.begin(), renderables1.end() });
+ generator.update<Renderable>({ renderables2.begin(), renderables2.end() });
+ generator.update<Renderable>({ renderables3.begin(), renderables3.end() });
EXPECT_EQ(decltype(renderables1)({
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ ClipID{ "00000001", "00000001" } } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "00000001", "00000001" } },
}),
renderables1);
EXPECT_EQ(decltype(renderables2)({
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ ClipID{ "00000010", "00000010" } } },
- { UnwrappedTileID{ 1, 0, 0 }, Renderable{ ClipID{ "00000011", "00000001" } } },
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00000010", "00000010" } },
+ Renderable{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "00000011", "00000001" } },
}),
renderables2);
EXPECT_EQ(decltype(renderables3)({
- { UnwrappedTileID{ 0, 0, 0 }, Renderable{ ClipID{ "00000100", "00000100" } } },
+ Renderable{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00000100", "00000100" } },
}),
renderables3);
- const auto stencils = generator.getStencils();
- EXPECT_EQ(decltype(stencils)({
+ const auto clipIDs = generator.getClipIDs();
+ EXPECT_EQ(decltype(clipIDs)({
{ UnwrappedTileID{ 0, 0, 0 }, ClipID{ "00000110", "00000110" } },
{ UnwrappedTileID{ 1, 0, 0 }, ClipID{ "00000111", "00000101" } },
}),
- stencils);
+ clipIDs);
}
diff --git a/test/algorithm/update_renderables.test.cpp b/test/algorithm/update_renderables.test.cpp
index af90d262de..2d37992579 100644
--- a/test/algorithm/update_renderables.test.cpp
+++ b/test/algorithm/update_renderables.test.cpp
@@ -23,10 +23,10 @@ struct GetTileDataAction {
};
std::ostream& operator<<(std::ostream& os, const GetTileDataAction& action) {
- return os << "GetTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ return os << "GetTileDataAction{ { " << int(action.tileID.overscaledZ) << ", " << int(action.tileID.wrap) << ", { "
<< int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
<< action.tileID.canonical.y << " } }, "
- << (action.found == Found ? "Found" : "NotFound") << " }";
+ << (action.found == Found ? "Found" : "NotFound") << " }\n";
}
struct CreateTileDataAction {
@@ -38,9 +38,9 @@ struct CreateTileDataAction {
};
std::ostream& operator<<(std::ostream& os, const CreateTileDataAction& action) {
- return os << "CreateTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ return os << "CreateTileDataAction{ { " << int(action.tileID.overscaledZ) << ", " << int(action.tileID.wrap) << ", { "
<< int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
- << action.tileID.canonical.y << " } } }";
+ << action.tileID.canonical.y << " } } }\n";
}
struct RetainTileDataAction {
@@ -53,10 +53,10 @@ struct RetainTileDataAction {
};
std::ostream& operator<<(std::ostream& os, const RetainTileDataAction& action) {
- return os << "RetainTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ return os << "RetainTileDataAction{ { " << int(action.tileID.overscaledZ) << ", " << int(action.tileID.wrap) << ", { "
<< int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
<< action.tileID.canonical.y << " } }, "
- << (action.necessity == Resource::Necessity::Required ? "Required" : "Optional") << " }";
+ << (action.necessity == Resource::Necessity::Required ? "Required" : "Optional") << " }\n";
}
struct RenderTileAction {
@@ -76,7 +76,7 @@ std::ostream& operator<<(std::ostream& os, const RenderTileAction& action) {
<< int(action.tileData.tileID.overscaledZ) << "_"
<< int(action.tileData.tileID.canonical.z) << "_"
<< action.tileData.tileID.canonical.x << "_" << action.tileData.tileID.canonical.y
- << " }";
+ << " }\n";
}
using ActionLogEntry =
@@ -100,12 +100,14 @@ auto createTileDataFn(ActionLog& log, T& dataTiles) {
};
}
+template <typename = int>
auto retainTileDataFn(ActionLog& log) {
return [&](auto& tileData, Resource::Necessity necessity) {
log.emplace_back(RetainTileDataAction{ tileData.tileID, necessity });
};
}
+template <typename = int>
auto renderTileFn(ActionLog& log) {
return [&](const auto& id, auto& tileData) {
log.emplace_back(RenderTileAction{ id, tileData });
@@ -129,8 +131,8 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // found ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // found ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
log);
@@ -140,8 +142,8 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // found ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // found ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
log);
@@ -152,39 +154,39 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, NotFound }, // missing ideal tile
- CreateTileDataAction{ { 1, { 1, 0, 1 } } }, // create ideal tile
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 2 } }, NotFound }, // four child tiles
- GetTileDataAction{ { 2, { 2, 0, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 2 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // parent tile
-
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // found ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, NotFound }, // missing ideal tile
+ CreateTileDataAction{ { 1, 0, { 1, 0, 1 } } }, // create ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 2 } }, NotFound }, // four child tiles
+ GetTileDataAction{ { 2, 0, { 2, 0, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 2 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // parent tile
+
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // found ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render found tile
}),
log);
// Mark the created tile as having the optional request tried.
log.clear();
- source.dataTiles[{ 1, { 1, 0, 1 } }]->triedOptional = true;
+ source.dataTiles[{ 1, 0, { 1, 0, 1 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // missing ideal tile
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 2 } }, NotFound }, // four child tiles
- GetTileDataAction{ { 2, { 2, 0, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 2 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // parent tile
- CreateTileDataAction{ { 0, { 0, 0, 0 } } }, // load parent tile
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
-
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // found ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // missing ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 2 } }, NotFound }, // four child tiles
+ GetTileDataAction{ { 2, 0, { 2, 0, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 2 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // parent tile
+ CreateTileDataAction{ { 0, 0, { 0, 0, 0 } } }, // load parent tile
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // found ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render found tile
}),
log);
@@ -196,12 +198,12 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // newly added tile
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // newly added tile
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render found tile
}),
log);
@@ -215,22 +217,22 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // found tile, not ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // four child tiles
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // found tile, not ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // four child tiles
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
// optional parent tile was already created before, but is not renderable
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // ideal tile
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
log);
@@ -241,16 +243,16 @@ TEST(UpdateRenderables, SingleTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // found tile, now ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // found tile, now ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, //
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // ideal tile
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, //
- GetTileDataAction{ { 1, { 1, 1, 1 } }, Found }, // ideal tile
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, Found }, // ideal tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, //
}),
log);
@@ -274,30 +276,30 @@ TEST(UpdateRenderables, UseParentTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, NotFound }, // missing ideal tile
- CreateTileDataAction{ { 1, { 1, 0, 1 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 2 } }, NotFound }, // child tile
- GetTileDataAction{ { 2, { 2, 0, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 2 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent found!
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, NotFound }, // missing ideal tile
+ CreateTileDataAction{ { 1, 0, { 1, 0, 1 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 2 } }, NotFound }, // child tile
+ GetTileDataAction{ { 2, 0, { 2, 0, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 2 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent found!
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, // render parent
- GetTileDataAction{ { 1, { 1, 1, 0 } }, NotFound }, // missing ideal tile
- CreateTileDataAction{ { 1, { 1, 1, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 1, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 2, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 2, { 2, 2, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 3, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 3, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 1, 1 } }, NotFound }, // missing tile
- CreateTileDataAction{ { 1, { 1, 1, 1 } } }, //
- RetainTileDataAction{ { 1, { 1, 1, 1 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 2, 2 } }, NotFound }, // child tile
- GetTileDataAction{ { 2, { 2, 2, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 3, 2 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 3, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 1, 0 } }, NotFound }, // missing ideal tile
+ CreateTileDataAction{ { 1, 0, { 1, 1, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 1, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 2, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 2, 0, { 2, 2, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 3, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 3, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, NotFound }, // missing tile
+ CreateTileDataAction{ { 1, 0, { 1, 1, 1 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 1, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 2, 2 } }, NotFound }, // child tile
+ GetTileDataAction{ { 2, 0, { 2, 2, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 3, 2 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 3, 3 } }, NotFound }, // ...
}),
log);
}
@@ -317,34 +319,34 @@ TEST(UpdateRenderables, DontUseWrongParentTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // missing ideal tile
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 3, { 3, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // parent tile, missing
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // parent tile, missing
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // missing ideal tile
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 3, 0, { 3, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // parent tile, missing
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // parent tile, missing
}),
log);
// Now mark the created tile as having the optional request tried.
log.clear();
- source.dataTiles[{ 2, { 2, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 2, 0, { 2, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // non-ready ideal tile
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 3, { 3, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // parent tile, missing
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, // find optional parent
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // parent tile, missing
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // non-ready ideal tile
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 3, 0, { 3, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // parent tile, missing
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, // find optional parent
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // parent tile, missing
}),
log);
@@ -354,26 +356,26 @@ TEST(UpdateRenderables, DontUseWrongParentTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // non-ready ideal tile
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // non-ready ideal tile
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
// this tile was added by the previous invocation of updateRenderables
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 3, { 3, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // parent tile not ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // missing parent tile
-
- GetTileDataAction{ { 2, { 2, 2, 0 } }, NotFound }, // missing ideal tile
- CreateTileDataAction{ { 2, { 2, 2, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 2, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 3, 4, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 3, { 3, 4, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 5, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 5, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 1, 0 } }, Found }, // found parent tile
- RetainTileDataAction{ { 1, { 1, 1, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 3, 0, { 3, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // parent tile not ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // missing parent tile
+
+ GetTileDataAction{ { 2, 0, { 2, 2, 0 } }, NotFound }, // missing ideal tile
+ CreateTileDataAction{ { 2, 0, { 2, 2, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 2, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 3, 4, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 3, 0, { 3, 4, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 5, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 5, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 1, 0 } }, Found }, // found parent tile
+ RetainTileDataAction{ { 1, 0, { 1, 1, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 1, 1, 0 }, *tile_1_1_1_0 }, // render parent tile
}),
log);
@@ -399,14 +401,14 @@ TEST(UpdateRenderables, UseParentTileWhenChildNotReady) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // found, but not ready
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 2 } }, NotFound }, // child tile
- GetTileDataAction{ { 2, { 2, 0, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 2 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 3 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile, ready
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // found, but not ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 2 } }, NotFound }, // child tile
+ GetTileDataAction{ { 2, 0, { 2, 0, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 2 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 3 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile, ready
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, // render parent tile
}),
log);
@@ -417,8 +419,8 @@ TEST(UpdateRenderables, UseParentTileWhenChildNotReady) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // found and ready
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // found and ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
}),
log);
@@ -444,19 +446,19 @@ TEST(UpdateRenderables, UseOverlappingParentTile) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ideal tile not found
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile found
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ideal tile not found
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile found
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
- GetTileDataAction{ { 1, { 1, 0, 1 } }, Found }, // ideal tile found
- RetainTileDataAction{ { 1, { 1, 0, 1 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, Found }, // ideal tile found
+ RetainTileDataAction{ { 1, 0, { 1, 0, 1 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, //
}),
log);
@@ -480,17 +482,17 @@ TEST(UpdateRenderables, UseChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 0);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ideal tile, missing
- CreateTileDataAction{ { 0, { 0, 0, 0 } } }, //
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // child tile found
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ideal tile, missing
+ CreateTileDataAction{ { 0, 0, { 0, 0, 0 } } }, //
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // child tile found
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, // render child tile
- GetTileDataAction{ { 1, { 1, 0, 1 } }, NotFound }, // child tile not found
- GetTileDataAction{ { 1, { 1, 1, 0 } }, Found }, // child tile found
- RetainTileDataAction{ { 1, { 1, 1, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 1 } }, NotFound }, // child tile not found
+ GetTileDataAction{ { 1, 0, { 1, 1, 0 } }, Found }, // child tile found
+ RetainTileDataAction{ { 1, 0, { 1, 1, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 1, 1, 0 }, *tile_1_1_1_0 }, // render child tile
- GetTileDataAction{ { 1, { 1, 1, 1 } }, NotFound }, // child tile not found
+ GetTileDataAction{ { 1, 0, { 1, 1, 1 } }, NotFound }, // child tile not found
// no parent tile of 0 to consider
}),
log);
@@ -514,17 +516,17 @@ TEST(UpdateRenderables, PreferChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ideal tile, not found
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // child tile, found
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ideal tile, not found
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // child tile, found
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, // child tile, not found
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile, found
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, // child tile, not found
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile, found
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
log);
@@ -537,19 +539,19 @@ TEST(UpdateRenderables, PreferChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // ideal tile, not ready
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // ideal tile, not ready
// ideal tile was added in previous invocation, but is not yet ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // child tile, found
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // child tile, found
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 0, 1 } }, Resource::Necessity::Optional }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 0, 1 } }, Resource::Necessity::Optional }, // ...
RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, // child tile, not found
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile, found
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, // child tile, not found
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile, found
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
log);
@@ -560,21 +562,21 @@ TEST(UpdateRenderables, PreferChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // ideal tile, not ready
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // ideal tile, not ready
// ideal tile was added in first invocation, but is not yet ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // child tile, found
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // child tile, found
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 0, 1 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 0, 1 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 1, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 1, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 1, 0 }, *tile_2_2_1_0 }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, // child tile, not found
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile, found
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, // child tile, not found
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile, found
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
log);
@@ -586,20 +588,20 @@ TEST(UpdateRenderables, PreferChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // ideal tile, not ready
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // ideal tile, not ready
// ideal tile was added in first invocation, but is not yet ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // child tile, found
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // child tile, found
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 0, 1 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 0, 1 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 1, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 1, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 1, 0 }, *tile_2_2_1_0 }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, Found }, // ...
- RetainTileDataAction{ { 2, { 2, 1, 1 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, Found }, // ...
+ RetainTileDataAction{ { 2, 0, { 2, 1, 1 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 1, 1 }, *tile_2_2_1_1 }, //
}),
log);
@@ -624,17 +626,17 @@ TEST(UpdateRenderables, UseParentAndChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ideal tile, missing
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // child tile
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ideal tile, missing
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // child tile
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
log);
@@ -645,14 +647,14 @@ TEST(UpdateRenderables, UseParentAndChildTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, // parent tile
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, // parent tile
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
log);
@@ -675,13 +677,13 @@ TEST(UpdateRenderables, DontUseTilesLowerThanMinzoom) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 1, 1 } }, NotFound }, //
// no requests for zoom 1 tiles
}),
log);
@@ -705,58 +707,58 @@ TEST(UpdateRenderables, UseOverzoomedTileAfterMaxzoom) {
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(
ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 2, 0, 0 } }, NotFound }, // overzoomed tile, not children!
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, NotFound }, // overzoomed tile, not children!
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, //
}),
log);
// Mark the created tile as having tried the optional request.
log.clear();
- source.dataTiles[{ 2, { 2, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 2, 0, { 2, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(
ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // ideal tile, missing
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 2, 0, 0 } }, NotFound }, // overzoomed tile, not children!
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, //
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // ideal tile, missing
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, NotFound }, // overzoomed tile, not children!
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, //
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, //
}),
log);
// Only add a non-overzoomed ("parent") tile at first.
log.clear();
- auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } });
+ auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, { 2, 0, 0 } });
tile_2_2_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
- CreateTileDataAction{ { 3, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 4, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, NotFound }, // ideal tile, missing
+ CreateTileDataAction{ { 3, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 4, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
log);
// Then add the overzoomed tile matching the zoom level we're rendering.
log.clear();
- auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } });
+ auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, 0, { 2, 0, 0 } });
tile_3_2_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
log);
@@ -766,26 +768,26 @@ TEST(UpdateRenderables, UseOverzoomedTileAfterMaxzoom) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
log);
// Now remove the best match.
log.clear();
- source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } });
+ source.dataTiles.erase(OverscaledTileID{ 2, 0, { 2, 0, 0 } });
tile_2_2_0_0 = nullptr;
// Use the overzoomed tile even though it doesn't match the zoom level.
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 2, 0, 0 } }, Found }, // use overzoomed tile!
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, //
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, Found }, // use overzoomed tile!
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
log);
@@ -803,69 +805,69 @@ TEST(UpdateRenderables, AscendToNonOverzoomedTiles) {
source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
// Add a matching overzoomed tile and make sure it gets selected.
- auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } });
+ auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, 0, { 2, 0, 0 } });
tile_3_2_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
log);
// Then, swap it with a non-overzoomed tile.
log.clear();
- source.dataTiles.erase(OverscaledTileID{ 3, { 2, 0, 0 } });
+ source.dataTiles.erase(OverscaledTileID{ 3, 0, { 2, 0, 0 } });
tile_3_2_0_0 = nullptr;
- auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } });
+ auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, { 2, 0, 0 } });
tile_2_2_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, NotFound }, //
- CreateTileDataAction{ { 3, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 4, { 2, 0, 0 } }, NotFound }, // prefer using a child first
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, NotFound }, //
+ CreateTileDataAction{ { 3, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 4, 0, { 2, 0, 0 } }, NotFound }, // prefer using a child first
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
log);
// Then, swap it with a parent tile.
log.clear();
- source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } });
+ source.dataTiles.erase(OverscaledTileID{ 2, 0, { 2, 0, 0 } });
tile_2_2_0_0 = nullptr;
- auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, { 1, 0, 0 } });
+ auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, { 1, 0, 0 } });
tile_1_1_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 4, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 4, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, //
}),
log);
// Now, mark the created tile as found.
log.clear();
- source.dataTiles[{ 3, { 2, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 3, 0, { 2, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 3);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 3, { 2, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 3, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 4, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 2, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 3, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 4, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, //
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, //
}),
log);
@@ -885,60 +887,60 @@ TEST(UpdateRenderables, DoNotAscendMultipleTimesIfNotFound) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 8);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 8, { 8, 0, 0 } }, NotFound }, // ideal tile
- CreateTileDataAction{ { 8, { 8, 0, 0 } } }, //
- RetainTileDataAction{ { 8, { 8, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 9, { 9, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 9, { 9, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // ascent
- GetTileDataAction{ { 6, { 6, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
-
- GetTileDataAction{ { 8, { 8, 1, 0 } }, NotFound }, // ideal tile
- CreateTileDataAction{ { 8, { 8, 1, 0 } } }, //
- RetainTileDataAction{ { 8, { 8, 1, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 9, { 9, 2, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 9, { 9, 2, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 3, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 3, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 8, 0, { 8, 0, 0 } }, NotFound }, // ideal tile
+ CreateTileDataAction{ { 8, 0, { 8, 0, 0 } } }, //
+ RetainTileDataAction{ { 8, 0, { 8, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 9, 0, { 9, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 9, 0, { 9, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // ascent
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
+
+ GetTileDataAction{ { 8, 0, { 8, 1, 0 } }, NotFound }, // ideal tile
+ CreateTileDataAction{ { 8, 0, { 8, 1, 0 } } }, //
+ RetainTileDataAction{ { 8, 0, { 8, 1, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 9, 0, { 9, 2, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 9, 0, { 9, 2, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 3, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 3, 1 } }, NotFound }, // ...
// no second ascent to 0
}),
log);
// Now add a mid-level tile that stops the ascent
log.clear();
- auto tile_4_0_0_0 = source.createTileData(OverscaledTileID{ 4, { 4, 0, 0 } });
+ auto tile_4_0_0_0 = source.createTileData(OverscaledTileID{ 4, 0, { 4, 0, 0 } });
tile_4_0_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 8);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 8, { 8, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 8, { 8, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 9, { 9, 0, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 9, { 9, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // ascent
- GetTileDataAction{ { 6, { 6, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 4, { 4, 0, 0 } }, Found }, // stops ascent
- RetainTileDataAction{ { 4, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 8, 0, { 8, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 8, 0, { 8, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 9, 0, { 9, 0, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 9, 0, { 9, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // ascent
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, Found }, // stops ascent
+ RetainTileDataAction{ { 4, 0, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 4, 0, 0 }, *tile_4_0_0_0 }, //
- GetTileDataAction{ { 8, { 8, 1, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 8, { 8, 1, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 9, { 9, 2, 0 } }, NotFound }, // child tile
- GetTileDataAction{ { 9, { 9, 2, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 3, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 9, { 9, 3, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 8, 0, { 8, 1, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 8, 0, { 8, 1, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 9, 0, { 9, 2, 0 } }, NotFound }, // child tile
+ GetTileDataAction{ { 9, 0, { 9, 2, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 3, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 9, 0, { 9, 3, 1 } }, NotFound }, // ...
// no second ascent to 0
}),
log);
@@ -960,15 +962,15 @@ TEST(UpdateRenderables, DontRetainUnusedNonIdealTiles) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 2);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 2, { 2, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 3, { 3, 1, 1 } }, NotFound }, //
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // parent tile, not ready
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 3, 0, { 3, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, Found }, // parent tile, not ready
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, //
}),
log);
}
@@ -981,56 +983,54 @@ TEST(UpdateRenderables, WrappedTiles) {
auto retainTileData = retainTileDataFn(log);
auto renderTile = renderTileFn(log);
- source.idealTiles.emplace(UnwrappedTileID{ 1, -1, 0 });
- source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
- source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 0 });
- source.idealTiles.emplace(UnwrappedTileID{ 1, 2, 0 });
+ source.idealTiles.emplace(UnwrappedTileID{ 1, -1, 0 }); // 'wrap' -> -1
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 }); // 'wrap' -> 0
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 0 }); // 'wrap' -> 0
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 2, 0 }); // 'wrap' -> 1
- auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, { 0, 0, 0 } });
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, { 0, 0, 0 } });
tile_0_0_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 1);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 1, { 1, 1, 0 } }, NotFound }, // ideal tile 1/-1/0
- CreateTileDataAction{ { 1, { 1, 1, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 1, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 2, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 2, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 3, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 3, 1 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
- RenderTileAction{ { 0, -1, 0 }, *tile_0_0_0_0 }, //
-
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ideal tile 1/0/0
- CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, -1, { 1, 1, 0 } }, NotFound }, // ideal tile 1/-1/0 (wrapped to -1)
+ CreateTileDataAction{ { 1, -1, { 1, 1, 0 } } }, //
+ RetainTileDataAction{ { 1, -1, { 1, 1, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, -1, { 2, 2, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, -1, { 2, 2, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, -1, { 2, 3, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, -1, { 2, 3, 1 } }, NotFound }, //
+ GetTileDataAction{ { 0, -1, { 0, 0, 0 } }, NotFound }, // { 0, 0, 0 } exists, but not the version wrapped to -1
+
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ideal tile 1/0/0
+ CreateTileDataAction{ { 1, 0, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, 0, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, Found }, //
+ RetainTileDataAction{ { 0, 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
- GetTileDataAction{ { 1, { 1, 1, 0 } }, Found }, // ideal tile 1/1/0
- RetainTileDataAction{ { 1, { 1, 1, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 2, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 2, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 3, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 3, 1 } }, NotFound }, //
+ GetTileDataAction{ { 1, 0, { 1, 1, 0 } }, NotFound }, // ideal tile 1/1/0, doesn't match 1/-/1/0
+ CreateTileDataAction{ { 1, 0, { 1, 1, 0 } } },
+ RetainTileDataAction{ { 1, 0, { 1, 1, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 0, { 2, 2, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 2, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 3, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 0, { 2, 3, 1 } }, NotFound }, //
// do not ascent; 0/0/0 has been rendered already for 1/0/0
- GetTileDataAction{ { 1, { 1, 0, 0 } }, Found }, // ideal tile 1/2/0
- RetainTileDataAction{ { 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 0, 1 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 0 } }, NotFound }, //
- GetTileDataAction{ { 2, { 2, 1, 1 } }, NotFound }, //
- GetTileDataAction{ { 0, { 0, 0, 0 } }, Found }, //
- RetainTileDataAction{ { 0, { 0, 0, 0 } }, Resource::Necessity::Optional }, //
- RenderTileAction{ { 0, 1, 0 }, *tile_0_0_0_0 }, //
+ GetTileDataAction{ { 1, 1, { 1, 0, 0 } }, NotFound }, // ideal tile 1/2/0 (wrapped to 1)
+ CreateTileDataAction{ { 1, 1, { 1, 0, 0 } } },
+ RetainTileDataAction{ { 1, 1, { 1, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 2, 1, { 2, 0, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 1, { 2, 0, 1 } }, NotFound }, //
+ GetTileDataAction{ { 2, 1, { 2, 1, 0 } }, NotFound }, //
+ GetTileDataAction{ { 2, 1, { 2, 1, 1 } }, NotFound }, //
+ GetTileDataAction{ { 0, 1, { 0, 0, 0 } }, NotFound }, // { 0, 0, 0 } exists, but not the version wrapped to -1
}),
log);
}
@@ -1048,19 +1048,19 @@ TEST(UpdateRenderables, RepeatedRenderWithMissingOptionals) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, NotFound }, // ideal tile, not found
- CreateTileDataAction{ { 6, { 6, 0, 0 } } }, //
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ascent
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, NotFound }, // ideal tile, not found
+ CreateTileDataAction{ { 6, 0, { 6, 0, 0 } } }, //
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ascent
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
@@ -1069,41 +1069,41 @@ TEST(UpdateRenderables, RepeatedRenderWithMissingOptionals) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ascent
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ascent
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
// Mark next level has having tried optional.
log.clear();
- source.dataTiles[{ 6, { 6, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 6, 0, { 6, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ascent
- CreateTileDataAction{ { 5, { 5, 0, 0 } } }, //
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ascent
+ CreateTileDataAction{ { 5, 0, { 5, 0, 0 } } }, //
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
@@ -1112,116 +1112,116 @@ TEST(UpdateRenderables, RepeatedRenderWithMissingOptionals) {
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, Found }, // ascent
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, Found }, // ascent
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
// Mark next level has having tried optional.
log.clear();
- source.dataTiles[{ 5, { 5, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 5, 0, { 5, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, Found }, // ascent
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- CreateTileDataAction{ { 4, { 4, 0, 0 } } }, //
- RetainTileDataAction{ { 4, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, Found }, // ascent
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ CreateTileDataAction{ { 4, 0, { 4, 0, 0 } } }, //
+ RetainTileDataAction{ { 4, 0, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
// Mark next level has having tried optional.
log.clear();
- source.dataTiles[{ 4, { 4, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 4, 0, { 4, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, Found }, // ascent
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, Found }, // ...
- RetainTileDataAction{ { 4, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- CreateTileDataAction{ { 3, { 3, 0, 0 } } }, //
- RetainTileDataAction{ { 3, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, Found }, // ascent
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 4, 0, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ CreateTileDataAction{ { 3, 0, { 3, 0, 0 } } }, //
+ RetainTileDataAction{ { 3, 0, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
// Mark next level has having tried optional.
log.clear();
- source.dataTiles[{ 3, { 3, 0, 0 } }]->triedOptional = true;
+ source.dataTiles[{ 3, 0, { 3, 0, 0 } }]->triedOptional = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, Found }, // ascent
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, Found }, // ...
- RetainTileDataAction{ { 4, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, Found }, // ...
- RetainTileDataAction{ { 3, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
- RetainTileDataAction{ { 2, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, Found }, // ascent
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 4, 0, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 3, 0, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ CreateTileDataAction{ { 2, 0, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, 0, { 2, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
// Mark as found
log.clear();
- auto tile_3_3_0_0 = source.dataTiles[{ 3, { 3, 0, 0 } }].get();
+ auto tile_3_3_0_0 = source.dataTiles[{ 3, 0, { 3, 0, 0 } }].get();
tile_3_3_0_0->renderable = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not ready
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 7, 0, 0 } }, NotFound }, // children
- GetTileDataAction{ { 7, { 7, 0, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 7, { 7, 1, 1 } }, NotFound }, // ...
- GetTileDataAction{ { 5, { 5, 0, 0 } }, Found }, // ascent
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 4, { 4, 0, 0 } }, Found }, // ...
- RetainTileDataAction{ { 4, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
- GetTileDataAction{ { 3, { 3, 0, 0 } }, Found }, // ...
- RetainTileDataAction{ { 3, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not ready
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 7, 0, 0 } }, NotFound }, // children
+ GetTileDataAction{ { 7, 0, { 7, 0, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 7, 0, { 7, 1, 1 } }, NotFound }, // ...
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, Found }, // ascent
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 4, 0, { 4, 0, 0 } }, Resource::Necessity::Optional }, //
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, Found }, // ...
+ RetainTileDataAction{ { 3, 0, { 3, 0, 0 } }, Resource::Necessity::Optional }, //
RenderTileAction{ { 3, 0, 0 }, *tile_3_3_0_0 }, //
}),
log);
@@ -1238,24 +1238,24 @@ TEST(UpdateRenderables, LoadRequiredIfIdealTileCantBeFound) {
source.zoomRange.max = 6;
source.idealTiles.emplace(UnwrappedTileID{ 6, 0, 0 });
- auto tile_6_6_0_0 = source.createTileData(OverscaledTileID{ 6, { 6, 0, 0 } });
+ auto tile_6_6_0_0 = source.createTileData(OverscaledTileID{ 6, 0, { 6, 0, 0 } });
tile_6_6_0_0->triedOptional = true;
tile_6_6_0_0->loaded = true;
algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
source.idealTiles, source.zoomRange, 6);
EXPECT_EQ(ActionLog({
- GetTileDataAction{ { 6, { 6, 0, 0 } }, Found }, // ideal tile, not found
- RetainTileDataAction{ { 6, { 6, 0, 0 } }, Resource::Necessity::Required }, //
- GetTileDataAction{ { 7, { 6, 0, 0 } }, NotFound }, // overzoomed child
- GetTileDataAction{ { 5, { 5, 0, 0 } }, NotFound }, // ascent
- CreateTileDataAction{ { 5, { 5, 0, 0 } } },
- RetainTileDataAction{ { 5, { 5, 0, 0 } }, Resource::Necessity::Required },
- GetTileDataAction{ { 4, { 4, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 3, { 3, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 2, { 2, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 1, { 1, 0, 0 } }, NotFound }, // ...
- GetTileDataAction{ { 0, { 0, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 6, 0, { 6, 0, 0 } }, Found }, // ideal tile, not found
+ RetainTileDataAction{ { 6, 0, { 6, 0, 0 } }, Resource::Necessity::Required }, //
+ GetTileDataAction{ { 7, 0, { 6, 0, 0 } }, NotFound }, // overzoomed child
+ GetTileDataAction{ { 5, 0, { 5, 0, 0 } }, NotFound }, // ascent
+ CreateTileDataAction{ { 5, 0, { 5, 0, 0 } } },
+ RetainTileDataAction{ { 5, 0, { 5, 0, 0 } }, Resource::Necessity::Required },
+ GetTileDataAction{ { 4, 0, { 4, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 3, 0, { 3, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 2, 0, { 2, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 1, 0, { 1, 0, 0 } }, NotFound }, // ...
+ GetTileDataAction{ { 0, 0, { 0, 0, 0 } }, NotFound }, // ...
}),
log);
}
diff --git a/test/algorithm/update_tile_masks.test.cpp b/test/algorithm/update_tile_masks.test.cpp
new file mode 100644
index 0000000000..3c698eb0cd
--- /dev/null
+++ b/test/algorithm/update_tile_masks.test.cpp
@@ -0,0 +1,132 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/algorithm/update_tile_masks.hpp>
+
+using namespace mbgl;
+
+namespace {
+
+class MaskedRenderable {
+public:
+ MaskedRenderable(const UnwrappedTileID& id_, TileMask&& mask_)
+ : id(id_), mask(std::move(mask_)) {
+ }
+
+ UnwrappedTileID id;
+ TileMask mask;
+ bool used = true;
+
+ void setMask(TileMask&& mask_) {
+ mask = std::move(mask_);
+ }
+};
+
+bool operator==(const MaskedRenderable& lhs, const MaskedRenderable& rhs) {
+ return lhs.id == rhs.id && lhs.mask == rhs.mask;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const MaskedRenderable& rhs) {
+ os << "MaskedRenderable{ " << rhs.id << ", { ";
+ bool first = true;
+ for (auto& id : rhs.mask) {
+ if (!first) {
+ os << ", ";
+ } else {
+ first = false;
+ }
+ os << id;
+ }
+ return os << " } }";
+}
+
+} // namespace
+
+void validate(const std::vector<MaskedRenderable> expected) {
+ std::vector<MaskedRenderable> actual = expected;
+ std::for_each(actual.begin(), actual.end(),
+ [](auto& renderable) { renderable.mask.clear(); });
+ algorithm::updateTileMasks<MaskedRenderable>({ actual.begin(), actual.end() });
+ EXPECT_EQ(expected, actual);
+}
+
+TEST(UpdateTileMasks, NoChildren) {
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 0, 0, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 4, 3, 8 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 1, 0, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 1, 1, 1 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 1, 0, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 2, 2, 3 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+}
+
+TEST(UpdateTileMasks, ParentAndFourChildren) {
+ validate({
+ // Mask is empty (== not rendered!) because we have four covering children.
+ MaskedRenderable{ UnwrappedTileID{ 0, 0, 0 }, {} },
+ // All four covering children
+ MaskedRenderable{ UnwrappedTileID{ 1, 0, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 1, 0, 1 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 1, 1, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 1, 1, 1 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+}
+
+TEST(UpdateTileMasks, OneChild) {
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 0, 0, 0 },
+ // Only render the three children that aren't covering the other tile.
+ { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 },
+ CanonicalTileID{ 1, 1, 1 } } },
+ MaskedRenderable{ UnwrappedTileID{ 1, 0, 0 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+}
+
+TEST(UpdateTileMasks, Complex) {
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 0, 0, 0 },
+ { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 },
+ CanonicalTileID{ 2, 2, 3 }, CanonicalTileID{ 2, 3, 2 },
+ CanonicalTileID{ 3, 6, 7 }, CanonicalTileID{ 3, 7, 6 } } },
+ MaskedRenderable{ UnwrappedTileID{ 0, { 1, 0, 0 } }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 0, { 2, 2, 2 } }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 0, { 3, 7, 7 } }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 0, { 3, 6, 6 } }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 0, 0, 0 },
+ { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 },
+ CanonicalTileID{ 1, 1, 1 }, CanonicalTileID{ 2, 0, 0 },
+ CanonicalTileID{ 2, 0, 1 }, CanonicalTileID{ 2, 1, 0 },
+ CanonicalTileID{ 3, 2, 3 }, CanonicalTileID{ 3, 3, 2 },
+ CanonicalTileID{ 3, 3, 3 }, CanonicalTileID{ 4, 4, 5 },
+ CanonicalTileID{ 4, 5, 4 }, CanonicalTileID{ 4, 5, 5 } } },
+ MaskedRenderable{ UnwrappedTileID{ 4, 4, 4 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+
+ validate({
+ MaskedRenderable{ UnwrappedTileID{ 12, 1028, 1456 },
+ { CanonicalTileID{ 1, 1, 1 }, CanonicalTileID{ 2, 3, 0 },
+ CanonicalTileID{ 2, 3, 1 } } },
+ MaskedRenderable{ UnwrappedTileID{ 13, 2056, 2912 },
+ { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 },
+ CanonicalTileID{ 1, 1, 1 } } },
+ MaskedRenderable{ UnwrappedTileID{ 13, 2056, 2913 },
+ { CanonicalTileID{ 1, 0, 0 }, CanonicalTileID{ 1, 1, 0 },
+ CanonicalTileID{ 1, 1, 1 } } },
+ MaskedRenderable{ UnwrappedTileID{ 14, 4112, 5824 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 14, 4112, 5827 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 14, 4114, 5824 }, { CanonicalTileID{ 0, 0, 0 } } },
+ MaskedRenderable{ UnwrappedTileID{ 14, 4114, 5825 }, { CanonicalTileID{ 0, 0, 0 } } },
+ });
+}
diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp
index 97ccaae684..9e622f780a 100644
--- a/test/api/annotations.test.cpp
+++ b/test/api/annotations.test.cpp
@@ -3,37 +3,40 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
using namespace mbgl;
namespace {
+PremultipliedImage namedImage(const std::string& name) {
+ return decodeImage(util::read_file("test/fixtures/sprites/" + name + ".png"));
+}
+
std::unique_ptr<style::Image> namedMarker(const std::string& name) {
- PremultipliedImage image = decodeImage(util::read_file("test/fixtures/sprites/" + name));
- return std::make_unique<style::Image>(std::move(image), 1.0);
+ return std::make_unique<style::Image>(name, namedImage(name), 1.0);
}
class AnnotationTest {
public:
util::RunLoop loop;
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext() };
StubFileSource fileSource;
ThreadPool threadPool { 4 };
- Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
+ float pixelRatio { 1 };
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
+ Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
+ threadPool, MapMode::Still };
void checkRendering(const char * name) {
test::checkImage(std::string("test/fixtures/annotations/") + name,
- test::render(map, view), 0.0002, 0.1);
+ frontend.render(map), 0.0002, 0.1);
}
};
@@ -42,12 +45,12 @@ public:
TEST(Annotations, SymbolAnnotation) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.addAnnotation(SymbolAnnotation { Point<double>(0, 0), "default_marker" });
test.checkRendering("point_annotation");
-// auto size = test.view.getSize();
+// auto size = test.frontend.getSize();
// auto screenBox = ScreenBox { {}, { double(size.width), double(size.height) } };
// for (uint8_t zoom = test.map.getMinZoom(); zoom <= test.map.getMaxZoom(); ++zoom) {
// test.map.setZoom(zoom);
@@ -64,7 +67,7 @@ TEST(Annotations, LineAnnotation) {
annotation.color = Color::red();
annotation.width = { 5 };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.addAnnotation(annotation);
test.checkRendering("line_annotation");
@@ -79,7 +82,7 @@ TEST(Annotations, FillAnnotation) {
FillAnnotation annotation { polygon };
annotation.color = Color::red();
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.addAnnotation(annotation);
test.checkRendering("fill_annotation");
@@ -92,7 +95,7 @@ TEST(Annotations, AntimeridianAnnotationSmall) {
double antimeridian = 180;
test.map.setLatLngZoom(mbgl::LatLng(0, antimeridian), 0);
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
LineString<double> line = {{ { antimeridian, 20 }, { antimeridian, -20 } }};
LineAnnotation lineAnnotation { line };
@@ -113,7 +116,7 @@ TEST(Annotations, AntimeridianAnnotationLarge) {
double antimeridian = 180;
test.map.setLatLngZoom(mbgl::LatLng(0, antimeridian), 0);
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
LineString<double> line = {{ { antimeridian, 20 }, { antimeridian, -20 } }};
LineAnnotation lineAnnotation { line };
@@ -138,30 +141,20 @@ TEST(Annotations, OverlappingFillAnnotation) {
FillAnnotation overlaidAnnotation { polygon };
overlaidAnnotation.color = Color::red();
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.addAnnotation(underlaidAnnotation);
test.map.addAnnotation(overlaidAnnotation);
test.checkRendering("overlapping_fill_annotation");
}
-TEST(Annotations, StyleSourcedShapeAnnotation) {
- AnnotationTest test;
-
- Polygon<double> polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} };
-
- test.map.setStyleJSON(util::read_file("test/fixtures/api/annotation.json"));
- test.map.addAnnotation(StyleSourcedAnnotation { polygon, "annotation" });
- test.checkRendering("style_sourced_shape_annotation");
-}
-
TEST(Annotations, AddMultiple) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.addAnnotation(SymbolAnnotation { Point<double> { -10, 0 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
test.map.addAnnotation(SymbolAnnotation { Point<double> { 10, 0 }, "default_marker" });
test.checkRendering("add_multiple");
@@ -170,8 +163,8 @@ TEST(Annotations, AddMultiple) {
TEST(Annotations, NonImmediateAdd) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test::render(test.map, test.view);
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.frontend.render(test.map);
Polygon<double> polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} };
FillAnnotation annotation { polygon };
@@ -184,12 +177,12 @@ TEST(Annotations, NonImmediateAdd) {
TEST(Annotations, UpdateSymbolAnnotationGeometry) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
- test.map.addAnnotationImage("flipped_marker", namedMarker("flipped_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
+ test.map.addAnnotationImage(namedMarker("flipped_marker"));
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
test.map.updateAnnotation(point, SymbolAnnotation { Point<double> { -10, 0 }, "default_marker" });
test.checkRendering("update_point");
@@ -198,12 +191,12 @@ TEST(Annotations, UpdateSymbolAnnotationGeometry) {
TEST(Annotations, UpdateSymbolAnnotationIcon) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
- test.map.addAnnotationImage("flipped_marker", namedMarker("flipped_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
+ test.map.addAnnotationImage(namedMarker("flipped_marker"));
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
test.map.updateAnnotation(point, SymbolAnnotation { Point<double> { 0, 0 }, "flipped_marker" });
test.checkRendering("update_icon");
@@ -216,10 +209,10 @@ TEST(Annotations, UpdateLineAnnotationGeometry) {
annotation.color = Color::red();
annotation.width = { 5 };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
AnnotationID line = test.map.addAnnotation(annotation);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
annotation.geometry = LineString<double> {{ { 0, 0 }, { -45, -45 } }};
test.map.updateAnnotation(line, annotation);
@@ -233,10 +226,10 @@ TEST(Annotations, UpdateLineAnnotationStyle) {
annotation.color = Color::red();
annotation.width = { 5 };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
AnnotationID line = test.map.addAnnotation(annotation);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
annotation.color = Color::green();
annotation.width = { 2 };
@@ -250,10 +243,10 @@ TEST(Annotations, UpdateFillAnnotationGeometry) {
FillAnnotation annotation { Polygon<double> { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} } };
annotation.color = Color::red();
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
AnnotationID fill = test.map.addAnnotation(annotation);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
annotation.geometry = Polygon<double> { {{ { 0, 0 }, { 0, 45 }, { 45, 0 } }} };
test.map.updateAnnotation(fill, annotation);
@@ -267,10 +260,10 @@ TEST(Annotations, UpdateFillAnnotationStyle) {
FillAnnotation annotation { polygon };
annotation.color = Color::red();
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
AnnotationID fill = test.map.addAnnotation(annotation);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
annotation.color = Color::green();
test.map.updateAnnotation(fill, annotation);
@@ -280,11 +273,11 @@ TEST(Annotations, UpdateFillAnnotationStyle) {
TEST(Annotations, RemovePoint) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
test.map.removeAnnotation(point);
test.checkRendering("remove_point");
@@ -298,10 +291,10 @@ TEST(Annotations, RemoveShape) {
annotation.color = Color::red();
annotation.width = { 5 };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
AnnotationID shape = test.map.addAnnotation(annotation);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
test.map.removeAnnotation(shape);
test.checkRendering("remove_shape");
@@ -311,40 +304,53 @@ TEST(Annotations, ImmediateRemoveShape) {
AnnotationTest test;
test.map.removeAnnotation(test.map.addAnnotation(LineAnnotation { LineString<double>() }));
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
}
TEST(Annotations, SwitchStyle) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.checkRendering("switch_style");
}
+TEST(Annotations, ReaddImage) {
+ AnnotationTest test;
+
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
+ test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
+
+ test.frontend.render(test.map);
+
+ test.map.addAnnotationImage(std::make_unique<style::Image>("default_marker", namedImage("flipped_marker"), 1.0));
+ test.checkRendering("readd_image");
+}
+
TEST(Annotations, QueryRenderedFeatures) {
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 50 }, "default_marker" });
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
- auto features = test.map.queryRenderedFeatures(test.map.pixelForLatLng({ 0, 0 }));
+ auto features = test.frontend.getRenderer()->queryRenderedFeatures(test.map.pixelForLatLng({ 0, 0 }));
EXPECT_EQ(features.size(), 1u);
EXPECT_TRUE(!!features[0].id);
EXPECT_EQ(*features[0].id, uint64_t(0));
- auto features2 = test.map.queryRenderedFeatures(test.map.pixelForLatLng({ 50, 0 }));
+ auto features2 = test.frontend.getRenderer()->queryRenderedFeatures(test.map.pixelForLatLng({ 50, 0 }));
EXPECT_EQ(features2.size(), 1u);
EXPECT_TRUE(!!features2[0].id);
EXPECT_EQ(*features2[0].id, uint64_t(1));
@@ -353,11 +359,11 @@ TEST(Annotations, QueryRenderedFeatures) {
TEST(Annotations, QueryFractionalZoomLevels) {
AnnotationTest test;
- auto viewSize = test.view.getSize();
+ auto viewSize = test.frontend.getSize();
auto box = ScreenBox { {}, { double(viewSize.width), double(viewSize.height) } };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
std::vector<mbgl::AnnotationID> ids;
for (int longitude = 0; longitude < 10; ++longitude) {
@@ -369,8 +375,8 @@ TEST(Annotations, QueryFractionalZoomLevels) {
test.map.setLatLngZoom({ 5, 5 }, 0);
for (uint16_t zoomSteps = 10; zoomSteps <= 20; ++zoomSteps) {
test.map.setZoom(zoomSteps / 10.0);
- test::render(test.map, test.view);
- auto features = test.map.queryRenderedFeatures(box);
+ test.frontend.render(test.map);
+ auto features = test.frontend.getRenderer()->queryRenderedFeatures(box);
// Filter out repeated features.
// See 'edge-cases/null-island' query-test for reference.
@@ -385,11 +391,11 @@ TEST(Annotations, QueryFractionalZoomLevels) {
TEST(Annotations, VisibleFeatures) {
AnnotationTest test;
- auto viewSize = test.view.getSize();
+ auto viewSize = test.frontend.getSize();
auto box = ScreenBox { {}, { double(viewSize.width), double(viewSize.height) } };
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.setLatLngZoom({ 5, 5 }, 3);
std::vector<mbgl::AnnotationID> ids;
@@ -401,9 +407,9 @@ TEST(Annotations, VisibleFeatures) {
// Change bearing *after* adding annotations causes them to be reordered.
test.map.setBearing(45);
- test::render(test.map, test.view);
+ test.frontend.render(test.map);
- auto features = test.map.queryRenderedFeatures(box, {});
+ auto features = test.frontend.getRenderer()->queryRenderedFeatures(box, {});
auto sortID = [](const Feature& lhs, const Feature& rhs) { return lhs.id < rhs.id; };
auto sameID = [](const Feature& lhs, const Feature& rhs) { return lhs.id == rhs.id; };
std::sort(features.begin(), features.end(), sortID);
@@ -412,13 +418,19 @@ TEST(Annotations, VisibleFeatures) {
test.map.setBearing(0);
test.map.setZoom(4);
- test::render(test.map, test.view);
- features = test.map.queryRenderedFeatures(box);
+ test.frontend.render(test.map);
+ features = test.frontend.getRenderer()->queryRenderedFeatures(box);
std::sort(features.begin(), features.end(), sortID);
features.erase(std::unique(features.begin(), features.end(), sameID), features.end());
EXPECT_EQ(features.size(), ids.size());
}
+TEST(Annotations, TopOffsetPixels) {
+ AnnotationTest test;
+
+ test.map.addAnnotationImage(namedMarker("default_marker"));
+ EXPECT_EQ(test.map.getTopOffsetPixelsForAnnotationImage("default_marker"), -28);
+}
TEST(Annotations, DebugEmpty) {
// This test should render nothing, not even the tile borders. Tile borders are only rendered
@@ -426,7 +438,7 @@ TEST(Annotations, DebugEmpty) {
// should not render them.
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.setDebug(MapDebugOptions::TileBorders);
test.map.setZoom(1);
@@ -439,10 +451,10 @@ TEST(Annotations, DebugSparse) {
// tiles because they're all empty.
AnnotationTest test;
- test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.setDebug(MapDebugOptions::TileBorders);
test.map.setZoom(1);
- test.map.addAnnotationImage("default_marker", namedMarker("default_marker.png"));
+ test.map.addAnnotationImage(namedMarker("default_marker"));
test.map.addAnnotation(SymbolAnnotation { Point<double>(10, 10), "default_marker" });
test.checkRendering("debug_sparse");
diff --git a/test/api/api_misuse.test.cpp b/test/api/api_misuse.test.cpp
index af703fddfb..690c1548e5 100644
--- a/test/api/api_misuse.test.cpp
+++ b/test/api/api_misuse.test.cpp
@@ -3,9 +3,8 @@
#include <mbgl/test/fixture_log_observer.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
#include <mbgl/storage/online_file_source.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/exception.hpp>
@@ -22,15 +21,14 @@ TEST(API, RenderWithoutCallback) {
util::RunLoop loop;
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext(), { 128, 512 } };
StubFileSource fileSource;
ThreadPool threadPool(4);
+ float pixelRatio { 1 };
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
- std::unique_ptr<Map> map =
- std::make_unique<Map>(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
- map->renderStill(view, nullptr);
+ auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
+ pixelRatio, fileSource, threadPool, MapMode::Still);
+ map->renderStill(nullptr);
// Force Map thread to join.
map.reset();
@@ -44,31 +42,3 @@ TEST(API, RenderWithoutCallback) {
EXPECT_EQ(log->count(logMessage), 1u);
}
-
-TEST(API, RenderWithoutStyle) {
- util::RunLoop loop;
-
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext(), { 128, 512 } };
- StubFileSource fileSource;
- ThreadPool threadPool(4);
-
- Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
-
- std::exception_ptr error;
- map.renderStill(view, [&](std::exception_ptr error_) {
- error = error_;
- loop.stop();
- });
-
- loop.run();
-
- try {
- std::rethrow_exception(error);
- } catch (const util::MisuseException& ex) {
- EXPECT_EQ(std::string(ex.what()), "Map doesn't have a style");
- } catch (const std::exception&) {
- EXPECT_TRUE(false) << "Unhandled exception.";
- }
-}
diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp
index 5a30220cd7..1c514aeca2 100644
--- a/test/api/custom_layer.test.cpp
+++ b/test/api/custom_layer.test.cpp
@@ -2,11 +2,10 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/util/io.hpp>
@@ -86,16 +85,15 @@ public:
TEST(CustomLayer, Basic) {
util::RunLoop loop;
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext() };
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
ThreadPool threadPool(4);
-
- Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+ float pixelRatio { 1 };
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
+ Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
+ threadPool, MapMode::Still);
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
map.setLatLngZoom({ 37.8, -122.5 }, 10);
- map.addLayer(std::make_unique<CustomLayer>(
+ map.getStyle().addLayer(std::make_unique<CustomLayer>(
"custom",
[] (void* context) {
reinterpret_cast<TestLayer*>(context)->initialize();
@@ -110,7 +108,7 @@ TEST(CustomLayer, Basic) {
auto layer = std::make_unique<FillLayer>("landcover", "mapbox");
layer->setSourceLayer("landcover");
layer->setFillColor(Color{ 1.0, 1.0, 0.0, 1.0 });
- map.addLayer(std::move(layer));
+ map.getStyle().addLayer(std::move(layer));
- test::checkImage("test/fixtures/custom_layer/basic", test::render(map, view), 0.0006, 0.1);
+ test::checkImage("test/fixtures/custom_layer/basic", frontend.render(map), 0.0006, 0.1);
}
diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp
index c509753d2d..3f3825eb72 100644
--- a/test/api/query.test.cpp
+++ b/test/api/query.test.cpp
@@ -1,15 +1,15 @@
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/test/stub_file_source.hpp>
#include <mbgl/test/util.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/source.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
using namespace mbgl;
using namespace mbgl::style;
@@ -19,20 +19,20 @@ namespace {
class QueryTest {
public:
QueryTest() {
- map.setStyleJSON(util::read_file("test/fixtures/api/query_style.json"));
- map.addImage("test-icon", std::make_unique<style::Image>(
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/query_style.json"));
+ map.getStyle().addImage(std::make_unique<style::Image>("test-icon",
decodeImage(util::read_file("test/fixtures/sprites/default_marker.png")), 1.0));
- test::render(map, view);
+ frontend.render(map);
}
util::RunLoop loop;
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext() };
StubFileSource fileSource;
ThreadPool threadPool { 4 };
- Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
+ float pixelRatio { 1 };
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
+ Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
+ threadPool, MapMode::Still };
};
} // end namespace
@@ -40,10 +40,10 @@ public:
TEST(Query, QueryRenderedFeatures) {
QueryTest test;
- auto features1 = test.map.queryRenderedFeatures(test.map.pixelForLatLng({ 0, 0 }));
+ auto features1 = test.frontend.getRenderer()->queryRenderedFeatures(test.map.pixelForLatLng({ 0, 0 }));
EXPECT_EQ(features1.size(), 4u);
- auto features2 = test.map.queryRenderedFeatures(test.map.pixelForLatLng({ 9, 9 }));
+ auto features2 = test.frontend.getRenderer()->queryRenderedFeatures(test.map.pixelForLatLng({ 9, 9 }));
EXPECT_EQ(features2.size(), 0u);
}
@@ -52,16 +52,16 @@ TEST(Query, QueryRenderedFeaturesFilterLayer) {
auto zz = test.map.pixelForLatLng({ 0, 0 });
- auto features1 = test.map.queryRenderedFeatures(zz, {{{ "layer1"}}, {}});
+ auto features1 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "layer1"}}, {}});
EXPECT_EQ(features1.size(), 1u);
- auto features2 = test.map.queryRenderedFeatures(zz, {{{ "layer1", "layer2" }}, {}});
+ auto features2 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "layer1", "layer2" }}, {}});
EXPECT_EQ(features2.size(), 2u);
- auto features3 = test.map.queryRenderedFeatures(zz, {{{ "foobar" }}, {}});
+ auto features3 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "foobar" }}, {}});
EXPECT_EQ(features3.size(), 0u);
- auto features4 = test.map.queryRenderedFeatures(zz, {{{ "foobar", "layer3" }}, {}});
+ auto features4 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "foobar", "layer3" }}, {}});
EXPECT_EQ(features4.size(), 1u);
}
@@ -71,22 +71,22 @@ TEST(Query, QueryRenderedFeaturesFilter) {
auto zz = test.map.pixelForLatLng({ 0, 0 });
const EqualsFilter eqFilter = { "key1", std::string("value1") };
- auto features1 = test.map.queryRenderedFeatures(zz, {{}, { eqFilter }});
+ auto features1 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{}, { eqFilter }});
EXPECT_EQ(features1.size(), 1u);
const IdentifierNotEqualsFilter idNotEqFilter = { std::string("feature1") };
- auto features2 = test.map.queryRenderedFeatures(zz, {{{ "layer4" }}, { idNotEqFilter }});
+ auto features2 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "layer4" }}, { idNotEqFilter }});
EXPECT_EQ(features2.size(), 0u);
const GreaterThanFilter gtFilter = { "key2", 1.0 };
- auto features3 = test.map.queryRenderedFeatures(zz, {{ }, { gtFilter }});
+ auto features3 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{ }, { gtFilter }});
EXPECT_EQ(features3.size(), 1u);
}
TEST(Query, QuerySourceFeatures) {
QueryTest test;
- auto features1 = test.map.querySourceFeatures("source3");
+ auto features1 = test.frontend.getRenderer()->querySourceFeatures("source3");
EXPECT_EQ(features1.size(), 1u);
}
@@ -94,15 +94,15 @@ TEST(Query, QuerySourceFeaturesOptionValidation) {
QueryTest test;
// GeoJSONSource, doesn't require a layer id
- auto features = test.map.querySourceFeatures("source3");
+ auto features = test.frontend.getRenderer()->querySourceFeatures("source3");
ASSERT_EQ(features.size(), 1u);
// VectorSource, requires a layer id
- features = test.map.querySourceFeatures("source5");
+ features = test.frontend.getRenderer()->querySourceFeatures("source5");
ASSERT_EQ(features.size(), 0u);
// RasterSource, not supported
- features = test.map.querySourceFeatures("source6");
+ features = test.frontend.getRenderer()->querySourceFeatures("source6");
ASSERT_EQ(features.size(), 0u);
}
@@ -110,15 +110,15 @@ TEST(Query, QuerySourceFeaturesFilter) {
QueryTest test;
const EqualsFilter eqFilter = { "key1", std::string("value1") };
- auto features1 = test.map.querySourceFeatures("source4", {{}, { eqFilter }});
+ auto features1 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { eqFilter }});
EXPECT_EQ(features1.size(), 1u);
const IdentifierNotEqualsFilter idNotEqFilter = { std::string("feature1") };
- auto features2 = test.map.querySourceFeatures("source4", {{}, { idNotEqFilter }});
+ auto features2 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { idNotEqFilter }});
EXPECT_EQ(features2.size(), 0u);
const GreaterThanFilter gtFilter = { "key2", 1.0 };
- auto features3 = test.map.querySourceFeatures("source4", {{}, { gtFilter }});
+ auto features3 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { gtFilter }});
EXPECT_EQ(features3.size(), 1u);
}
diff --git a/test/api/recycle_map.cpp b/test/api/recycle_map.cpp
new file mode 100644
index 0000000000..8cd622fe79
--- /dev/null
+++ b/test/api/recycle_map.cpp
@@ -0,0 +1,58 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_file_source.hpp>
+
+#include <mbgl/gl/headless_frontend.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/storage/online_file_source.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+
+TEST(API, RecycleMapUpdateImages) {
+ util::RunLoop loop;
+
+ StubFileSource fileSource;
+ ThreadPool threadPool(4);
+ float pixelRatio { 1 };
+
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
+ auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
+ pixelRatio, fileSource, threadPool, MapMode::Still);
+
+ EXPECT_TRUE(map);
+
+ auto loadStyle = [&](auto markerName, auto markerPath) {
+ auto source = std::make_unique<GeoJSONSource>("geometry");
+ source->setGeoJSON({ Point<double> { 0, 0 } });
+
+ auto layer = std::make_unique<SymbolLayer>("geometry", "geometry");
+ layer->setIconImage({ markerName });
+
+ map->getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ map->getStyle().addSource(std::move(source));
+ map->getStyle().addLayer(std::move(layer));
+ map->getStyle().addImage(std::make_unique<style::Image>(markerName, decodeImage(util::read_file(markerPath)), 1.0));
+ };
+
+ // default marker
+
+ loadStyle("default_marker", "test/fixtures/sprites/default_marker.png");
+ test::checkImage("test/fixtures/recycle_map/default_marker", frontend.render(*map), 0.0006, 0.1);
+
+ // flipped marker
+
+ loadStyle("flipped_marker", "test/fixtures/sprites/flipped_marker.png");
+ test::checkImage("test/fixtures/recycle_map/flipped_marker", frontend.render(*map), 0.0006, 0.1);
+}
diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp
deleted file mode 100644
index 6e99501708..0000000000
--- a/test/api/render_missing.test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-#include <mbgl/test/util.hpp>
-#include <mbgl/test/fixture_log_observer.hpp>
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
-#include <mbgl/util/default_thread_pool.hpp>
-#include <mbgl/storage/default_file_source.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <future>
-
-#if TEST_HAS_SERVER
-#define TEST_REQUIRES_SERVER(name) name
-#else
-#define TEST_REQUIRES_SERVER(name) DISABLED_ ## name
-#endif
-
-TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
- using namespace mbgl;
-
- util::RunLoop loop;
-
- const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json");
-
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext(), { 256, 512 } };
- DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
- ThreadPool threadPool(4);
-
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
-
- std::string message;
-
- // This host does not respond (== connection error).
- // Are you seeing this test fail? Make sure you don't have a server running on port 3001!
- map.setStyleJSON(style);
- map.renderStill(view, [&](std::exception_ptr err) {
- ASSERT_TRUE(err.operator bool());
- try {
- std::rethrow_exception(err);
- } catch (const std::exception& ex) {
- message = ex.what();
- EXPECT_TRUE(message.find("onnect") != std::string::npos); // [C|c]onnect
- }
- loop.stop();
- });
-
- loop.run();
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(1u, flo->count(FixtureLog::Message(
- EventSeverity::Error, Event::Style, -1,
- std::string("Failed to load tile 0/0/0=>0 for source mapbox: " + message))));
- auto unchecked = flo->unchecked();
- EXPECT_TRUE(unchecked.empty()) << unchecked;
-}
diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp
deleted file mode 100644
index 0b9726d3fa..0000000000
--- a/test/api/repeated_render.test.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <mbgl/test/util.hpp>
-#include <mbgl/test/fixture_log_observer.hpp>
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
-#include <mbgl/util/default_thread_pool.hpp>
-#include <mbgl/storage/default_file_source.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <future>
-
-using namespace mbgl;
-
-
-TEST(API, RepeatedRender) {
-
- util::RunLoop loop;
-
- const auto style = util::read_file("test/fixtures/api/water.json");
-
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext(), { 256, 512 } };
- DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
- ThreadPool threadPool(4);
-
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
-
- {
- map.setStyleJSON(style);
- PremultipliedImage result;
- map.renderStill(view, [&](std::exception_ptr) {
- result = view.readStillImage();
- });
-
- while (!result.valid()) {
- loop.runOnce();
- }
-
- ASSERT_EQ(256u, result.size.width);
- ASSERT_EQ(512u, result.size.height);
-#if !TEST_READ_ONLY
- util::write_file("test/fixtures/api/1.png", encodePNG(result));
-#endif
- }
-
- {
- map.setStyleJSON(style);
- PremultipliedImage result;
- map.renderStill(view, [&](std::exception_ptr) {
- result = view.readStillImage();
- });
-
- while (!result.valid()) {
- loop.runOnce();
- }
-
- ASSERT_EQ(256u, result.size.width);
- ASSERT_EQ(512u, result.size.height);
-#if !TEST_READ_ONLY
- util::write_file("test/fixtures/api/2.png", encodePNG(result));
-#endif
- }
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- auto unchecked = flo->unchecked();
- EXPECT_TRUE(unchecked.empty()) << unchecked;
-}
diff --git a/test/api/zoom_history.cpp b/test/api/zoom_history.cpp
new file mode 100644
index 0000000000..1b1159bf52
--- /dev/null
+++ b/test/api/zoom_history.cpp
@@ -0,0 +1,71 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_file_source.hpp>
+
+#include <mbgl/gl/headless_frontend.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/storage/online_file_source.hpp>
+#include <mbgl/style/function/camera_function.hpp>
+#include <mbgl/style/function/exponential_stops.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+TEST(API, ZoomHistory) {
+ util::RunLoop loop;
+
+ StubFileSource fileSource;
+ ThreadPool threadPool(4);
+ float pixelRatio { 1 };
+
+ HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
+ auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
+ pixelRatio, fileSource, threadPool, MapMode::Still);
+
+ EXPECT_TRUE(map);
+
+ map->getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+
+ auto source = std::make_unique<GeoJSONSource>("source");
+ source->setGeoJSON({ LineString<double> { { 45, -45 }, { -45, 45 } } });
+ map->getStyle().addSource(std::move(source));
+
+ auto layer = std::make_unique<LineLayer>("layer-1", "source");
+ layer->setLineWidth(CameraFunction<float> { ExponentialStops<float> {{ { 0, 8 }, { 1, 16 } }} });
+ layer->setLineDasharray({ std::vector<float> { 1, 1 } });
+ layer->setLineColor( { Color::black() } );
+ map->getStyle().addLayer(std::move(layer));
+
+ layer = std::make_unique<LineLayer>("layer-2", "source");
+ layer->setLineWidth(CameraFunction<float> { ExponentialStops<float> {{ { 0, 4 }, { 1, 8 } }} });
+ layer->setLineDasharray({ std::vector<float> { 2, 2 } });
+ layer->setLineColor( { Color::red() } );
+ map->getStyle().addLayer(std::move(layer));
+
+ // ZoomHistory.lastIntegerZoom is 1.
+ map->setZoom(1.0);
+ frontend.render(*map);
+
+ map->setZoom(0.0);
+ frontend.render(*map);
+
+ // ZoomHistory.lastIntegerZoom should be 0.
+ map->setZoom(0.5);
+ test::checkImage("test/fixtures/zoom_history", frontend.render(*map), 0.0002);
+
+ map->setZoom(1.0);
+ frontend.render(*map);
+
+ map->setZoom(0.5);
+ test::checkImage("test/fixtures/zoom_history", frontend.render(*map), 0.0002);
+}
diff --git a/test/fixtures/annotations/readd_image/expected.png b/test/fixtures/annotations/readd_image/expected.png
new file mode 100644
index 0000000000..3c4847f3a7
--- /dev/null
+++ b/test/fixtures/annotations/readd_image/expected.png
Binary files differ
diff --git a/test/fixtures/api/empty-zoomed.json b/test/fixtures/api/empty-zoomed.json
new file mode 100644
index 0000000000..02d8fca99e
--- /dev/null
+++ b/test/fixtures/api/empty-zoomed.json
@@ -0,0 +1,6 @@
+{
+ "version": 8,
+ "zoom": 0.5,
+ "sources": {},
+ "layers": []
+}
diff --git a/test/fixtures/image_manager/basic/expected.png b/test/fixtures/image_manager/basic/expected.png
new file mode 100644
index 0000000000..8c615234dc
--- /dev/null
+++ b/test/fixtures/image_manager/basic/expected.png
Binary files differ
diff --git a/test/fixtures/image_manager/updates_after/expected.png b/test/fixtures/image_manager/updates_after/expected.png
new file mode 100644
index 0000000000..db588c739b
--- /dev/null
+++ b/test/fixtures/image_manager/updates_after/expected.png
Binary files differ
diff --git a/test/fixtures/image_manager/updates_before/expected.png b/test/fixtures/image_manager/updates_before/expected.png
new file mode 100644
index 0000000000..1466a92fe7
--- /dev/null
+++ b/test/fixtures/image_manager/updates_before/expected.png
Binary files differ
diff --git a/test/fixtures/map/nocontent/expected.png b/test/fixtures/map/nocontent/expected.png
new file mode 100644
index 0000000000..8fa3f0f5db
--- /dev/null
+++ b/test/fixtures/map/nocontent/expected.png
Binary files differ
diff --git a/test/fixtures/map/prefetch/empty.json b/test/fixtures/map/prefetch/empty.json
new file mode 100644
index 0000000000..61a8fadcdb
--- /dev/null
+++ b/test/fixtures/map/prefetch/empty.json
@@ -0,0 +1,5 @@
+{
+ "version": 8,
+ "sources": {},
+ "layers": []
+}
diff --git a/test/fixtures/map/prefetch/expected.png b/test/fixtures/map/prefetch/expected.png
new file mode 100644
index 0000000000..e1111b37f7
--- /dev/null
+++ b/test/fixtures/map/prefetch/expected.png
Binary files differ
diff --git a/test/fixtures/map/prefetch/style.json b/test/fixtures/map/prefetch/style.json
new file mode 100644
index 0000000000..b4e163888c
--- /dev/null
+++ b/test/fixtures/map/prefetch/style.json
@@ -0,0 +1,24 @@
+{
+ "version": 8,
+ "name": "Test",
+ "sources": {
+ "raster": {
+ "type": "raster",
+ "tiles": [ "{z}" ],
+ "tileSize": 256,
+ "maxzoom": 20,
+ "minzoom": 0
+ }
+ },
+ "layers": [{
+ "id": "background",
+ "type": "background",
+ "paint": {
+ "background-color": "blue"
+ }
+ }, {
+ "id": "raster",
+ "type": "raster",
+ "source": "raster"
+ }]
+}
diff --git a/test/fixtures/map/prefetch/tile_green.png b/test/fixtures/map/prefetch/tile_green.png
new file mode 100644
index 0000000000..553cd10cd1
--- /dev/null
+++ b/test/fixtures/map/prefetch/tile_green.png
Binary files differ
diff --git a/test/fixtures/map/prefetch/tile_red.png b/test/fixtures/map/prefetch/tile_red.png
new file mode 100644
index 0000000000..5fa561fb92
--- /dev/null
+++ b/test/fixtures/map/prefetch/tile_red.png
Binary files differ
diff --git a/test/fixtures/offline_database/v5.db b/test/fixtures/offline_database/v5.db
new file mode 100644
index 0000000000..9bba351208
--- /dev/null
+++ b/test/fixtures/offline_database/v5.db
Binary files differ
diff --git a/test/fixtures/offline_download/radar.gif b/test/fixtures/offline_download/radar.gif
new file mode 100644
index 0000000000..7398a060c0
--- /dev/null
+++ b/test/fixtures/offline_download/radar.gif
Binary files differ
diff --git a/test/fixtures/offline_download/style.json b/test/fixtures/offline_download/style.json
index 978df3aae3..618afd45f0 100644
--- a/test/fixtures/offline_download/style.json
+++ b/test/fixtures/offline_download/style.json
@@ -5,6 +5,16 @@
"mapbox": {
"type": "vector",
"url": "http://127.0.0.1:3000/streets.json"
+ },
+ "radar": {
+ "type": "image",
+ "url":"http://127.0.0.1:3000/radar.gif",
+ "coordinates": [
+ [-180, -85.0511],
+ [180, -85.0511],
+ [180, 85.0511],
+ [-180, 85.0511]
+ ]
}
},
"glyphs": "http://127.0.0.1:3000/{fontstack}/{range}.pbf",
diff --git a/test/fixtures/recycle_map/default_marker/expected.png b/test/fixtures/recycle_map/default_marker/expected.png
new file mode 100644
index 0000000000..a23b79f8d8
--- /dev/null
+++ b/test/fixtures/recycle_map/default_marker/expected.png
Binary files differ
diff --git a/test/fixtures/recycle_map/flipped_marker/expected.png b/test/fixtures/recycle_map/flipped_marker/expected.png
new file mode 100644
index 0000000000..3c4847f3a7
--- /dev/null
+++ b/test/fixtures/recycle_map/flipped_marker/expected.png
Binary files differ
diff --git a/test/fixtures/sprite_atlas/basic/expected.png b/test/fixtures/sprite_atlas/basic/expected.png
deleted file mode 100644
index cd13d16df6..0000000000
--- a/test/fixtures/sprite_atlas/basic/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/sprite_atlas/size/expected.png b/test/fixtures/sprite_atlas/size/expected.png
deleted file mode 100644
index d9ae7dab47..0000000000
--- a/test/fixtures/sprite_atlas/size/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/sprite_atlas/updates_after/expected.png b/test/fixtures/sprite_atlas/updates_after/expected.png
deleted file mode 100644
index 3c850c0a25..0000000000
--- a/test/fixtures/sprite_atlas/updates_after/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/sprite_atlas/updates_before/expected.png b/test/fixtures/sprite_atlas/updates_before/expected.png
deleted file mode 100644
index effcd38f1e..0000000000
--- a/test/fixtures/sprite_atlas/updates_before/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/style_parser/center-not-latlong.info.json b/test/fixtures/style_parser/center-not-latlong.info.json
new file mode 100644
index 0000000000..c79de0a525
--- /dev/null
+++ b/test/fixtures/style_parser/center-not-latlong.info.json
@@ -0,0 +1,7 @@
+{
+ "default": {
+ "log": [
+ [1, "WARNING", "ParseStyle", "center coordinate must be a longitude, latitude pair"]
+ ]
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/style_parser/center-not-latlong.style.json b/test/fixtures/style_parser/center-not-latlong.style.json
new file mode 100644
index 0000000000..eb847868f5
--- /dev/null
+++ b/test/fixtures/style_parser/center-not-latlong.style.json
@@ -0,0 +1,4 @@
+{
+ "version": 8,
+ "center" : [ 75.123, 181.123]
+} \ No newline at end of file
diff --git a/test/fixtures/style_parser/geojson-missing-properties.info.json b/test/fixtures/style_parser/geojson-missing-properties.info.json
new file mode 100644
index 0000000000..9c25a2f488
--- /dev/null
+++ b/test/fixtures/style_parser/geojson-missing-properties.info.json
@@ -0,0 +1,6 @@
+{
+ "default": {
+ "log": [
+ ]
+ }
+}
diff --git a/test/fixtures/style_parser/geojson-missing-properties.style.json b/test/fixtures/style_parser/geojson-missing-properties.style.json
new file mode 100644
index 0000000000..fc4fe97c78
--- /dev/null
+++ b/test/fixtures/style_parser/geojson-missing-properties.style.json
@@ -0,0 +1,9 @@
+{
+ "version": 8,
+ "sources": {
+ "mapbox": {
+ "type": "geojson",
+ "data": { "type": "Feature", "geometry": { "type": "Point", "coordinates": [100.0, 0.0] } }
+ }
+ }
+}
diff --git a/test/fixtures/style_parser/image-coordinates.info.json b/test/fixtures/style_parser/image-coordinates.info.json
new file mode 100644
index 0000000000..5ef44badba
--- /dev/null
+++ b/test/fixtures/style_parser/image-coordinates.info.json
@@ -0,0 +1,7 @@
+{
+ "default": {
+ "log": [
+ [1, "WARNING", "ParseStyle", "Image coordinates must be an array of four longitude latitude pairs"]
+ ]
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/style_parser/image-coordinates.style.json b/test/fixtures/style_parser/image-coordinates.style.json
new file mode 100644
index 0000000000..51b0e93ee7
--- /dev/null
+++ b/test/fixtures/style_parser/image-coordinates.style.json
@@ -0,0 +1,14 @@
+{
+ "version": 8,
+ "center" : [ 75.123, 81.123],
+ "sources": {
+ "image": {
+ "type": "image",
+ "url": "local://0.png",
+ "coordinates": [
+ [ 12.2344, 87.23434],
+ [-12.234, 12.41242]
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/style_parser/image-url.info.json b/test/fixtures/style_parser/image-url.info.json
new file mode 100644
index 0000000000..988e89c011
--- /dev/null
+++ b/test/fixtures/style_parser/image-url.info.json
@@ -0,0 +1,7 @@
+{
+ "default": {
+ "log": [
+ [1, "WARNING", "ParseStyle", "Image source must have a url value"]
+ ]
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/style_parser/image-url.style.json b/test/fixtures/style_parser/image-url.style.json
new file mode 100644
index 0000000000..94614cb7ab
--- /dev/null
+++ b/test/fixtures/style_parser/image-url.style.json
@@ -0,0 +1,9 @@
+{
+ "version": 8,
+ "center" : [ 75.123, 81.123],
+ "sources": {
+ "image": {
+ "type": "image"
+ }
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/zoom_history/expected.png b/test/fixtures/zoom_history/expected.png
new file mode 100644
index 0000000000..100dc508a4
--- /dev/null
+++ b/test/fixtures/zoom_history/expected.png
Binary files differ
diff --git a/test/geometry/binpack.test.cpp b/test/geometry/binpack.test.cpp
deleted file mode 100644
index 0b74df7fa9..0000000000
--- a/test/geometry/binpack.test.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <mbgl/test/util.hpp>
-
-#include <mbgl/geometry/binpack.hpp>
-
-#include <iosfwd>
-#include <array>
-
-namespace mbgl {
-template <typename T> ::std::ostream& operator<<(::std::ostream& os, const Rect<T>& t) {
- return os << "Rect { " << t.x << ", " << t.y << ", " << t.w << ", " << t.h << " }";
-}
-} // namespace mbgl
-
-TEST(BinPack, Allocating) {
- mbgl::BinPack<uint16_t> bin(128, 128);
- std::array<mbgl::Rect<uint16_t>, 4> rects;
-
- rects[0] = bin.allocate(32, 48);
- ASSERT_EQ(mbgl::Rect<uint16_t>(0, 0, 32, 48), rects[0]);
- rects[1] = bin.allocate(8, 17);
- ASSERT_EQ(mbgl::Rect<uint16_t>(32, 0, 8, 17), rects[1]);
- rects[2] = bin.allocate(8, 17);
- ASSERT_EQ(mbgl::Rect<uint16_t>(0, 48, 8, 17), rects[2]);
-
- bin.release(rects[0]);
- rects[0] = bin.allocate(32, 24);
- ASSERT_EQ(mbgl::Rect<uint16_t>(0, 0, 32, 24), rects[0]);
- rects[3] = bin.allocate(32, 24);
- ASSERT_EQ(mbgl::Rect<uint16_t>(32, 17, 32, 24), rects[3]);
-}
-
-
-TEST(BinPack, Full) {
- mbgl::BinPack<uint16_t> bin(128, 128);
- std::vector<mbgl::Rect<uint16_t>> rects;
-
- for (int j = 0; j < 3; j++) {
- for (int i = 0; i < 256; i++) {
- auto rect = bin.allocate(8, 8);
- ASSERT_TRUE(rect.hasArea());
- rects.push_back(rect);
- }
-
- ASSERT_FALSE(bin.allocate(8, 8).hasArea());
-
- for (auto& rect: rects) {
- bin.release(rect);
- }
- rects.clear();
- }
-}
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index e21d82321d..5f9626bc99 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -1,29 +1,94 @@
#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_geometry_tile_feature.hpp>
-#include <mbgl/renderer/circle_bucket.hpp>
-#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/gl/context.hpp>
#include <mbgl/map/mode.hpp>
+namespace mbgl {
+
+template <class Attributes>
+bool operator==(const Segment<Attributes>& lhs, const Segment<Attributes>& rhs) {
+ return std::tie(lhs.vertexOffset, lhs.indexOffset, lhs.vertexLength, lhs.indexLength) ==
+ std::tie(rhs.vertexOffset, rhs.indexOffset, rhs.vertexLength, rhs.indexLength);
+}
+
+namespace gl {
+namespace detail {
+
+template <class A1, class A2>
+bool operator==(const Vertex<A1, A2>& lhs, const Vertex<A1, A2>& rhs) {
+ return std::tie(lhs.a1, lhs.a2) == std::tie(rhs.a1, rhs.a2);
+}
+
+} // namespace detail
+} // namespace gl
+} // namespace mbgl
+
using namespace mbgl;
+namespace {
+
+PropertyMap properties;
+
+} // namespace
+
TEST(Buckets, CircleBucket) {
- CircleBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
+ gl::Context context;
+ CircleBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ GeometryCollection point { { { 0, 0 } } };
+ bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, point, properties }, point);
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
}
TEST(Buckets, FillBucket) {
- FillBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
+ gl::Context context;
+ FillBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ GeometryCollection polygon { { { 0, 0 }, { 0, 1 }, { 1, 1 } } };
+ bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Polygon, polygon, properties }, polygon);
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_FALSE(bucket.needsUpload());
}
TEST(Buckets, LineBucket) {
- LineBucket bucket { { {0, 0, 0}, MapMode::Still }, {}, {} };
+ gl::Context context;
+ LineBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {}, {} };
ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ // Ignore invalid feature type.
+ GeometryCollection point { { { 0, 0 } } };
+ bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, point, properties }, point);
+ ASSERT_FALSE(bucket.hasData());
+
+ GeometryCollection line { { { 0, 0 }, { 1, 1 } } };
+ bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::LineString, line, properties }, line);
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_FALSE(bucket.needsUpload());
}
TEST(Buckets, SymbolBucket) {
@@ -31,8 +96,180 @@ TEST(Buckets, SymbolBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
+ gl::Context context;
SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear };
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
+ ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ // SymbolBucket::addFeature() is a no-op.
+ GeometryCollection point { { { 0, 0 } } };
+ bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, point, properties }, point);
+ ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ bucket.text.segments.emplace_back(0, 0);
+ ASSERT_TRUE(bucket.hasTextData());
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_FALSE(bucket.needsUpload());
+}
+
+TEST(Buckets, RasterBucket) {
+ gl::Context context;
+ PremultipliedImage rgba({ 1, 1 });
+
+ // RasterBucket::hasData() is always true.
+ RasterBucket bucket = { std::move(rgba) };
+ ASSERT_TRUE(bucket.hasData());
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_FALSE(bucket.needsUpload());
+
+ bucket.clear();
+ ASSERT_TRUE(bucket.needsUpload());
}
+
+TEST(Buckets, RasterBucketMaskEmpty) {
+ RasterBucket bucket{ nullptr };
+ bucket.setMask({});
+ EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector());
+ EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector());
+ SegmentVector<RasterAttributes> expectedSegments;
+ expectedSegments.emplace_back(0, 0, 0, 0);
+ EXPECT_EQ(expectedSegments, bucket.segments);
+}
+
+TEST(Buckets, RasterBucketMaskNoChildren) {
+ RasterBucket bucket{ nullptr };
+ bucket.setMask({ CanonicalTileID{ 0, 0, 0 } });
+
+ // A mask of 0/0/0 doesn't produce buffers since we're instead using the global shared buffers.
+ EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector());
+ EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector());
+ EXPECT_EQ((SegmentVector<RasterAttributes>{}), bucket.segments);
+}
+
+ TEST(Buckets, RasterBucketMaskTwoChildren) {
+ RasterBucket bucket{ nullptr };
+ bucket.setMask(
+ { CanonicalTileID{ 1, 0, 0 }, CanonicalTileID{ 1, 1, 1 } });
+
+ EXPECT_EQ(
+ (std::vector<RasterLayoutVertex>{
+ // 1/0/1
+ RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }),
+ RasterProgram::layoutVertex({ 4096, 0 }, { 4096, 0 }),
+ RasterProgram::layoutVertex({ 0, 4096 }, { 0, 4096 }),
+ RasterProgram::layoutVertex({ 4096, 4096 }, { 4096, 4096 }),
+
+ // 1/1/1
+ RasterProgram::layoutVertex({ 4096, 4096 }, { 4096, 4096 }),
+ RasterProgram::layoutVertex({ 8192, 4096 }, { 8192, 4096 }),
+ RasterProgram::layoutVertex({ 4096, 8192 }, { 4096, 8192 }),
+ RasterProgram::layoutVertex({ 8192, 8192 }, { 8192, 8192 }),
+ }),
+ bucket.vertices.vector());
+
+ EXPECT_EQ(
+ (std::vector<uint16_t>{
+ // 1/0/1
+ 0, 1, 2,
+ 1, 2, 3,
+
+ // 1/1/1
+ 4, 5, 6,
+ 5, 6, 7,
+ }),
+ bucket.indices.vector());
+
+
+ SegmentVector<RasterAttributes> expectedSegments;
+ expectedSegments.emplace_back(0, 0, 8, 12);
+ EXPECT_EQ(expectedSegments, bucket.segments);
+ }
+
+ TEST(Buckets, RasterBucketMaskComplex) {
+ RasterBucket bucket{ nullptr };
+ bucket.setMask(
+ { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 }, CanonicalTileID{ 2, 2, 3 },
+ CanonicalTileID{ 2, 3, 2 }, CanonicalTileID{ 3, 6, 7 }, CanonicalTileID{ 3, 7, 6 } });
+
+ EXPECT_EQ(
+ (std::vector<RasterLayoutVertex>{
+ // 1/0/1
+ RasterProgram::layoutVertex({ 0, 4096 }, { 0, 4096 }),
+ RasterProgram::layoutVertex({ 4096, 4096 }, { 4096, 4096 }),
+ RasterProgram::layoutVertex({ 0, 8192 }, { 0, 8192 }),
+ RasterProgram::layoutVertex({ 4096, 8192 }, { 4096, 8192 }),
+
+ // 1/1/0
+ RasterProgram::layoutVertex({ 4096, 0 }, { 4096, 0 }),
+ RasterProgram::layoutVertex({ 8192, 0 }, { 8192, 0 }),
+ RasterProgram::layoutVertex({ 4096, 4096 }, { 4096, 4096 }),
+ RasterProgram::layoutVertex({ 8192, 4096 }, { 8192, 4096 }),
+
+ // 2/2/3
+ RasterProgram::layoutVertex({ 4096, 6144 }, { 4096, 6144 }),
+ RasterProgram::layoutVertex({ 6144, 6144 }, { 6144, 6144 }),
+ RasterProgram::layoutVertex({ 4096, 8192 }, { 4096, 8192 }),
+ RasterProgram::layoutVertex({ 6144, 8192 }, { 6144, 8192 }),
+
+ // 2/3/2
+ RasterProgram::layoutVertex({ 6144, 4096 }, { 6144, 4096 }),
+ RasterProgram::layoutVertex({ 8192, 4096 }, { 8192, 4096 }),
+ RasterProgram::layoutVertex({ 6144, 6144 }, { 6144, 6144 }),
+ RasterProgram::layoutVertex({ 8192, 6144 }, { 8192, 6144 }),
+
+ // 3/6/7
+ RasterProgram::layoutVertex({ 6144, 7168 }, { 6144, 7168 }),
+ RasterProgram::layoutVertex({ 7168, 7168 }, { 7168, 7168 }),
+ RasterProgram::layoutVertex({ 6144, 8192 }, { 6144, 8192 }),
+ RasterProgram::layoutVertex({ 7168, 8192 }, { 7168, 8192 }),
+
+ // 3/7/6
+ RasterProgram::layoutVertex({ 7168, 6144 }, { 7168, 6144 }),
+ RasterProgram::layoutVertex({ 8192, 6144 }, { 8192, 6144 }),
+ RasterProgram::layoutVertex({ 7168, 7168 }, { 7168, 7168 }),
+ RasterProgram::layoutVertex({ 8192, 7168 }, { 8192, 7168 }),
+ }),
+ bucket.vertices.vector());
+
+ EXPECT_EQ(
+ (std::vector<uint16_t>{
+ // 1/0/1
+ 0, 1, 2,
+ 1, 2, 3,
+
+ // 1/1/0
+ 4, 5, 6,
+ 5, 6, 7,
+
+ // 2/2/3
+ 8, 9, 10,
+ 9, 10, 11,
+
+ // 2/3/2
+ 12, 13, 14,
+ 13, 14, 15,
+
+ // 3/6/7
+ 16, 17, 18,
+ 17, 18, 19,
+
+ // 3/7/6
+ 20, 21, 22,
+ 21, 22, 23,
+ }),
+ bucket.indices.vector());
+
+
+ SegmentVector<RasterAttributes> expectedSegments;
+ expectedSegments.emplace_back(0, 0, 24, 36);
+ EXPECT_EQ(expectedSegments, bucket.segments);
+ }
diff --git a/test/gl/object.test.cpp b/test/gl/object.test.cpp
index b5a055f4ca..8046927c54 100644
--- a/test/gl/object.test.cpp
+++ b/test/gl/object.test.cpp
@@ -1,9 +1,7 @@
#include <mbgl/test/util.hpp>
-#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
-
#include <mbgl/gl/context.hpp>
#include <memory>
@@ -47,9 +45,8 @@ TEST(GLObject, Value) {
}
TEST(GLObject, Store) {
- HeadlessBackend backend { test::sharedDisplay() };
+ HeadlessBackend backend { { 256, 256 } };
BackendScope scope { backend };
- OffscreenView view(backend.getContext());
gl::Context context;
EXPECT_TRUE(context.empty());
diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp
index c24f736fcd..50d5e50abb 100644
--- a/test/map/map.test.cpp
+++ b/test/map/map.test.cpp
@@ -4,10 +4,8 @@
#include <mbgl/test/fixture_log_observer.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/storage/default_file_source.hpp>
@@ -16,6 +14,7 @@
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/async_task.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/util/color.hpp>
@@ -24,87 +23,116 @@ using namespace mbgl;
using namespace mbgl::style;
using namespace std::literals::string_literals;
-class BackendTest : public HeadlessBackend {
+class StubMapObserver : public MapObserver {
public:
- BackendTest() : HeadlessBackend(test::sharedDisplay()) {}
-
+ void onWillStartLoadingMap() final {
+ if (onWillStartLoadingMapCallback) {
+ onWillStartLoadingMapCallback();
+ }
+ }
+
+ void onDidFinishLoadingMap() final {
+ if (onDidFinishLoadingMapCallback) {
+ onDidFinishLoadingMapCallback();
+ }
+ }
+
void onDidFailLoadingMap(std::exception_ptr) final {
if (didFailLoadingMapCallback) {
didFailLoadingMapCallback();
}
}
-
+
void onDidFinishLoadingStyle() final {
if (didFinishLoadingStyleCallback) {
didFinishLoadingStyleCallback();
}
}
+ void onDidFinishRenderingFrame(RenderMode mode) final {
+ if (didFinishRenderingFrame) {
+ didFinishRenderingFrame(mode);
+ }
+ }
+
+ std::function<void()> onWillStartLoadingMapCallback;
+ std::function<void()> onDidFinishLoadingMapCallback;
std::function<void()> didFailLoadingMapCallback;
std::function<void()> didFinishLoadingStyleCallback;
+ std::function<void(RenderMode)> didFinishRenderingFrame;
};
-struct MapTest {
+template <class FileSource = StubFileSource>
+class MapTest {
+public:
util::RunLoop runLoop;
- BackendTest backend;
- BackendScope scope { backend };
- OffscreenView view { backend.getContext() };
- StubFileSource fileSource;
+ FileSource fileSource;
ThreadPool threadPool { 4 };
+ StubMapObserver observer;
+ HeadlessFrontend frontend;
+ Map map;
+
+ MapTest(float pixelRatio = 1, MapMode mode = MapMode::Still)
+ : frontend(pixelRatio, fileSource, threadPool)
+ , map(frontend, observer, frontend.getSize(), pixelRatio, fileSource, threadPool, mode) {
+ }
+
+ template <typename T = FileSource>
+ MapTest(const std::string& cachePath, const std::string& assetRoot,
+ float pixelRatio = 1, MapMode mode = MapMode::Still,
+ typename std::enable_if<std::is_same<T, DefaultFileSource>::value>::type* = 0)
+ : fileSource { cachePath, assetRoot }
+ , frontend(pixelRatio, fileSource, threadPool)
+ , map(frontend, observer, frontend.getSize(), pixelRatio, fileSource, threadPool, mode) {
+ }
};
TEST(Map, LatLngBehavior) {
- MapTest test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
-
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ MapTest<> test;
- map.setLatLngZoom({ 1, 1 }, 0);
- auto latLng1 = map.getLatLng();
+ test.map.setLatLngZoom({ 1, 1 }, 0);
+ auto latLng1 = test.map.getLatLng();
- map.setLatLng({ 1, 1 });
- auto latLng2 = map.getLatLng();
+ test.map.setLatLng({ 1, 1 });
+ auto latLng2 = test.map.getLatLng();
ASSERT_DOUBLE_EQ(latLng1.latitude(), latLng2.latitude());
ASSERT_DOUBLE_EQ(latLng1.longitude(), latLng2.longitude());
}
TEST(Map, LatLngBoundsToCamera) {
- MapTest test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
+ MapTest<> test;
- map.setLatLngZoom({ 40.712730, -74.005953 }, 16.0);
+ test.map.setLatLngZoom({ 40.712730, -74.005953 }, 16.0);
LatLngBounds bounds = LatLngBounds::hull({15.68169,73.499857}, {53.560711, 134.77281});
- CameraOptions virtualCamera = map.cameraForLatLngBounds(bounds, {});
+ CameraOptions virtualCamera = test.map.cameraForLatLngBounds(bounds, {});
ASSERT_TRUE(bounds.contains(*virtualCamera.center));
}
TEST(Map, CameraToLatLngBounds) {
- MapTest test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
+ MapTest<> test;
- map.setLatLngZoom({ 45, 90 }, 16);
+ test.map.setLatLngZoom({ 45, 90 }, 16);
LatLngBounds bounds = LatLngBounds::hull(
- map.latLngForPixel({}),
- map.latLngForPixel({ double(map.getSize().width), double(map.getSize().height) }));
+ test.map.latLngForPixel({}),
+ test.map.latLngForPixel({ double(test.map.getSize().width), double(test.map.getSize().height) }));
- CameraOptions camera = map.getCameraOptions({});
+ CameraOptions camera = test.map.getCameraOptions({});
- ASSERT_EQ(bounds, map.latLngBoundsForCamera(camera));
+ ASSERT_EQ(bounds, test.map.latLngBoundsForCamera(camera));
// Map::cameraForLatLngBounds only sets zoom and center.
- CameraOptions virtualCamera = map.cameraForLatLngBounds(bounds, {});
+ CameraOptions virtualCamera = test.map.cameraForLatLngBounds(bounds, {});
ASSERT_NEAR(*camera.zoom, *virtualCamera.zoom, 1e-7);
ASSERT_NEAR(camera.center->latitude(), virtualCamera.center->latitude(), 1e-7);
ASSERT_NEAR(camera.center->longitude(), virtualCamera.center->longitude(), 1e-7);
}
TEST(Map, Offline) {
- MapTest test;
- DefaultFileSource fileSource(":memory:", ".");
+ MapTest<DefaultFileSource> test {":memory:", "."};
auto expiredItem = [] (const std::string& path) {
Response response;
@@ -114,39 +142,50 @@ TEST(Map, Offline) {
};
const std::string prefix = "http://127.0.0.1:3000/";
- fileSource.put(Resource::style(prefix + "style.json"), expiredItem("style.json"));
- fileSource.put(Resource::source(prefix + "streets.json"), expiredItem("streets.json"));
- fileSource.put(Resource::spriteJSON(prefix + "sprite", 1.0), expiredItem("sprite.json"));
- fileSource.put(Resource::spriteImage(prefix + "sprite", 1.0), expiredItem("sprite.png"));
- fileSource.put(Resource::tile(prefix + "{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), expiredItem("0-0-0.vector.pbf"));
- fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf"));
+ test.fileSource.put(Resource::style(prefix + "style.json"), expiredItem("style.json"));
+ test.fileSource.put(Resource::source(prefix + "streets.json"), expiredItem("streets.json"));
+ test.fileSource.put(Resource::spriteJSON(prefix + "sprite", 1.0), expiredItem("sprite.json"));
+ test.fileSource.put(Resource::spriteImage(prefix + "sprite", 1.0), expiredItem("sprite.png"));
+ test.fileSource.put(Resource::tile(prefix + "{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), expiredItem("0-0-0.vector.pbf"));
+ test.fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf"));
NetworkStatus::Set(NetworkStatus::Status::Offline);
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL(prefix + "style.json");
+ test.map.getStyle().loadURL(prefix + "style.json");
test::checkImage("test/fixtures/map/offline",
- test::render(map, test.view),
+ test.frontend.render(test.map),
0.0015,
0.1);
NetworkStatus::Set(NetworkStatus::Status::Online);
}
-TEST(Map, SetStyleInvalidJSON) {
- MapTest test;
+TEST(Map, SetStyleDefaultCamera) {
+ MapTest<> test;
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ EXPECT_DOUBLE_EQ(test.map.getZoom(), 0.0);
+ EXPECT_DOUBLE_EQ(test.map.getPitch(), 0.0);
+ EXPECT_DOUBLE_EQ(test.map.getBearing(), 0.0);
+ EXPECT_EQ(test.map.getLatLng(), LatLng {});
+
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty-zoomed.json"));
+ EXPECT_DOUBLE_EQ(test.map.getZoom(), 0.0);
+
+ test.map.jumpTo(test.map.getStyle().getDefaultCamera());
+ EXPECT_DOUBLE_EQ(test.map.getZoom(), 0.5);
+}
+TEST(Map, SetStyleInvalidJSON) {
Log::setObserver(std::make_unique<FixtureLogObserver>());
bool fail = false;
- test.backend.didFailLoadingMapCallback = [&]() {
- fail = true;
- };
{
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool,
- MapMode::Still);
- map.setStyleJSON("invalid");
+ MapTest<> test;
+ test.observer.didFailLoadingMapCallback = [&]() {
+ fail = true;
+ };
+ test.map.getStyle().loadJSON("invalid");
}
EXPECT_TRUE(fail);
@@ -160,7 +199,7 @@ TEST(Map, SetStyleInvalidJSON) {
}
TEST(Map, SetStyleInvalidURL) {
- MapTest test;
+ MapTest<> test;
test.fileSource.styleResponse = [] (const Resource&) {
Response response;
@@ -170,40 +209,36 @@ TEST(Map, SetStyleInvalidURL) {
return response;
};
- test.backend.didFailLoadingMapCallback = [&]() {
+ test.observer.didFailLoadingMapCallback = [&]() {
test.runLoop.stop();
};
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://bar");
+ test.map.getStyle().loadURL("mapbox://bar");
test.runLoop.run();
}
TEST(Map, DoubleStyleLoad) {
- MapTest test;
+ MapTest<> test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON("");
- map.setStyleJSON("");
+ test.map.getStyle().loadJSON("");
+ test.map.getStyle().loadJSON("");
}
TEST(Map, StyleFresh) {
// The map should not revalidate fresh styles.
- MapTest test;
- FakeFileSource fileSource;
+ MapTest<FakeFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.map.getStyle().loadURL("mapbox://styles/test");
+ EXPECT_EQ(1u, test.fileSource.requests.size());
Response response;
response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json"));
response.expires = Timestamp::max();
- fileSource.respond(Resource::Style, response);
- EXPECT_EQ(0u, fileSource.requests.size());
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(0u, test.fileSource.requests.size());
}
TEST(Map, StyleExpired) {
@@ -211,26 +246,24 @@ TEST(Map, StyleExpired) {
using namespace std::chrono_literals;
- MapTest test;
- FakeFileSource fileSource;
+ MapTest<FakeFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.map.getStyle().loadURL("mapbox://styles/test");
+ EXPECT_EQ(1u, test.fileSource.requests.size());
Response response;
response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json"));
response.expires = util::now() - 1h;
- fileSource.respond(Resource::Style, response);
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
- map.addLayer(std::make_unique<style::BackgroundLayer>("bg"));
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.map.getStyle().addLayer(std::make_unique<style::BackgroundLayer>("bg"));
+ EXPECT_EQ(1u, test.fileSource.requests.size());
- fileSource.respond(Resource::Style, response);
- EXPECT_EQ(0u, fileSource.requests.size());
- EXPECT_NE(nullptr, map.getLayer("bg"));
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(0u, test.fileSource.requests.size());
+ EXPECT_NE(nullptr, test.map.getStyle().getLayer("bg"));
}
TEST(Map, StyleExpiredWithAnnotations) {
@@ -238,72 +271,111 @@ TEST(Map, StyleExpiredWithAnnotations) {
using namespace std::chrono_literals;
- MapTest test;
- FakeFileSource fileSource;
+ MapTest<FakeFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.map.getStyle().loadURL("mapbox://styles/test");
+ EXPECT_EQ(1u, test.fileSource.requests.size());
Response response;
response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json"));
response.expires = util::now() - 1h;
- fileSource.respond(Resource::Style, response);
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
- map.addAnnotation(LineAnnotation { LineString<double> {{ { 0, 0 }, { 10, 10 } }} });
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.map.addAnnotation(LineAnnotation { LineString<double> {{ { 0, 0 }, { 10, 10 } }} });
+ EXPECT_EQ(1u, test.fileSource.requests.size());
- fileSource.respond(Resource::Style, response);
- EXPECT_EQ(1u, fileSource.requests.size());
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
+}
+
+TEST(Map, StyleExpiredWithRender) {
+ // Rendering should not prevent revalidation of an expired style.
+
+ using namespace std::chrono_literals;
+
+ MapTest<FakeFileSource> test;
+
+ test.map.getStyle().loadURL("mapbox://styles/test");
+ EXPECT_EQ(1u, test.fileSource.requests.size());
+
+ Response response;
+ response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json"));
+ response.expires = util::now() - 1h;
+
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
+
+ test.frontend.render(test.map);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
+
+ test.fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, test.fileSource.requests.size());
}
TEST(Map, StyleEarlyMutation) {
// An early mutation should not prevent the initial style load.
- MapTest test;
- FakeFileSource fileSource;
+ MapTest<FakeFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
- map.addLayer(std::make_unique<style::BackgroundLayer>("bg"));
+ test.map.getStyle().loadURL("mapbox://styles/test");
+ test.map.getStyle().addLayer(std::make_unique<style::BackgroundLayer>("bg"));
Response response;
response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/water.json"));
- fileSource.respond(Resource::Style, response);
+ test.fileSource.respond(Resource::Style, response);
+
+ EXPECT_EQ(0u, test.fileSource.requests.size());
+ EXPECT_NE(nullptr, test.map.getStyle().getLayer("water"));
+}
+
+TEST(Map, MapLoadingSignal) {
+ MapTest<> test;
+
+ bool emitted = false;
+ test.observer.onWillStartLoadingMapCallback = [&]() {
+ emitted = true;
+ };
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ EXPECT_TRUE(emitted);
+}
+
+TEST(Map, MapLoadedSignal) {
+ MapTest<> test { 1, MapMode::Continuous };
+
+ test.observer.onDidFinishLoadingMapCallback = [&]() {
+ test.runLoop.stop();
+ };
- EXPECT_EQ(0u, fileSource.requests.size());
- EXPECT_NE(nullptr, map.getLayer("water"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.runLoop.run();
}
TEST(Map, StyleLoadedSignal) {
- MapTest test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
+ MapTest<> test;
// The map should emit a signal on style loaded
bool emitted = false;
- test.backend.didFinishLoadingStyleCallback = [&]() {
+ test.observer.didFinishLoadingStyleCallback = [&]() {
emitted = true;
};
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
EXPECT_TRUE(emitted);
// But not when the style couldn't be parsed
emitted = false;
- map.setStyleJSON("invalid");
+ test.map.getStyle().loadJSON("invalid");
EXPECT_FALSE(emitted);
}
// Test for https://github.com/mapbox/mapbox-gl-native/issues/7902
TEST(Map, TEST_REQUIRES_SERVER(StyleNetworkErrorRetry)) {
- MapTest test;
- OnlineFileSource fileSource;
+ MapTest<OnlineFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("http://127.0.0.1:3000/style-fail-once-500");
+ test.map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-500");
- test.backend.didFinishLoadingStyleCallback = [&]() {
+ test.observer.didFinishLoadingStyleCallback = [&]() {
test.runLoop.stop();
};
@@ -311,21 +383,19 @@ TEST(Map, TEST_REQUIRES_SERVER(StyleNetworkErrorRetry)) {
}
TEST(Map, TEST_REQUIRES_SERVER(StyleNotFound)) {
- MapTest test;
- OnlineFileSource fileSource;
+ MapTest<OnlineFileSource> test;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("http://127.0.0.1:3000/style-fail-once-404");
+ test.map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-404");
using namespace std::chrono_literals;
util::Timer timer;
// Not found errors should not trigger a retry like other errors.
- test.backend.didFinishLoadingStyleCallback = [&]() {
+ test.observer.didFinishLoadingStyleCallback = [&]() {
FAIL() << "Should not retry on not found!";
};
- test.backend.didFailLoadingMapCallback = [&]() {
+ test.observer.didFailLoadingMapCallback = [&]() {
timer.start(Milliseconds(1100), 0s, [&] {
test.runLoop.stop();
});
@@ -334,52 +404,48 @@ TEST(Map, TEST_REQUIRES_SERVER(StyleNotFound)) {
test.runLoop.run();
// Should also not retry if the response has cache headers.
- map.setStyleURL("http://127.0.0.1:3000/style-fail-once-404-cache");
+ test.map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-404-cache");
test.runLoop.run();
}
TEST(Map, AddLayer) {
- MapTest test;
+ MapTest<> test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
auto layer = std::make_unique<BackgroundLayer>("background");
layer->setBackgroundColor({ { 1, 0, 0, 1 } });
- map.addLayer(std::move(layer));
+ test.map.getStyle().addLayer(std::move(layer));
- test::checkImage("test/fixtures/map/add_layer", test::render(map, test.view));
+ test::checkImage("test/fixtures/map/add_layer", test.frontend.render(test.map));
}
TEST(Map, WithoutVAOExtension) {
- MapTest test;
-
- test.backend.getContext().disableVAOExtension = true;
+ MapTest<DefaultFileSource> test { ":memory:", "test/fixtures/api/assets" };
- DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
+ BackendScope scope { *test.frontend.getBackend() };
+ test.frontend.getBackend()->getContext().disableVAOExtension = true;
- Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
- test::checkImage("test/fixtures/map/no_vao", test::render(map, test.view), 0.002);
+ test::checkImage("test/fixtures/map/no_vao", test.frontend.render(test.map), 0.002);
}
TEST(Map, RemoveLayer) {
- MapTest test;
+ MapTest<> test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
auto layer = std::make_unique<BackgroundLayer>("background");
layer->setBackgroundColor({{ 1, 0, 0, 1 }});
- map.addLayer(std::move(layer));
- map.removeLayer("background");
+ test.map.getStyle().addLayer(std::move(layer));
+ test.map.getStyle().removeLayer("background");
- test::checkImage("test/fixtures/map/remove_layer", test::render(map, test.view));
+ test::checkImage("test/fixtures/map/remove_layer", test.frontend.render(test.map));
}
TEST(Map, DisabledSources) {
- MapTest test;
+ MapTest<> test;
// Always load the same image tile for raster layers.
test.fileSource.response = [] (const Resource& res) -> optional<Response> {
@@ -392,15 +458,14 @@ TEST(Map, DisabledSources) {
return {};
};
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setZoom(1);
+ test.map.setZoom(1);
// This stylesheet has two raster layers, one that starts at zoom 1, the other at zoom 0.
// We first render a map at zoom level 1, which should show both layers (both are "visible" due
// to an opacity of 0.5). Then, we are zooming back out to a zoom level of 0.5 and rerender.
// The "raster1" layer should not be visible anymore since it has minzoom 1, while "raster2"
// should still be there. Both layers have a distinct color through "raster-hue-rotate".
- map.setStyleJSON(R"STYLE(
+ test.map.getStyle().loadJSON(R"STYLE(
{
"version": 8,
"name": "Test",
@@ -434,92 +499,15 @@ TEST(Map, DisabledSources) {
}
)STYLE");
- test::checkImage("test/fixtures/map/disabled_layers/first", test::render(map, test.view));
- map.setZoom(0.5);
- test::checkImage("test/fixtures/map/disabled_layers/second", test::render(map, test.view));
-}
-
-TEST(Map, Classes) {
- MapTest test;
-
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
-
- EXPECT_FALSE(map.getTransitionOptions().duration);
-
- auto duration = mbgl::Duration(mbgl::Milliseconds(300));
- map.setTransitionOptions({ duration });
- EXPECT_EQ(map.getTransitionOptions().duration, duration);
-
- map.addClass("test");
- EXPECT_TRUE(map.hasClass("test"));
-
- map.removeClass("test");
- EXPECT_TRUE(map.getClasses().empty());
-
- std::vector<std::string> classes = { "foo", "bar" };
- map.setClasses(classes);
- EXPECT_FALSE(map.hasClass("test"));
- EXPECT_TRUE(map.hasClass("foo"));
- EXPECT_TRUE(map.hasClass("bar"));
-
- // Does nothing - same style JSON.
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
- EXPECT_TRUE(map.hasClass("foo"));
- EXPECT_EQ(map.getTransitionOptions().duration, duration);
-
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
- EXPECT_TRUE(map.getClasses().empty());
- EXPECT_FALSE(map.getTransitionOptions().duration);
-}
-
-TEST(Map, AddImage) {
- MapTest test;
-
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- auto decoded1 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
- auto decoded2 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
- auto image1 = std::make_unique<style::Image>(std::move(decoded1), 1.0);
- auto image2 = std::make_unique<style::Image>(std::move(decoded2), 1.0);
-
- // No-op.
- map.addImage("test-icon", std::move(image1));
-
- map.setStyleJSON(util::read_file("test/fixtures/api/icon_style.json"));
- map.addImage("test-icon", std::move(image2));
- test::checkImage("test/fixtures/map/add_icon", test::render(map, test.view));
-}
-
-TEST(Map, RemoveImage) {
- MapTest test;
-
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
- auto image = std::make_unique<style::Image>(std::move(decoded), 1.0);
-
- map.setStyleJSON(util::read_file("test/fixtures/api/icon_style.json"));
- map.addImage("test-icon", std::move(image));
- map.removeImage("test-icon");
- test::checkImage("test/fixtures/map/remove_icon", test::render(map, test.view));
-}
-
-TEST(Map, GetImage) {
- MapTest test;
-
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
- auto image = std::make_unique<style::Image>(std::move(decoded), 1.0);
-
- map.setStyleJSON(util::read_file("test/fixtures/api/icon_style.json"));
- map.addImage("test-icon", std::move(image));
- test::checkImage("test/fixtures/map/get_icon", map.getImage("test-icon")->image);
+ test::checkImage("test/fixtures/map/disabled_layers/first", test.frontend.render(test.map));
+ test.map.setZoom(0.5);
+ test::checkImage("test/fixtures/map/disabled_layers/second", test.frontend.render(test.map));
}
TEST(Map, DontLoadUnneededTiles) {
- MapTest test;
+ MapTest<> test;
- Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(R"STYLE({
+ test.map.getStyle().loadJSON(R"STYLE({
"sources": {
"a": { "type": "vector", "tiles": [ "a/{z}/{x}/{y}" ] }
},
@@ -557,65 +545,84 @@ TEST(Map, DontLoadUnneededTiles) {
// Note: using z += 0.1 in the loop doesn't produce accurate floating point numbers.
const double z = double(zoom) / 10;
tiles.clear();
- map.setZoom(z);
- test::render(map, test.view);
+ test.map.setZoom(z);
+ test.frontend.render(test.map);
EXPECT_EQ(referenceTiles[z], tiles) << "zoom level " << z;
}
}
-
-class MockBackend : public HeadlessBackend {
-public:
- MockBackend(std::shared_ptr<HeadlessDisplay> display_)
- : HeadlessBackend(display_) {
- }
-
- std::function<void()> callback;
- void invalidate() override {
- if (callback) {
- callback();
- }
- }
-};
-
TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) {
util::RunLoop runLoop;
- MockBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view { backend.getContext() };
ThreadPool threadPool { 4 };
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
- Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Continuous);
+ float pixelRatio { 1 };
using namespace std::chrono_literals;
util::Timer emergencyShutoff;
emergencyShutoff.start(10s, 0s, [&] {
- util::RunLoop::Get()->stop();
+ runLoop.stop();
FAIL() << "Did not stop rendering";
});
util::Timer timer;
- util::AsyncTask render{[&] {
- if (map.isFullyLoaded()) {
- // Abort the test after 1 second after the map loading fully. Note that a "fully loaded
- // map" doesn't mean that we won't render anymore: we could still render fade in/fade
- // out or other animations.
- // If we are continuing to render indefinitely, the emergency shutoff above will trigger
- // and the test will fail since the regular time will be constantly reset.
- timer.start(1s, 0s, [&] {
- util::RunLoop::Get()->stop();
- });
- }
- BackendScope scope2(backend);
- map.render(view);
- }};
+ HeadlessFrontend frontend(pixelRatio, fileSource, threadPool);
- backend.callback = [&] {
- render.send();
+ StubMapObserver observer;
+ observer.didFinishRenderingFrame = [&] (MapObserver::RenderMode) {
+ // Start a timer that ends the test one second from now. If we are continuing to render
+ // indefinitely, the timer will be constantly restarted and never trigger. Instead, the
+ // emergency shutoff above will trigger, failing the test.
+ timer.start(1s, 0s, [&] {
+ runLoop.stop();
+ });
};
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
- util::RunLoop::Get()->run();
+ Map map(frontend, observer, frontend.getSize(), pixelRatio, fileSource, threadPool, MapMode::Continuous);
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
+
+ runLoop.run();
+}
+
+TEST(Map, NoContentTiles) {
+ MapTest<DefaultFileSource> test {":memory:", "."};
+
+ using namespace std::chrono_literals;
+
+ // Insert a 204 No Content response for the 0/0/0 tile
+ Response response;
+ response.noContent = true;
+ response.expires = util::now() + 1h;
+ test.fileSource.put(Resource::tile("http://example.com/{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0,
+ Tileset::Scheme::XYZ),
+ response);
+
+ test.map.getStyle().loadJSON(R"STYLE({
+ "version": 8,
+ "name": "Water",
+ "sources": {
+ "mapbox": {
+ "type": "vector",
+ "tiles": ["http://example.com/{z}-{x}-{y}.vector.pbf"]
+ }
+ },
+ "layers": [{
+ "id": "background",
+ "type": "background",
+ "paint": {
+ "background-color": "red"
+ }
+ }, {
+ "id": "water",
+ "type": "fill",
+ "source": "mapbox",
+ "source-layer": "water"
+ }]
+ })STYLE");
+
+ test::checkImage("test/fixtures/map/nocontent",
+ test.frontend.render(test.map),
+ 0.0015,
+ 0.1);
}
diff --git a/test/map/prefetch.test.cpp b/test/map/prefetch.test.cpp
new file mode 100644
index 0000000000..5c9a22d1bf
--- /dev/null
+++ b/test/map/prefetch.test.cpp
@@ -0,0 +1,89 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_file_source.hpp>
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+using namespace mbgl;
+using namespace mbgl::style;
+using namespace std::literals::string_literals;
+
+TEST(Map, PrefetchTiles) {
+ util::RunLoop runLoop;
+ ThreadPool threadPool(4);
+ StubFileSource fileSource;
+ HeadlessFrontend frontend { { 512, 512 }, 1, fileSource, threadPool };
+ Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), 1, fileSource, threadPool, MapMode::Still);
+
+ std::vector<int> tiles;
+
+ fileSource.response = [&] (const Resource& res) -> optional<Response> {
+ Response response;
+
+ auto zoom = std::stoi(res.url);
+ tiles.push_back(zoom);
+
+ // Return a red tile for prefetched tiles or green to the actual tile.
+ // The end rendering result should be all green because the map is only
+ // considered fully rendered when only ideal tiles are shown.
+ if (zoom == int(map.getZoom()) + 1) {
+ response.data = std::make_shared<std::string>(
+ util::read_file("test/fixtures/map/prefetch/tile_green.png"));
+ } else {
+ response.data = std::make_shared<std::string>(
+ util::read_file("test/fixtures/map/prefetch/tile_red.png"));
+ }
+
+ return { std::move(response) };
+ };
+
+ auto checkTilesForZoom = [&](int zoom, const std::vector<int>& expected) {
+ tiles.clear();
+
+ // Force tile reloading.
+ map.getStyle().loadJSON(util::read_file("test/fixtures/map/prefetch/empty.json"));
+ map.getStyle().loadJSON(util::read_file("test/fixtures/map/prefetch/style.json"));
+
+ map.setLatLngZoom({ 40.726989, -73.992857 }, zoom); // Manhattan
+
+ // Should always render the ideal tiles (i.e. a green map)
+ test::checkImage("test/fixtures/map/prefetch", frontend.render(map));
+
+ ASSERT_TRUE(std::is_permutation(tiles.begin(), tiles.end(), expected.begin()));
+ ASSERT_FALSE(tiles.empty());
+ };
+
+ // Check defaults, should be 4.
+ ASSERT_EQ(map.getPrefetchZoomDelta(), 4);
+ checkTilesForZoom(12, { 13, 13, 13, 13, 13, 13, 13, 13, 13, 9 });
+
+ // Setting it to 0 disables prefetching.
+ map.setPrefetchZoomDelta(0);
+
+ // No prefetching, raster tiles will use ideal
+ // tiles instead of the actual zoom level, that is
+ // why the zoom levels for non-prefetched tiles are
+ // not the same.
+ checkTilesForZoom(10, { 11, 11, 11, 11, 11, 11, 11, 11, 11 });
+
+ map.setPrefetchZoomDelta(5);
+ checkTilesForZoom(12, { 13, 13, 13, 13, 13, 13, 13, 13, 13, 8 });
+
+ // Should clamp at `minzoom`.
+ map.setPrefetchZoomDelta(20);
+ checkTilesForZoom(10, { 11, 11, 11, 11, 11, 11, 11, 11, 11, 0 });
+
+ // Disabled again.
+ map.setPrefetchZoomDelta(0);
+ checkTilesForZoom(13, { 14, 14, 14, 14, 14, 14, 14, 14, 14 });
+}
diff --git a/test/map/transform.test.cpp b/test/map/transform.test.cpp
index aa49d250b6..11c2c1cc6b 100644
--- a/test/map/transform.test.cpp
+++ b/test/map/transform.test.cpp
@@ -28,6 +28,27 @@ TEST(Transform, InvalidZoom) {
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude());
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude());
ASSERT_DOUBLE_EQ(1, transform.getZoom());
+
+ transform.setZoom(transform.getState().getMaxZoom() + 0.1);
+ ASSERT_DOUBLE_EQ(transform.getZoom(), transform.getState().getMaxZoom());
+
+ CameraOptions cameraOptions;
+ cameraOptions.center = LatLng { util::LATITUDE_MAX, util::LONGITUDE_MAX };
+ cameraOptions.zoom = transform.getState().getMaxZoom();
+
+ // Executing flyTo with an empty size causes frameZoom to be NaN.
+ transform.flyTo(cameraOptions);
+ transform.updateTransitions(transform.getTransitionStart() + transform.getTransitionDuration());
+ ASSERT_DOUBLE_EQ(transform.getZoom(), transform.getState().getMaxZoom());
+
+ // Executing flyTo with maximum zoom level to the same zoom level causes
+ // frameZoom to be bigger than maximum zoom.
+ transform.resize(Size { 100, 100 });
+ transform.flyTo(cameraOptions);
+ transform.updateTransitions(transform.getTransitionStart() + transform.getTransitionDuration());
+
+ ASSERT_TRUE(transform.getState().valid());
+ ASSERT_DOUBLE_EQ(transform.getState().getMaxZoom(), transform.getZoom());
}
diff --git a/test/programs/symbol_program.test.cpp b/test/programs/symbol_program.test.cpp
new file mode 100644
index 0000000000..62a2e58d7b
--- /dev/null
+++ b/test/programs/symbol_program.test.cpp
@@ -0,0 +1,57 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/programs/symbol_program.hpp>
+
+using namespace mbgl;
+
+TEST(SymbolProgram, SymbolSizeBinder) {
+ auto binder = SymbolSizeBinder::create(5.0f, 12.0f, 0.0f);
+ auto uniformValues = binder->uniformValues(5.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_size>().t, 12.0f);
+
+ binder = SymbolSizeBinder::create(1.0f, style::CameraFunction<float>(style::ExponentialStops<float>({
+ {0.0f, 8.0f},
+ {10.0f, 18.0f}
+ }, 1.0f)), 0.0f);
+ uniformValues = binder->uniformValues(1.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, false);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_size>().t, 9.5f);
+
+ binder = SymbolSizeBinder::create(0.0f, style::CameraFunction<float>(style::ExponentialStops<float>({
+ {1.0f, 8.0f},
+ {11.0f, 18.0f}
+ }, 1.0f)), 0.0f);
+ uniformValues = binder->uniformValues(0.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, false);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_size>().t, 8.0f);
+
+ binder = SymbolSizeBinder::create(12.0f, style::CameraFunction<float>(style::ExponentialStops<float>({
+ {1.0f, 8.0f},
+ {11.0f, 18.0f}
+ }, 1.0f)), 0.0f);
+ uniformValues = binder->uniformValues(12.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, false);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_size>().t, 18.0f);
+
+ binder = SymbolSizeBinder::create(0.0f, style::SourceFunction<float>("x", style::ExponentialStops<float>({
+ {1.0f, 8.0f},
+ {11.0f, 18.0f}
+ }, 1.0f)), 0.0f);
+ uniformValues = binder->uniformValues(12.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, true);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, false);
+
+ binder = SymbolSizeBinder::create(5.0f, style::CompositeFunction<float>("x", style::CompositeExponentialStops<float>({
+ {1.0f, {{0.0f, 8.0f}, {100.0f, 18.0f}}},
+ {11.0f, {{0.0f, 12.0f}, {100.0f, 24.9f}}}
+ }, 1.0f)), 0.0f);
+ uniformValues = binder->uniformValues(5.5f);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>().t, false);
+ EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>().t, false);
+ EXPECT_EQ(uniformValues.get<uniforms::u_size_t>().t, 0.45f);
+}
diff --git a/test/renderer/backend_scope.test.cpp b/test/renderer/backend_scope.test.cpp
index 6afd8f12ed..66cf88a9c6 100644
--- a/test/renderer/backend_scope.test.cpp
+++ b/test/renderer/backend_scope.test.cpp
@@ -1,14 +1,20 @@
#include <mbgl/test/util.hpp>
-#include <mbgl/map/backend.hpp>
-#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
#include <functional>
using namespace mbgl;
-class StubBackend: public Backend {
+class StubRendererBackend: public RendererBackend {
public:
+ void bind() override {
+ }
+
+ mbgl::Size getFramebufferSize() const override {
+ return mbgl::Size{};
+ }
void activate() override {
if (activateFunction) activateFunction();
@@ -22,8 +28,6 @@ public:
if (updateAssumedStateFunction) updateAssumedStateFunction();
}
- void invalidate() override {}
-
gl::ProcAddress initializeExtension(const char* ext) override {
if (initializeExtensionFunction) {
return initializeExtensionFunction(ext);
@@ -45,7 +49,7 @@ TEST(BackendScope, SingleScope) {
bool activated;
bool deactivated;
- StubBackend backend;
+ StubRendererBackend backend;
backend.activateFunction = [&] { activated = true; };
backend.deactivateFunction = [&] { deactivated = true; };
@@ -63,7 +67,7 @@ TEST(BackendScope, NestedScopes) {
int activated = 0;
int deactivated = 0;
- StubBackend backend;
+ StubRendererBackend backend;
backend.activateFunction = [&] { activated++; };
backend.deactivateFunction = [&] { deactivated++; };
@@ -87,15 +91,15 @@ TEST(BackendScope, NestedScopes) {
TEST(BackendScope, ChainedScopes) {
bool activatedA = false;
bool activatedB = false;
-
- StubBackend backendA;
+
+ StubRendererBackend backendA;
backendA.activateFunction = [&] { activatedA = true; };
backendA.deactivateFunction = [&] { activatedA = false; };
-
- StubBackend backendB;
+
+ StubRendererBackend backendB;
backendB.activateFunction = [&] { activatedB = true; };
backendB.deactivateFunction = [&] { activatedB = false; };
-
+
{
BackendScope scopeA { backendA };
ASSERT_TRUE(activatedA);
@@ -107,7 +111,7 @@ TEST(BackendScope, ChainedScopes) {
ASSERT_FALSE(activatedB);
ASSERT_TRUE(activatedA);
}
-
+
ASSERT_FALSE(activatedA);
ASSERT_FALSE(activatedB);
}
diff --git a/test/renderer/group_by_layout.test.cpp b/test/renderer/group_by_layout.test.cpp
index 9c8e09e222..958f1bdf24 100644
--- a/test/renderer/group_by_layout.test.cpp
+++ b/test/renderer/group_by_layout.test.cpp
@@ -13,7 +13,7 @@ static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vecto
std::vector<std::unique_ptr<RenderLayer>> result;
result.reserve(layers.size());
for (auto& layer : layers) {
- result.push_back(layer->baseImpl->createRenderLayer());
+ result.push_back(RenderLayer::create(layer->baseImpl));
}
return result;
}
diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp
new file mode 100644
index 0000000000..ebe1bcd72f
--- /dev/null
+++ b/test/renderer/image_manager.test.cpp
@@ -0,0 +1,150 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/fixture_log_observer.hpp>
+#include <mbgl/test/stub_file_source.hpp>
+#include <mbgl/test/stub_style_observer.hpp>
+
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/sprite/sprite_parser.hpp>
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <utility>
+
+using namespace mbgl;
+
+TEST(ImageManager, Missing) {
+ ImageManager imageManager;
+ EXPECT_FALSE(imageManager.getImage("doesnotexist"));
+}
+
+TEST(ImageManager, Basic) {
+ FixtureLog log;
+ ImageManager imageManager;
+
+ auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
+ util::read_file("test/fixtures/annotations/emerald.json"));
+ for (auto& image : images) {
+ imageManager.addImage(image->baseImpl);
+ }
+
+ auto metro = *imageManager.getPattern("metro");
+ EXPECT_EQ(1, metro.tl()[0]);
+ EXPECT_EQ(1, metro.tl()[1]);
+ EXPECT_EQ(19, metro.br()[0]);
+ EXPECT_EQ(19, metro.br()[1]);
+ EXPECT_EQ(18, metro.displaySize()[0]);
+ EXPECT_EQ(18, metro.displaySize()[1]);
+ EXPECT_EQ(1.0f, metro.pixelRatio);
+ EXPECT_EQ(imageManager.getPixelSize(), imageManager.getAtlasImage().size);
+
+ test::checkImage("test/fixtures/image_manager/basic", imageManager.getAtlasImage());
+}
+
+TEST(ImageManager, Updates) {
+ ImageManager imageManager;
+
+ PremultipliedImage imageA({ 16, 12 });
+ imageA.fill(255);
+ imageManager.addImage(makeMutable<style::Image::Impl>("one", std::move(imageA), 1));
+
+ auto a = *imageManager.getPattern("one");
+ EXPECT_EQ(1, a.tl()[0]);
+ EXPECT_EQ(1, a.tl()[1]);
+ EXPECT_EQ(17, a.br()[0]);
+ EXPECT_EQ(13, a.br()[1]);
+ EXPECT_EQ(16, a.displaySize()[0]);
+ EXPECT_EQ(12, a.displaySize()[1]);
+ EXPECT_EQ(1.0f, a.pixelRatio);
+ test::checkImage("test/fixtures/image_manager/updates_before", imageManager.getAtlasImage());
+
+ PremultipliedImage imageB({ 5, 5 });
+ imageA.fill(200);
+ imageManager.updateImage(makeMutable<style::Image::Impl>("one", std::move(imageB), 1));
+
+ auto b = *imageManager.getPattern("one");
+ EXPECT_EQ(1, b.tl()[0]);
+ EXPECT_EQ(1, b.tl()[1]);
+ EXPECT_EQ(6, b.br()[0]);
+ EXPECT_EQ(6, b.br()[1]);
+ EXPECT_EQ(5, b.displaySize()[0]);
+ EXPECT_EQ(5, b.displaySize()[1]);
+ EXPECT_EQ(1.0f, b.pixelRatio);
+ test::checkImage("test/fixtures/image_manager/updates_after", imageManager.getAtlasImage());
+}
+
+TEST(ImageManager, AddRemove) {
+ FixtureLog log;
+ ImageManager imageManager;
+
+ imageManager.addImage(makeMutable<style::Image::Impl>("one", PremultipliedImage({ 16, 16 }), 2));
+ imageManager.addImage(makeMutable<style::Image::Impl>("two", PremultipliedImage({ 16, 16 }), 2));
+ imageManager.addImage(makeMutable<style::Image::Impl>("three", PremultipliedImage({ 16, 16 }), 2));
+
+ imageManager.removeImage("one");
+ imageManager.removeImage("two");
+
+ EXPECT_NE(nullptr, imageManager.getImage("three"));
+ EXPECT_EQ(nullptr, imageManager.getImage("two"));
+ EXPECT_EQ(nullptr, imageManager.getImage("four"));
+}
+
+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());
+}
+
+class StubImageRequestor : public ImageRequestor {
+public:
+ void onImagesAvailable(ImageMap images, uint64_t imageCorrelationID_) final {
+ if (imagesAvailable && imageCorrelationID == imageCorrelationID_) imagesAvailable(images);
+ }
+
+ std::function<void (ImageMap)> imagesAvailable;
+ uint64_t imageCorrelationID = 0;
+};
+
+TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) {
+ ImageManager imageManager;
+ StubImageRequestor requestor;
+ bool notified = false;
+
+ requestor.imagesAvailable = [&] (ImageMap) {
+ notified = true;
+ };
+
+ uint64_t imageCorrelationID = 0;
+ imageManager.getImages(requestor, std::make_pair(std::set<std::string> {"one"}, imageCorrelationID));
+ ASSERT_FALSE(notified);
+
+ imageManager.setLoaded(true);
+ ASSERT_TRUE(notified);
+}
+
+TEST(ImageManager, NotifiesRequestorImmediatelyIfDependenciesAreSatisfied) {
+ ImageManager imageManager;
+ StubImageRequestor requestor;
+ bool notified = false;
+
+ requestor.imagesAvailable = [&] (ImageMap) {
+ notified = true;
+ };
+
+ uint64_t imageCorrelationID = 0;
+ imageManager.addImage(makeMutable<style::Image::Impl>("one", PremultipliedImage({ 16, 16 }), 2));
+ imageManager.getImages(requestor, std::make_pair(std::set<std::string> {"one"}, imageCorrelationID));
+
+ ASSERT_TRUE(notified);
+}
diff --git a/test/sprite/sprite_atlas.test.cpp b/test/sprite/sprite_atlas.test.cpp
deleted file mode 100644
index 08388f0a93..0000000000
--- a/test/sprite/sprite_atlas.test.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-#include <mbgl/test/util.hpp>
-#include <mbgl/test/fixture_log_observer.hpp>
-#include <mbgl/test/stub_file_source.hpp>
-#include <mbgl/test/stub_style_observer.hpp>
-
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/sprite/sprite_parser.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/default_thread_pool.hpp>
-#include <mbgl/util/string.hpp>
-
-#include <utility>
-
-using namespace mbgl;
-
-TEST(SpriteAtlas, Basic) {
- FixtureLog log;
- SpriteAtlas atlas({ 63, 112 }, 1);
-
- auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
- util::read_file("test/fixtures/annotations/emerald.json"));
- for (auto& pair : images) {
- atlas.addImage(pair.first, std::move(pair.second));
- }
-
- EXPECT_EQ(1.0f, atlas.getPixelRatio());
- EXPECT_EQ(63u, atlas.getSize().width);
- EXPECT_EQ(112u, atlas.getSize().height);
-
- auto metro = *atlas.getIcon("metro");
- float imagePixelRatio = metro.relativePixelRatio * atlas.getPixelRatio();
- 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.width);
- EXPECT_EQ(18, metro.height);
- EXPECT_EQ(18u, metro.width * imagePixelRatio);
- EXPECT_EQ(18u, metro.height * imagePixelRatio);
- EXPECT_EQ(1.0f, imagePixelRatio);
-
-
- EXPECT_EQ(63u, atlas.getAtlasImage().size.width);
- EXPECT_EQ(112u, atlas.getAtlasImage().size.height);
-
- auto pos = *atlas.getIcon("metro");
- 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.getIcon("doesnotexist");
- 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.getPattern("metro");
- EXPECT_EQ(20, metro2.pos.x);
- EXPECT_EQ(0, metro2.pos.y);
- EXPECT_EQ(20, metro2.pos.w);
- EXPECT_EQ(20, metro2.pos.h);
-
- test::checkImage("test/fixtures/sprite_atlas/basic", atlas.getAtlasImage());
-}
-
-TEST(SpriteAtlas, Size) {
- SpriteAtlas atlas({ 63, 112 }, 1.4);
-
- auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
- util::read_file("test/fixtures/annotations/emerald.json"));
- for (auto& pair : images) {
- atlas.addImage(pair.first, std::move(pair.second));
- }
-
- EXPECT_DOUBLE_EQ(1.4f, atlas.getPixelRatio());
- EXPECT_EQ(63u, atlas.getSize().width);
- EXPECT_EQ(112u, atlas.getSize().height);
-
- auto metro = *atlas.getIcon("metro");
- float imagePixelRatio = metro.relativePixelRatio * atlas.getPixelRatio();
- EXPECT_EQ(0, metro.pos.x);
- EXPECT_EQ(0, metro.pos.y);
- EXPECT_EQ(16, metro.pos.w);
- EXPECT_EQ(16, metro.pos.h);
- EXPECT_EQ(18, metro.width);
- EXPECT_EQ(18, metro.height);
- EXPECT_EQ(18u, metro.width * imagePixelRatio);
- EXPECT_EQ(18u, metro.height * imagePixelRatio);
- EXPECT_EQ(1.0f, imagePixelRatio);
-
- // Now the image was created lazily.
- EXPECT_EQ(89u, atlas.getAtlasImage().size.width);
- EXPECT_EQ(157u, atlas.getAtlasImage().size.height);
-
- test::checkImage("test/fixtures/sprite_atlas/size", atlas.getAtlasImage());
-}
-
-TEST(SpriteAtlas, Updates) {
- SpriteAtlas atlas({ 32, 32 }, 1);
-
- EXPECT_EQ(1.0f, atlas.getPixelRatio());
- EXPECT_EQ(32u, atlas.getSize().width);
- EXPECT_EQ(32u, atlas.getSize().height);
-
- atlas.addImage("one", std::make_unique<style::Image>(PremultipliedImage({ 16, 12 }), 1));
- auto one = *atlas.getIcon("one");
- float imagePixelRatio = one.relativePixelRatio * atlas.getPixelRatio();
- EXPECT_EQ(0, one.pos.x);
- EXPECT_EQ(0, one.pos.y);
- EXPECT_EQ(20, one.pos.w);
- EXPECT_EQ(16, one.pos.h);
- EXPECT_EQ(16, one.width);
- EXPECT_EQ(12, one.height);
- EXPECT_EQ(16u, one.width * imagePixelRatio);
- EXPECT_EQ(12u, one.height * imagePixelRatio);
- EXPECT_EQ(1.0f, imagePixelRatio);
-
- // Now the image was created lazily.
- EXPECT_EQ(32u, atlas.getAtlasImage().size.width);
- EXPECT_EQ(32u, atlas.getAtlasImage().size.height);
-
- test::checkImage("test/fixtures/sprite_atlas/updates_before", atlas.getAtlasImage());
-
- // Update image
- PremultipliedImage image2({ 16, 12 });
- for (size_t i = 0; i < image2.bytes(); i++) {
- image2.data.get()[i] = 255;
- }
- atlas.addImage("one", std::make_unique<style::Image>(std::move(image2), 1));
-
- test::checkImage("test/fixtures/sprite_atlas/updates_after", atlas.getAtlasImage());
-}
-
-TEST(SpriteAtlas, AddRemove) {
- FixtureLog log;
- SpriteAtlas atlas({ 32, 32 }, 1);
-
- atlas.addImage("one", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
- atlas.addImage("two", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
- atlas.addImage("three", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
-
- atlas.removeImage("one");
- atlas.removeImage("two");
-
- EXPECT_NE(nullptr, atlas.getImage("three"));
- EXPECT_EQ(nullptr, atlas.getImage("two"));
- EXPECT_EQ(nullptr, atlas.getImage("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'",
- }));
-}
-
-TEST(SpriteAtlas, RemoveReleasesBinPackRect) {
- FixtureLog log;
-
- SpriteAtlas atlas({ 36, 36 }, 1);
-
- atlas.addImage("big", std::make_unique<style::Image>(PremultipliedImage({ 32, 32 }), 1));
- EXPECT_TRUE(atlas.getIcon("big"));
-
- atlas.removeImage("big");
-
- atlas.addImage("big", std::make_unique<style::Image>(PremultipliedImage({ 32, 32 }), 1));
- EXPECT_TRUE(atlas.getIcon("big"));
- EXPECT_TRUE(log.empty());
-}
-
-TEST(SpriteAtlas, OtherPixelRatio) {
- FixtureLog log;
- SpriteAtlas atlas({ 32, 32 }, 1);
-
- // Adding mismatched sprite image
- atlas.addImage("one", std::make_unique<style::Image>(PremultipliedImage({ 8, 8 }), 2));
-}
-
-TEST(SpriteAtlas, Replace) {
- FixtureLog log;
- SpriteAtlas atlas({ 32, 32 }, 1);
-
- atlas.addImage("sprite", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
- auto image = atlas.getImage("sprite");
- atlas.addImage("sprite", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
- EXPECT_NE(image, atlas.getImage("sprite"));
-}
-
-TEST(SpriteAtlas, ReplaceWithDifferentDimensions) {
- FixtureLog log;
- SpriteAtlas atlas({ 32, 32 }, 1);
-
- atlas.addImage("sprite", std::make_unique<style::Image>(PremultipliedImage({ 16, 16 }), 2));
- atlas.addImage("sprite", std::make_unique<style::Image>(PremultipliedImage({ 18, 18 }), 2));
-
- EXPECT_EQ(1u, log.count({
- EventSeverity::Warning,
- Event::Sprite,
- int64_t(-1),
- "Can't change sprite dimensions for 'sprite'",
- }));
-}
-
-class SpriteAtlasTest {
-public:
- SpriteAtlasTest() = default;
-
- util::RunLoop loop;
- StubFileSource fileSource;
- StubStyleObserver observer;
- ThreadPool threadPool { 1 };
- SpriteAtlas spriteAtlas{ { 32, 32 }, 1 };
-
- void run() {
- // Squelch logging.
- Log::setObserver(std::make_unique<Log::NullObserver>());
-
- spriteAtlas.setObserver(&observer);
- spriteAtlas.load("test/fixtures/resources/sprite", threadPool, fileSource);
-
- loop.run();
- }
-
- void end() {
- loop.stop();
- }
-};
-
-Response successfulSpriteImageResponse(const Resource& resource) {
- EXPECT_EQ("test/fixtures/resources/sprite.png", resource.url);
- Response response;
- response.data = std::make_unique<std::string>(util::read_file(resource.url));
- return response;
-}
-
-Response successfulSpriteJSONResponse(const Resource& resource) {
- EXPECT_EQ("test/fixtures/resources/sprite.json", resource.url);
- Response response;
- response.data = std::make_unique<std::string>(util::read_file(resource.url));
- return response;
-}
-
-Response failedSpriteResponse(const Resource&) {
- Response response;
- response.error = std::make_unique<Response::Error>(
- Response::Error::Reason::Other,
- "Failed by the test case");
- return response;
-}
-
-Response corruptSpriteResponse(const Resource&) {
- Response response;
- response.data = std::make_unique<std::string>("CORRUPT");
- return response;
-}
-
-TEST(SpriteAtlas, LoadingSuccess) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
- test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- FAIL() << util::toString(error);
- test.end();
- };
-
- test.observer.spriteLoaded = [&] () {
- EXPECT_EQ(1.0, test.spriteAtlas.getPixelRatio());
- EXPECT_TRUE(test.spriteAtlas.isLoaded());
- test.end();
- };
-
- test.run();
-}
-
-TEST(SpriteAtlas, JSONLoadingFail) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
- test.fileSource.spriteJSONResponse = failedSpriteResponse;
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_TRUE(error != nullptr);
- EXPECT_EQ("Failed by the test case", util::toString(error));
- EXPECT_FALSE(test.spriteAtlas.isLoaded());
- test.end();
- };
-
- test.run();
-}
-
-TEST(SpriteAtlas, ImageLoadingFail) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse = failedSpriteResponse;
- test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_TRUE(error != nullptr);
- EXPECT_EQ("Failed by the test case", util::toString(error));
- EXPECT_FALSE(test.spriteAtlas.isLoaded());
- test.end();
- };
-
- test.run();
-}
-
-TEST(SpriteAtlas, JSONLoadingCorrupted) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
- test.fileSource.spriteJSONResponse = corruptSpriteResponse;
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_TRUE(error != nullptr);
- EXPECT_EQ("Failed to parse JSON: Invalid value. at offset 0", util::toString(error));
- EXPECT_FALSE(test.spriteAtlas.isLoaded());
- test.end();
- };
-
- test.run();
-}
-
-TEST(SpriteAtlas, ImageLoadingCorrupted) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse = corruptSpriteResponse;
- test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_TRUE(error != nullptr);
- // Not asserting on platform-specific error text.
- EXPECT_FALSE(test.spriteAtlas.isLoaded());
- test.end();
- };
-
- test.run();
-}
-
-TEST(SpriteAtlas, LoadingCancel) {
- SpriteAtlasTest test;
-
- test.fileSource.spriteImageResponse =
- test.fileSource.spriteJSONResponse = [&] (const Resource&) {
- test.end();
- return optional<Response>();
- };
-
- test.observer.spriteLoaded = [&] () {
- FAIL() << "Should never be called";
- };
-
- test.run();
-}
diff --git a/test/sprite/sprite_loader.test.cpp b/test/sprite/sprite_loader.test.cpp
new file mode 100644
index 0000000000..3691572265
--- /dev/null
+++ b/test/sprite/sprite_loader.test.cpp
@@ -0,0 +1,179 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/fixture_log_observer.hpp>
+#include <mbgl/test/stub_file_source.hpp>
+
+#include <mbgl/sprite/sprite_loader.hpp>
+#include <mbgl/sprite/sprite_loader_observer.hpp>
+#include <mbgl/sprite/sprite_parser.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <utility>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+class StubSpriteLoaderObserver : public SpriteLoaderObserver {
+public:
+ void onSpriteLoaded(std::vector<std::unique_ptr<style::Image>>&& images) override {
+ if (spriteLoaded) spriteLoaded(std::move(images));
+ }
+
+ void onSpriteError(std::exception_ptr error) override {
+ if (spriteError) spriteError(error);
+ }
+
+ std::function<void (std::vector<std::unique_ptr<style::Image>>&&)> spriteLoaded;
+ std::function<void (std::exception_ptr)> spriteError;
+};
+
+class SpriteLoaderTest {
+public:
+ SpriteLoaderTest() = default;
+
+ util::RunLoop loop;
+ StubFileSource fileSource;
+ StubSpriteLoaderObserver observer;
+ ThreadPool threadPool { 1 };
+ SpriteLoader spriteLoader{ 1 };
+
+ void run() {
+ // Squelch logging.
+ Log::setObserver(std::make_unique<Log::NullObserver>());
+
+ spriteLoader.setObserver(&observer);
+ spriteLoader.load("test/fixtures/resources/sprite", threadPool, fileSource);
+
+ loop.run();
+ }
+
+ void end() {
+ loop.stop();
+ }
+};
+
+Response successfulSpriteImageResponse(const Resource& resource) {
+ EXPECT_EQ("test/fixtures/resources/sprite.png", resource.url);
+ Response response;
+ response.data = std::make_unique<std::string>(util::read_file(resource.url));
+ return response;
+}
+
+Response successfulSpriteJSONResponse(const Resource& resource) {
+ EXPECT_EQ("test/fixtures/resources/sprite.json", resource.url);
+ Response response;
+ response.data = std::make_unique<std::string>(util::read_file(resource.url));
+ return response;
+}
+
+Response failedSpriteResponse(const Resource&) {
+ Response response;
+ response.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other,
+ "Failed by the test case");
+ return response;
+}
+
+Response corruptSpriteResponse(const Resource&) {
+ Response response;
+ response.data = std::make_unique<std::string>("CORRUPT");
+ return response;
+}
+
+TEST(SpriteLoader, LoadingSuccess) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
+ test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
+
+ test.observer.spriteError = [&] (std::exception_ptr error) {
+ FAIL() << util::toString(error);
+ test.end();
+ };
+
+ test.observer.spriteLoaded = [&] (std::vector<std::unique_ptr<style::Image>>&& images) {
+ EXPECT_EQ(images.size(), 367u);
+ test.end();
+ };
+
+ test.run();
+}
+
+TEST(SpriteLoader, JSONLoadingFail) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
+ test.fileSource.spriteJSONResponse = failedSpriteResponse;
+
+ test.observer.spriteError = [&] (std::exception_ptr error) {
+ EXPECT_TRUE(error != nullptr);
+ EXPECT_EQ("Failed by the test case", util::toString(error));
+ test.end();
+ };
+
+ test.run();
+}
+
+TEST(SpriteLoader, ImageLoadingFail) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse = failedSpriteResponse;
+ test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
+
+ test.observer.spriteError = [&] (std::exception_ptr error) {
+ EXPECT_TRUE(error != nullptr);
+ EXPECT_EQ("Failed by the test case", util::toString(error));
+ test.end();
+ };
+
+ test.run();
+}
+
+TEST(SpriteLoader, JSONLoadingCorrupted) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse = successfulSpriteImageResponse;
+ test.fileSource.spriteJSONResponse = corruptSpriteResponse;
+
+ test.observer.spriteError = [&] (std::exception_ptr error) {
+ EXPECT_TRUE(error != nullptr);
+ EXPECT_EQ("Failed to parse JSON: Invalid value. at offset 0", util::toString(error));
+ test.end();
+ };
+
+ test.run();
+}
+
+TEST(SpriteLoader, ImageLoadingCorrupted) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse = corruptSpriteResponse;
+ test.fileSource.spriteJSONResponse = successfulSpriteJSONResponse;
+
+ test.observer.spriteError = [&] (std::exception_ptr error) {
+ EXPECT_TRUE(error != nullptr);
+ // Not asserting on platform-specific error text.
+ test.end();
+ };
+
+ test.run();
+}
+
+TEST(SpriteLoader, LoadingCancel) {
+ SpriteLoaderTest test;
+
+ test.fileSource.spriteImageResponse =
+ test.fileSource.spriteJSONResponse = [&] (const Resource&) {
+ test.end();
+ return optional<Response>();
+ };
+
+ test.observer.spriteLoaded = [&] (const std::vector<std::unique_ptr<style::Image>>&) {
+ FAIL() << "Should never be called";
+ };
+
+ test.run();
+}
diff --git a/test/sprite/sprite_parser.test.cpp b/test/sprite/sprite_parser.test.cpp
index bb8e71db95..529e4c75e8 100644
--- a/test/sprite/sprite_parser.test.cpp
+++ b/test/sprite/sprite_parser.test.cpp
@@ -27,19 +27,19 @@ TEST(Sprite, SpriteImageCreationInvalid) {
ASSERT_EQ(200u, image_1x.size.width);
ASSERT_EQ(299u, image_1x.size.height);
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 0, 16, 1, false)); // width == 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 16, 0, 1, false)); // height == 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, -1, 16, 1, false)); // width < 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 16, -1, 1, false)); // height < 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 1, 1, 0, false)); // ratio == 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 1, 1, -1, false)); // ratio < 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 1, 1, 23, false)); // ratio too large
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 2048, 16, 1, false)); // too wide
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 16, 1025, 1, false)); // too tall
- ASSERT_EQ(nullptr, createStyleImage(image_1x, -1, 0, 16, 16, 1, false)); // srcX < 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, -1, 16, 16, 1, false)); // srcY < 0
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, image_1x.size.width + 1, 16, 1, false)); // right edge out of bounds
- ASSERT_EQ(nullptr, createStyleImage(image_1x, 0, 0, 16, image_1x.size.height + 1, 1, false)); // bottom edge out of bounds
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 0, 16, 1, false)); // width == 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 16, 0, 1, false)); // height == 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, -1, 16, 1, false)); // width < 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 16, -1, 1, false)); // height < 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 1, 1, 0, false)); // ratio == 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 1, 1, -1, false)); // ratio < 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 1, 1, 23, false)); // ratio too large
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 2048, 16, 1, false)); // too wide
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 16, 1025, 1, false)); // too tall
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, -1, 0, 16, 16, 1, false)); // srcX < 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, -1, 16, 16, 1, false)); // srcY < 0
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, image_1x.size.width + 1, 16, 1, false)); // right edge out of bounds
+ ASSERT_EQ(nullptr, createStyleImage("test", image_1x, 0, 0, 16, image_1x.size.height + 1, 1, false)); // bottom edge out of bounds
EXPECT_EQ(1u, log.count({
EventSeverity::Error,
@@ -141,15 +141,13 @@ TEST(Sprite, SpriteImageCreation1x) {
ASSERT_EQ(299u, image_1x.size.height);
{ // "museum_icon":{"x":177,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false}
- const auto sprite = createStyleImage(image_1x, 177, 187, 18, 18, 1, false);
+ const auto sprite = createStyleImage("test", image_1x, 177, 187, 18, 18, 1, false);
ASSERT_TRUE(sprite.get());
- EXPECT_EQ(18, sprite->getWidth());
- EXPECT_EQ(18, sprite->getHeight());
- EXPECT_EQ(18u, sprite->image.size.width);
- EXPECT_EQ(18u, sprite->image.size.height);
- EXPECT_EQ(1, sprite->pixelRatio);
+ EXPECT_EQ(18u, sprite->getImage().size.width);
+ EXPECT_EQ(18u, sprite->getImage().size.height);
+ EXPECT_EQ(1, sprite->getPixelRatio());
EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteimagecreation1x-museum.png"),
- sprite->image);
+ sprite->getImage());
}
}
@@ -157,41 +155,35 @@ TEST(Sprite, SpriteImageCreation2x) {
const PremultipliedImage image_2x = decodeImage(util::read_file("test/fixtures/annotations/emerald@2x.png"));
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
- const auto sprite = createStyleImage(image_2x, 354, 374, 36, 36, 2, false);
+ const auto sprite = createStyleImage("test", image_2x, 354, 374, 36, 36, 2, false);
ASSERT_TRUE(sprite.get());
- EXPECT_EQ(18, sprite->getWidth());
- EXPECT_EQ(18, sprite->getHeight());
- EXPECT_EQ(36u, sprite->image.size.width);
- EXPECT_EQ(36u, sprite->image.size.height);
- EXPECT_EQ(2, sprite->pixelRatio);
+ EXPECT_EQ(36u, sprite->getImage().size.width);
+ EXPECT_EQ(36u, sprite->getImage().size.height);
+ EXPECT_EQ(2, sprite->getPixelRatio());
EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteimagecreation2x.png"),
- sprite->image);
+ sprite->getImage());
}
TEST(Sprite, SpriteImageCreation1_5x) {
const PremultipliedImage image_2x = decodeImage(util::read_file("test/fixtures/annotations/emerald@2x.png"));
// "museum_icon":{"x":354,"y":374,"width":36,"height":36,"pixelRatio":2,"sdf":false}
- const auto sprite = createStyleImage(image_2x, 354, 374, 36, 36, 1.5, false);
+ const auto sprite = createStyleImage("test", image_2x, 354, 374, 36, 36, 1.5, false);
ASSERT_TRUE(sprite.get());
- EXPECT_EQ(24, sprite->getWidth());
- EXPECT_EQ(24, sprite->getHeight());
- EXPECT_EQ(36u, sprite->image.size.width);
- EXPECT_EQ(36u, sprite->image.size.height);
- EXPECT_EQ(1.5, sprite->pixelRatio);
+ EXPECT_EQ(36u, sprite->getImage().size.width);
+ EXPECT_EQ(36u, sprite->getImage().size.height);
+ EXPECT_EQ(1.5, sprite->getPixelRatio());
EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteimagecreation1_5x-museum.png"),
- sprite->image);
+ sprite->getImage());
// "hospital_icon":{"x":314,"y":518,"width":36,"height":36,"pixelRatio":2,"sdf":false}
- const auto sprite2 = createStyleImage(image_2x, 314, 518, 35, 35, 1.5, false);
+ const auto sprite2 = createStyleImage("test", image_2x, 314, 518, 35, 35, 1.5, false);
ASSERT_TRUE(sprite2.get());
- EXPECT_EQ(float(35 / 1.5), sprite2->getWidth());
- EXPECT_EQ(float(35 / 1.5), sprite2->getHeight());
- EXPECT_EQ(35u, sprite2->image.size.width);
- EXPECT_EQ(35u, sprite2->image.size.height);
- EXPECT_EQ(1.5, sprite2->pixelRatio);
+ EXPECT_EQ(35u, sprite2->getImage().size.width);
+ EXPECT_EQ(35u, sprite2->getImage().size.height);
+ EXPECT_EQ(1.5, sprite2->getPixelRatio());
EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteimagecreation1_5x-hospital.png"),
- sprite2->image);
+ sprite2->getImage());
}
TEST(Sprite, SpriteParsing) {
@@ -202,7 +194,7 @@ TEST(Sprite, SpriteParsing) {
std::set<std::string> names;
std::transform(images.begin(), images.end(), std::inserter(names, names.begin()),
- [](const auto& pair) { return pair.first; });
+ [](const auto& image) { return image->getID(); });
EXPECT_EQ(std::set<std::string>({ "airfield_icon",
"airport_icon",
@@ -280,13 +272,11 @@ TEST(Sprite, SpriteParsing) {
names);
{
- auto& sprite = images.find("generic-metro")->second;
- EXPECT_EQ(18, sprite->getWidth());
- EXPECT_EQ(18, sprite->getHeight());
- EXPECT_EQ(18u, sprite->image.size.width);
- EXPECT_EQ(18u, sprite->image.size.height);
- EXPECT_EQ(1, sprite->pixelRatio);
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteparsing.png"), sprite->image);
+ auto& sprite = *std::find_if(images.begin(), images.end(), [] (const auto& image) { return image->getID() == "generic-metro"; });
+ EXPECT_EQ(18u, sprite->getImage().size.width);
+ EXPECT_EQ(18u, sprite->getImage().size.height);
+ EXPECT_EQ(1, sprite->getPixelRatio());
+ EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteparsing.png"), sprite->getImage());
}
}
diff --git a/test/src/mbgl/test/conversion_stubs.hpp b/test/src/mbgl/test/conversion_stubs.hpp
index e6581c5e53..30395ddb97 100644
--- a/test/src/mbgl/test/conversion_stubs.hpp
+++ b/test/src/mbgl/test/conversion_stubs.hpp
@@ -17,6 +17,7 @@ using ValueMap = std::unordered_map<std::string, Value>;
using ValueVector = std::vector<Value>;
class Value : public mbgl::variant<std::string,
float,
+ double,
bool,
mapbox::util::recursive_wrapper<ValueMap>,
mapbox::util::recursive_wrapper<ValueVector>> {
@@ -90,6 +91,14 @@ inline optional<float> toNumber(const Value& value) {
return {};
}
+
+inline optional<double> toDouble(const Value& value) {
+ if (value.is<double>()) {
+ return value.get<double>();
+ }
+ return {};
+}
+
inline optional<std::string> toString(const Value& value) {
if (value.is<std::string>()) {
return value.get<std::string>();
diff --git a/test/src/mbgl/test/fake_file_source.hpp b/test/src/mbgl/test/fake_file_source.hpp
index 3ed3f90a17..baae7f9b7e 100644
--- a/test/src/mbgl/test/fake_file_source.hpp
+++ b/test/src/mbgl/test/fake_file_source.hpp
@@ -42,8 +42,8 @@ public:
}
bool respond(Resource::Kind kind, const Response& response) {
- auto it = std::find_if(requests.begin(), requests.end(), [&] (FakeFileRequest* request) {
- return request->resource.kind == kind;
+ auto it = std::find_if(requests.begin(), requests.end(), [&] (FakeFileRequest* fakeRequest) {
+ return fakeRequest->resource.kind == kind;
});
if (it != requests.end()) {
diff --git a/test/src/mbgl/test/fixture_log_observer.cpp b/test/src/mbgl/test/fixture_log_observer.cpp
index fc0239bb1c..717d2da753 100644
--- a/test/src/mbgl/test/fixture_log_observer.cpp
+++ b/test/src/mbgl/test/fixture_log_observer.cpp
@@ -15,9 +15,6 @@ bool FixtureLog::Message::operator==(const Message& rhs) const {
return severity == rhs.severity && event == rhs.event && code == rhs.code && msg == rhs.msg;
}
-FixtureLog::Message::Message() : severity(), event(), code(), msg() {
-}
-
FixtureLog::Observer::Observer(FixtureLog* log_) : log(log_) {
}
@@ -97,10 +94,10 @@ std::vector<FixtureLog::Message> FixtureLogObserver::unchecked() const {
}
::std::ostream& operator<<(::std::ostream& os, const FixtureLog::Message& message) {
- os << "[\"" << Enum<EventSeverity>::toString(message.severity) << "\", \"";
- os << Enum<Event>::toString(message.event) << "\"";
+ os << R"([")" << Enum<EventSeverity>::toString(message.severity) << R"(", ")";
+ os << Enum<Event>::toString(message.event) << R"(")";
os << ", " << message.code;
- os << ", \"" << message.msg << "\"";
+ os << R"(, ")" << message.msg << R"(")";
return os << "]" << std::endl;
}
diff --git a/test/src/mbgl/test/fixture_log_observer.hpp b/test/src/mbgl/test/fixture_log_observer.hpp
index 96ddc2c54f..328d4753a8 100644
--- a/test/src/mbgl/test/fixture_log_observer.hpp
+++ b/test/src/mbgl/test/fixture_log_observer.hpp
@@ -12,15 +12,15 @@ namespace mbgl {
class FixtureLog {
public:
struct Message {
+ Message() = default;
Message(EventSeverity severity_, Event event_, int64_t code_, std::string msg_);
- Message();
bool operator==(const Message& rhs) const;
- const EventSeverity severity;
- const Event event;
- const int64_t code;
- const std::string msg;
+ const EventSeverity severity {};
+ const Event event {};
+ const int64_t code {};
+ const std::string msg {};
mutable bool checked = false;
};
diff --git a/test/src/mbgl/test/getrss.cpp b/test/src/mbgl/test/getrss.cpp
index 9f57ad8e7b..c21b653eaa 100644
--- a/test/src/mbgl/test/getrss.cpp
+++ b/test/src/mbgl/test/getrss.cpp
@@ -80,8 +80,8 @@ size_t getCurrentRSS( )
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
/* Linux ---------------------------------------------------- */
long rss = 0L;
- FILE* fp = NULL;
- if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
+ FILE* fp = nullptr;
+ if ( (fp = fopen( "/proc/self/statm", "r" )) == nullptr )
return (size_t)0L; /* Can't open? */
if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
{
diff --git a/test/src/mbgl/test/getrss.hpp b/test/src/mbgl/test/getrss.hpp
index a4420c4b5f..be45ae889a 100644
--- a/test/src/mbgl/test/getrss.hpp
+++ b/test/src/mbgl/test/getrss.hpp
@@ -41,5 +41,5 @@ size_t getPeakRSS();
*/
size_t getCurrentRSS();
-}
-}
+} // namespace test
+} // namespace mbgl
diff --git a/test/src/mbgl/test/stub_file_source.cpp b/test/src/mbgl/test/stub_file_source.cpp
index ec0545e88c..7891d5d907 100644
--- a/test/src/mbgl/test/stub_file_source.cpp
+++ b/test/src/mbgl/test/stub_file_source.cpp
@@ -77,6 +77,9 @@ optional<Response> StubFileSource::defaultResponse(const Resource& resource) {
case Resource::Kind::SpriteImage:
if (!spriteImageResponse) throw std::runtime_error("unexpected sprite image request");
return spriteImageResponse(resource);
+ case Resource::Kind::Image:
+ if (!imageResponse) throw std::runtime_error("unexpected image request");
+ return imageResponse(resource);
case Resource::Kind::Unknown:
throw std::runtime_error("unknown resource type");
}
diff --git a/test/src/mbgl/test/stub_file_source.hpp b/test/src/mbgl/test/stub_file_source.hpp
index ee4175cc3f..85118e1a77 100644
--- a/test/src/mbgl/test/stub_file_source.hpp
+++ b/test/src/mbgl/test/stub_file_source.hpp
@@ -29,6 +29,7 @@ public:
ResponseFunction glyphsResponse;
ResponseFunction spriteJSONResponse;
ResponseFunction spriteImageResponse;
+ ResponseFunction imageResponse;
private:
// The default behavior is to throw if no per-kind callback has been set.
diff --git a/test/src/mbgl/test/stub_geometry_tile_feature.hpp b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
index 21d198a96b..0164ab133c 100644
--- a/test/src/mbgl/test/stub_geometry_tile_feature.hpp
+++ b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
@@ -9,10 +9,17 @@ public:
: properties(std::move(properties_)) {
}
+ StubGeometryTileFeature(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_, PropertyMap properties_)
+ : properties(std::move(properties_)),
+ id(std::move(id_)),
+ type(type_),
+ geometry(std::move(geometry_)) {
+ }
+
PropertyMap properties;
- optional<FeatureIdentifier> id = {};
+ optional<FeatureIdentifier> id;
FeatureType type = FeatureType::Point;
- GeometryCollection geometry = {};
+ GeometryCollection geometry;
FeatureType getType() const override {
return type;
diff --git a/test/src/mbgl/test/stub_layer_observer.hpp b/test/src/mbgl/test/stub_layer_observer.hpp
index 9acd4b077a..0fa413aefe 100644
--- a/test/src/mbgl/test/stub_layer_observer.hpp
+++ b/test/src/mbgl/test/stub_layer_observer.hpp
@@ -10,29 +10,9 @@ using namespace mbgl::style;
*/
class StubLayerObserver : public style::LayerObserver {
public:
- void onLayerFilterChanged(Layer& layer) override {
- if (layerFilterChanged) layerFilterChanged(layer);
+ void onLayerChanged(Layer& layer) override {
+ if (layerChanged) layerChanged(layer);
}
- void onLayerVisibilityChanged(Layer& layer) override {
- if (layerVisibilityChanged) layerVisibilityChanged(layer);
- }
-
- void onLayerPaintPropertyChanged(Layer& layer) override {
- if (layerPaintPropertyChanged) layerPaintPropertyChanged(layer);
- }
-
- void onLayerDataDrivenPaintPropertyChanged(Layer& layer) override {
- if (layerDataDrivenPaintPropertyChanged) layerDataDrivenPaintPropertyChanged(layer);
- }
-
- void onLayerLayoutPropertyChanged(Layer& layer, const char * property) override {
- if (layerLayoutPropertyChanged) layerLayoutPropertyChanged(layer, property);
- }
-
- std::function<void (Layer&)> layerFilterChanged;
- std::function<void (Layer&)> layerVisibilityChanged;
- std::function<void (Layer&)> layerPaintPropertyChanged;
- std::function<void (Layer&)> layerDataDrivenPaintPropertyChanged;
- std::function<void (Layer&, const char *)> layerLayoutPropertyChanged;
+ std::function<void (Layer&)> layerChanged;
};
diff --git a/test/src/mbgl/test/stub_style_observer.hpp b/test/src/mbgl/test/stub_style_observer.hpp
index 7e22c68823..b97911cdb0 100644
--- a/test/src/mbgl/test/stub_style_observer.hpp
+++ b/test/src/mbgl/test/stub_style_observer.hpp
@@ -10,22 +10,6 @@ using namespace mbgl::style;
*/
class StubStyleObserver : public style::Observer {
public:
- void onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) override {
- if (glyphsLoaded) glyphsLoaded(fontStack, glyphRange);
- }
-
- void onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) override {
- if (glyphsError) glyphsError(fontStack, glyphRange, error);
- }
-
- void onSpriteLoaded() override {
- if (spriteLoaded) spriteLoaded();
- }
-
- void onSpriteError(std::exception_ptr error) override {
- if (spriteError) spriteError(error);
- }
-
void onSourceLoaded(Source& source) override {
if (sourceLoaded) sourceLoaded(source);
}
@@ -46,10 +30,6 @@ public:
if (resourceError) resourceError(error);
};
- std::function<void (const FontStack&, const GlyphRange&)> glyphsLoaded;
- std::function<void (const FontStack&, const GlyphRange&, std::exception_ptr)> glyphsError;
- std::function<void ()> spriteLoaded;
- std::function<void (std::exception_ptr)> spriteError;
std::function<void (Source&)> sourceLoaded;
std::function<void (Source&)> sourceChanged;
std::function<void (Source&, std::exception_ptr)> sourceError;
diff --git a/test/src/mbgl/test/util.cpp b/test/src/mbgl/test/util.cpp
index 7ca2d72504..028a0a9d51 100644
--- a/test/src/mbgl/test/util.cpp
+++ b/test/src/mbgl/test/util.cpp
@@ -1,13 +1,8 @@
#include <mbgl/test/util.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
-#include <mbgl/gl/headless_display.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
#include <mapbox/pixelmatch.hpp>
@@ -99,24 +94,6 @@ Server::~Server() {
}
}
-std::shared_ptr<HeadlessDisplay> sharedDisplay() {
- static auto display = std::make_shared<HeadlessDisplay>();
- return display;
-}
-
-PremultipliedImage render(Map& map, OffscreenView& view) {
- PremultipliedImage result;
- map.renderStill(view, [&](std::exception_ptr) {
- result = view.readStillImage();
- });
-
- while (!result.valid()) {
- util::RunLoop::Get()->runOnce();
- }
-
- return result;
-}
-
void checkImage(const std::string& base,
const PremultipliedImage& actual,
double imageThreshold,
diff --git a/test/src/mbgl/test/util.hpp b/test/src/mbgl/test/util.hpp
index 8673155fe4..7a8d78897e 100644
--- a/test/src/mbgl/test/util.hpp
+++ b/test/src/mbgl/test/util.hpp
@@ -54,11 +54,6 @@
#include <gtest/gtest.h>
namespace mbgl {
-
-class Map;
-class OffscreenView;
-class HeadlessDisplay;
-
namespace test {
class Server {
@@ -70,10 +65,6 @@ private:
int fd = -1;
};
-std::shared_ptr<HeadlessDisplay> sharedDisplay();
-
-PremultipliedImage render(Map&, OffscreenView&);
-
void checkImage(const std::string& base,
const PremultipliedImage& actual,
double imageThreshold = 0,
diff --git a/test/storage/asset_file_source.test.cpp b/test/storage/asset_file_source.test.cpp
index 010a2c9dc7..a39d2963d2 100644
--- a/test/storage/asset_file_source.test.cpp
+++ b/test/storage/asset_file_source.test.cpp
@@ -3,8 +3,10 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread.hpp>
+#include <mbgl/actor/actor_ref.hpp>
#include <gtest/gtest.h>
+#include <atomic>
using namespace mbgl;
@@ -20,16 +22,11 @@ TEST(AssetFileSource, Load) {
#else
unsigned numThreads = 50;
#endif
-
- auto callback = [&] {
- if (!--numThreads) {
- loop.stop();
- }
- };
+ std::atomic_uint completed(numThreads);
class TestWorker {
public:
- TestWorker(mbgl::AssetFileSource* fs_) : fs(fs_) {}
+ TestWorker(ActorRef<TestWorker>, mbgl::AssetFileSource* fs_) : fs(fs_) {}
void run(std::function<void()> endCallback) {
const std::string asset("asset://nonempty");
@@ -60,16 +57,12 @@ TEST(AssetFileSource, Load) {
};
std::vector<std::unique_ptr<util::Thread<TestWorker>>> threads;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
- util::ThreadContext context = { "Test" };
for (unsigned i = 0; i < numThreads; ++i) {
std::unique_ptr<util::Thread<TestWorker>> thread =
- std::make_unique<util::Thread<TestWorker>>(context, &fs);
-
- requests.push_back(
- thread->invokeWithCallback(&TestWorker::run, callback));
+ std::make_unique<util::Thread<TestWorker>>("Test", &fs);
+ thread->actor().invoke(&TestWorker::run, [&] { if (!--completed) loop.stop(); });
threads.push_back(std::move(thread));
}
diff --git a/test/storage/default_file_source.test.cpp b/test/storage/default_file_source.test.cpp
index 03f1076559..b5686b5ffe 100644
--- a/test/storage/default_file_source.test.cpp
+++ b/test/storage/default_file_source.test.cpp
@@ -1,5 +1,7 @@
+#include <mbgl/actor/actor.hpp>
#include <mbgl/test/util.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/run_loop.hpp>
using namespace mbgl;
@@ -20,6 +22,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheResponse)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response 1", *res.data);
EXPECT_TRUE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
response = res;
@@ -32,6 +35,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheResponse)) {
ASSERT_TRUE(res2.data.get());
EXPECT_EQ(*response.data, *res2.data);
EXPECT_EQ(response.expires, res2.expires);
+ EXPECT_EQ(response.mustRevalidate, res2.mustRevalidate);
EXPECT_EQ(response.modified, res2.modified);
EXPECT_EQ(response.etag, res2.etag);
@@ -49,35 +53,53 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateSame)) {
const Resource revalidateSame { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" };
std::unique_ptr<AsyncRequest> req1;
std::unique_ptr<AsyncRequest> req2;
- uint16_t counter = 0;
+ bool gotResponse = false;
// First request causes the response to get cached.
req1 = fs.request(revalidateSame, [&](Response res) {
req1.reset();
EXPECT_EQ(nullptr, res.error);
+ EXPECT_FALSE(res.notModified);
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_EQ("snowfall", *res.etag);
- // Second request returns the cached response, then immediately revalidates.
- req2 = fs.request(revalidateSame, [&, res](Response res2) {
- if (counter == 0) {
- ++counter;
+ // The first response is stored in the cache, but it has 'must-revalidate' set. This means
+ // it can't return the cached response right away and we must wait for the revalidation
+ // request to complete. We can distinguish the cached response from the revalided response
+ // because the latter has an expiration date, while the cached response doesn't.
+ req2 = fs.request(revalidateSame, [&](Response res2) {
+ if (!gotResponse) {
+ // Even though we could find the response in the database, we send a revalidation
+ // request and get a 304 response. Since we haven't sent a reply yet, we're forcing
+ // notModified to be false so that implementations can continue to use the
+ // notModified flag to skip parsing new data.
+ gotResponse = true;
+ EXPECT_EQ(nullptr, res2.error);
EXPECT_FALSE(res2.notModified);
+ ASSERT_TRUE(res2.data.get());
+ EXPECT_EQ("Response", *res2.data);
+ EXPECT_TRUE(bool(res2.expires));
+ EXPECT_TRUE(res2.mustRevalidate);
+ EXPECT_FALSE(bool(res2.modified));
+ EXPECT_EQ("snowfall", *res2.etag);
} else {
+ // The test server sends a Cache-Control header with a max-age of 1 second. This
+ // means that our OnlineFileSource implementation will request the tile again after
+ // 1 second. This time, our request already had a prior response, so we don't need
+ // to send the data again, and instead can actually forward the notModified flag.
req2.reset();
-
EXPECT_EQ(nullptr, res2.error);
EXPECT_TRUE(res2.notModified);
- ASSERT_FALSE(res2.data.get());
+ EXPECT_FALSE(res2.data.get());
EXPECT_TRUE(bool(res2.expires));
+ EXPECT_TRUE(res2.mustRevalidate);
EXPECT_FALSE(bool(res2.modified));
- // We're not sending the ETag in the 304 reply, but it should still be there.
EXPECT_EQ("snowfall", *res2.etag);
-
loop.stop();
}
});
@@ -94,34 +116,53 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateModified)) {
"http://127.0.0.1:3000/revalidate-modified" };
std::unique_ptr<AsyncRequest> req1;
std::unique_ptr<AsyncRequest> req2;
- uint16_t counter = 0;
+ bool gotResponse = false;
// First request causes the response to get cached.
req1 = fs.request(revalidateModified, [&](Response res) {
req1.reset();
EXPECT_EQ(nullptr, res.error);
+ EXPECT_FALSE(res.notModified);
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_EQ(Timestamp{ Seconds(1420070400) }, *res.modified);
EXPECT_FALSE(res.etag);
- // Second request returns the cached response, then immediately revalidates.
+ // The first response is stored in the cache, but it has 'must-revalidate' set. This means
+ // it can't return the cached response right away and we must wait for the revalidation
+ // request to complete. We can distinguish the cached response from the revalided response
+ // because the latter has an expiration date, while the cached response doesn't.
req2 = fs.request(revalidateModified, [&, res](Response res2) {
- if (counter == 0) {
- ++counter;
+ if (!gotResponse) {
+ // Even though we could find the response in the database, we send a revalidation
+ // request and get a 304 response. Since we haven't sent a reply yet, we're forcing
+ // notModified to be false so that implementations can continue to use the
+ // notModified flag to skip parsing new data.
+ gotResponse = true;
+ EXPECT_EQ(nullptr, res2.error);
EXPECT_FALSE(res2.notModified);
+ ASSERT_TRUE(res2.data.get());
+ EXPECT_EQ("Response", *res2.data);
+ EXPECT_TRUE(bool(res2.expires));
+ EXPECT_TRUE(res2.mustRevalidate);
+ EXPECT_EQ(Timestamp{ Seconds(1420070400) }, *res2.modified);
+ EXPECT_FALSE(res2.etag);
} else {
+ // The test server sends a Cache-Control header with a max-age of 1 second. This
+ // means that our OnlineFileSource implementation will request the tile again after
+ // 1 second. This time, our request already had a prior response, so we don't need
+ // to send the data again, and instead can actually forward the notModified flag.
req2.reset();
-
EXPECT_EQ(nullptr, res2.error);
EXPECT_TRUE(res2.notModified);
- ASSERT_FALSE(res2.data.get());
+ EXPECT_FALSE(res2.data.get());
EXPECT_TRUE(bool(res2.expires));
+ EXPECT_TRUE(res2.mustRevalidate);
EXPECT_EQ(Timestamp{ Seconds(1420070400) }, *res2.modified);
EXPECT_FALSE(res2.etag);
-
loop.stop();
}
});
@@ -137,7 +178,6 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) {
const Resource revalidateEtag { Resource::Unknown, "http://127.0.0.1:3000/revalidate-etag" };
std::unique_ptr<AsyncRequest> req1;
std::unique_ptr<AsyncRequest> req2;
- uint16_t counter = 0;
// First request causes the response to get cached.
req1 = fs.request(revalidateEtag, [&](Response res) {
@@ -147,27 +187,24 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response 1", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_EQ("response-1", *res.etag);
- // Second request returns the cached response, then immediately revalidates.
+ // Second request does not return the cached response, since it had Cache-Control: must-revalidate set.
req2 = fs.request(revalidateEtag, [&, res](Response res2) {
- if (counter == 0) {
- ++counter;
- EXPECT_FALSE(res2.notModified);
- } else {
- req2.reset();
+ req2.reset();
- EXPECT_EQ(nullptr, res2.error);
- ASSERT_TRUE(res2.data.get());
- EXPECT_NE(res.data, res2.data);
- EXPECT_EQ("Response 2", *res2.data);
- EXPECT_FALSE(bool(res2.expires));
- EXPECT_FALSE(bool(res2.modified));
- EXPECT_EQ("response-2", *res2.etag);
+ EXPECT_EQ(nullptr, res2.error);
+ ASSERT_TRUE(res2.data.get());
+ EXPECT_NE(res.data, res2.data);
+ EXPECT_EQ("Response 2", *res2.data);
+ EXPECT_FALSE(bool(res2.expires));
+ EXPECT_TRUE(res2.mustRevalidate);
+ EXPECT_FALSE(bool(res2.modified));
+ EXPECT_EQ("response-2", *res2.etag);
- loop.stop();
- }
+ loop.stop();
});
});
@@ -201,6 +238,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(HTTPIssue1369)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -230,6 +268,7 @@ TEST(DefaultFileSource, OptionalNonExpired) {
EXPECT_EQ("Cached value", *res.data);
ASSERT_TRUE(bool(res.expires));
EXPECT_EQ(*response.expires, *res.expires);
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -259,6 +298,7 @@ TEST(DefaultFileSource, OptionalExpired) {
EXPECT_EQ("Cached value", *res.data);
ASSERT_TRUE(bool(res.expires));
EXPECT_EQ(*response.expires, *res.expires);
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -299,6 +339,7 @@ TEST(DefaultFileSource, OptionalNotFound) {
EXPECT_EQ("Not found in offline database", res.error->message);
EXPECT_FALSE(res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -332,6 +373,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagNotModified)) {
EXPECT_FALSE(res.data.get());
ASSERT_TRUE(bool(res.expires));
EXPECT_LT(util::now(), *res.expires);
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
ASSERT_TRUE(bool(res.etag));
EXPECT_EQ("snowfall", *res.etag);
@@ -366,6 +408,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshEtagModified)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
ASSERT_TRUE(bool(res.etag));
EXPECT_EQ("snowfall", *res.etag);
@@ -401,6 +444,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheFull)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
ASSERT_TRUE(bool(res.etag));
EXPECT_EQ("snowfall", *res.etag);
@@ -435,6 +479,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedNotModified))
EXPECT_FALSE(res.data.get());
ASSERT_TRUE(bool(res.expires));
EXPECT_LT(util::now(), *res.expires);
+ EXPECT_TRUE(res.mustRevalidate);
ASSERT_TRUE(bool(res.modified));
EXPECT_EQ(Timestamp{ Seconds(1420070400) }, *res.modified);
EXPECT_FALSE(bool(res.etag));
@@ -469,6 +514,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedModified)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_TRUE(res.mustRevalidate);
EXPECT_EQ(Timestamp{ Seconds(1420070400) }, *res.modified);
EXPECT_FALSE(res.etag);
loop.stop();
@@ -482,7 +528,7 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(SetResourceTransform)) {
DefaultFileSource fs(":memory:", ".");
// Translates the URL "localhost://test to http://127.0.0.1:3000/test
- fs.setResourceTransform([](Resource::Kind, std::string&& url) -> std::string {
+ Actor<ResourceTransform> transform(loop, [](Resource::Kind, const std::string&& url) -> std::string {
if (url == "localhost://test") {
return "http://127.0.0.1:3000/test";
} else {
@@ -490,19 +536,116 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(SetResourceTransform)) {
}
});
- const Resource resource { Resource::Unknown, "localhost://test" };
+ fs.setResourceTransform(transform.self());
+ const Resource resource1 { Resource::Unknown, "localhost://test" };
std::unique_ptr<AsyncRequest> req;
- req = fs.request(resource, [&](Response res) {
+ req = fs.request(resource1, [&](Response res) {
req.reset();
EXPECT_EQ(nullptr, res.error);
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
});
loop.run();
+
+ fs.setResourceTransform({});
+ const Resource resource2 { Resource::Unknown, "http://127.0.0.1:3000/test" };
+
+ req = fs.request(resource2, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+// Test that a stale cache file that has must-revalidate set will trigger a response.
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(RespondToStaleMustRevalidate)) {
+ util::RunLoop loop;
+ DefaultFileSource fs(":memory:", ".");
+
+ Resource resource { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" };
+ resource.necessity = Resource::Necessity::Optional;
+
+ // using namespace std::chrono_literals;
+
+ // Put an existing value in the cache that has expired, and has must-revalidate set.
+ Response response;
+ response.data = std::make_shared<std::string>("Cached value");
+ response.modified = Timestamp(Seconds(1417392000)); // December 1, 2014
+ response.expires = Timestamp(Seconds(1417392000));
+ response.mustRevalidate = true;
+ response.etag.emplace("snowfall");
+ fs.put(resource, response);
+
+ std::unique_ptr<AsyncRequest> req;
+ req = fs.request(resource, [&](Response res) {
+ req.reset();
+ ASSERT_TRUE(res.error.get());
+ EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
+ EXPECT_EQ("Cached resource is unusable", res.error->message);
+ EXPECT_FALSE(res.notModified);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Cached value", *res.data);
+ ASSERT_TRUE(res.expires);
+ EXPECT_EQ(Timestamp{ Seconds(1417392000) }, *res.expires);
+ EXPECT_TRUE(res.mustRevalidate);
+ ASSERT_TRUE(res.modified);
+ EXPECT_EQ(Timestamp{ Seconds(1417392000) }, *res.modified);
+ ASSERT_TRUE(res.etag);
+ EXPECT_EQ("snowfall", *res.etag);
+
+ resource.priorEtag = res.etag;
+ resource.priorModified = res.modified;
+ resource.priorExpires = res.expires;
+ resource.priorData = res.data;
+
+ loop.stop();
+ });
+
+ loop.run();
+
+ // Now run this request again, with the data we gathered from the previous stale/unusable
+ // request. We're replacing the data so that we can check that the DefaultFileSource doesn't
+ // attempt another database access if we already have the value.
+ resource.necessity = Resource::Necessity::Required;
+ resource.priorData = std::make_shared<std::string>("Prior value");
+
+ req = fs.request(resource, [&](Response res) {
+ req.reset();
+ ASSERT_EQ(nullptr, res.error.get());
+ // Since the data was found in the cache, we're doing a revalidation request. Yet, since
+ // this request hasn't returned data before, we're setting notModified to false in the
+ // OnlineFileSource to ensure that requestors know that this is the first time they're
+ // seeing this data.
+ EXPECT_FALSE(res.notModified);
+ ASSERT_TRUE(res.data.get());
+ // Ensure that it's the value that we manually inserted into the cache rather than the value
+ // the server returns, since we should be executing a revalidation request which doesn't
+ // return new data, only a 304 Not Modified response.
+ EXPECT_EQ("Prior value", *res.data);
+ ASSERT_TRUE(res.expires);
+ EXPECT_LE(util::now(), *res.expires);
+ EXPECT_TRUE(res.mustRevalidate);
+ ASSERT_TRUE(res.modified);
+ EXPECT_EQ(Timestamp{ Seconds(1417392000) }, *res.modified);
+ ASSERT_TRUE(res.etag);
+ EXPECT_EQ("snowfall", *res.etag);
+ loop.stop();
+ });
+
+ loop.run();
}
diff --git a/test/storage/http_file_source.test.cpp b/test/storage/http_file_source.test.cpp
index 5b081d7d57..006b7a0fb3 100644
--- a/test/storage/http_file_source.test.cpp
+++ b/test/storage/http_file_source.test.cpp
@@ -26,6 +26,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP200)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -44,6 +45,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP404)) {
EXPECT_EQ("HTTP status code 404", res.error->message);
EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -61,6 +63,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTPTile404)) {
EXPECT_FALSE(bool(res.error));
EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -78,6 +81,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP200EmptyData)) {
EXPECT_FALSE(bool(res.error));
EXPECT_EQ(*res.data, std::string());
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -95,6 +99,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP204)) {
EXPECT_FALSE(bool(res.error));
EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -113,6 +118,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP500)) {
EXPECT_EQ("HTTP status code 500", res.error->message);
EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -131,6 +137,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(ExpiresParsing)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_EQ(Timestamp{ Seconds(1420797926) }, res.expires);
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_EQ(Timestamp{ Seconds(1420794326) }, res.modified);
EXPECT_EQ("foo", *res.etag);
loop.stop();
@@ -148,6 +155,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(CacheControlParsing)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_GT(Seconds(2), util::abs(*res.expires - util::now() - Seconds(120))) << "Expiration date isn't about 120 seconds in the future";
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -176,6 +184,7 @@ TEST(HTTPFileSource, TEST_REQUIRES_SERVER(Load)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
diff --git a/test/storage/local_file_source.test.cpp b/test/storage/local_file_source.test.cpp
index 1b90e5bb1e..4d509e6c7d 100644
--- a/test/storage/local_file_source.test.cpp
+++ b/test/storage/local_file_source.test.cpp
@@ -3,7 +3,7 @@
#include <mbgl/util/run_loop.hpp>
#include <unistd.h>
-#include <limits.h>
+#include <climits>
#include <gtest/gtest.h>
namespace {
diff --git a/test/storage/offline.test.cpp b/test/storage/offline.test.cpp
index 0faaabc298..e7ebe5199f 100644
--- a/test/storage/offline.test.cpp
+++ b/test/storage/offline.test.cpp
@@ -52,3 +52,11 @@ TEST(OfflineTilePyramidRegionDefinition, TileCoverWrapped) {
EXPECT_EQ((std::vector<CanonicalTileID>{ { 0, 0, 0 } }),
region.tileCover(SourceType::Vector, 512, { 0, 22 }));
}
+
+TEST(OfflineTilePyramidRegionDefinition, TileCount) {
+ OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 22, 1.0);
+
+ //These numbers match the count from tileCover().size().
+ EXPECT_EQ(38424u, region.tileCount(SourceType::Vector, 512, { 10, 18 }));
+ EXPECT_EQ(9675240u, region.tileCount(SourceType::Vector, 512, { 3, 22 }));
+}
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index fbf515679e..d99c1f946f 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -650,19 +650,19 @@ TEST(OfflineDatabase, MigrateFromV2Schema) {
// v2.db is a v2 database containing a single offline region with a small number of resources.
- deleteFile("test/fixtures/offline_database/v5.db");
- writeFile("test/fixtures/offline_database/v5.db", util::read_file("test/fixtures/offline_database/v2.db"));
+ deleteFile("test/fixtures/offline_database/migrated.db");
+ writeFile("test/fixtures/offline_database/migrated.db", util::read_file("test/fixtures/offline_database/v2.db"));
{
- OfflineDatabase db("test/fixtures/offline_database/v5.db", 0);
+ OfflineDatabase db("test/fixtures/offline_database/migrated.db", 0);
auto regions = db.listRegions();
for (auto& region : regions) {
db.deleteRegion(std::move(region));
}
}
- EXPECT_EQ(5, databaseUserVersion("test/fixtures/offline_database/v5.db"));
- EXPECT_LT(databasePageCount("test/fixtures/offline_database/v5.db"),
+ EXPECT_EQ(6, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
+ EXPECT_LT(databasePageCount("test/fixtures/offline_database/migrated.db"),
databasePageCount("test/fixtures/offline_database/v2.db"));
}
@@ -671,18 +671,18 @@ TEST(OfflineDatabase, MigrateFromV3Schema) {
// v3.db is a v3 database, migrated from v2.
- deleteFile("test/fixtures/offline_database/v5.db");
- writeFile("test/fixtures/offline_database/v5.db", util::read_file("test/fixtures/offline_database/v3.db"));
+ deleteFile("test/fixtures/offline_database/migrated.db");
+ writeFile("test/fixtures/offline_database/migrated.db", util::read_file("test/fixtures/offline_database/v3.db"));
{
- OfflineDatabase db("test/fixtures/offline_database/v5.db", 0);
+ OfflineDatabase db("test/fixtures/offline_database/migrated.db", 0);
auto regions = db.listRegions();
for (auto& region : regions) {
db.deleteRegion(std::move(region));
}
}
- EXPECT_EQ(5, databaseUserVersion("test/fixtures/offline_database/v5.db"));
+ EXPECT_EQ(6, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
}
TEST(OfflineDatabase, MigrateFromV4Schema) {
@@ -690,24 +690,52 @@ TEST(OfflineDatabase, MigrateFromV4Schema) {
// v4.db is a v4 database, migrated from v2 & v3. This database used `journal_mode = WAL` and `synchronous = NORMAL`.
- deleteFile("test/fixtures/offline_database/v5.db");
- writeFile("test/fixtures/offline_database/v5.db", util::read_file("test/fixtures/offline_database/v4.db"));
+ deleteFile("test/fixtures/offline_database/migrated.db");
+ writeFile("test/fixtures/offline_database/migrated.db", util::read_file("test/fixtures/offline_database/v4.db"));
{
- OfflineDatabase db("test/fixtures/offline_database/v5.db", 0);
+ OfflineDatabase db("test/fixtures/offline_database/migrated.db", 0);
auto regions = db.listRegions();
for (auto& region : regions) {
db.deleteRegion(std::move(region));
}
}
- EXPECT_EQ(5, databaseUserVersion("test/fixtures/offline_database/v5.db"));
+ EXPECT_EQ(6, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
// Journal mode should be DELETE after migration to v5.
- EXPECT_EQ("delete", databaseJournalMode("test/fixtures/offline_database/v5.db"));
+ EXPECT_EQ("delete", databaseJournalMode("test/fixtures/offline_database/migrated.db"));
// Synchronous setting should be FULL (2) after migration to v5.
- EXPECT_EQ(2, databaseSyncMode("test/fixtures/offline_database/v5.db"));
+ EXPECT_EQ(2, databaseSyncMode("test/fixtures/offline_database/migrated.db"));
+}
+
+
+TEST(OfflineDatabase, MigrateFromV5Schema) {
+ using namespace mbgl;
+
+ // v5.db is a v5 database, migrated from v2, v3 & v4.
+
+ deleteFile("test/fixtures/offline_database/migrated.db");
+ writeFile("test/fixtures/offline_database/migrated.db", util::read_file("test/fixtures/offline_database/v5.db"));
+
+ {
+ OfflineDatabase db("test/fixtures/offline_database/migrated.db", 0);
+ auto regions = db.listRegions();
+ for (auto& region : regions) {
+ db.deleteRegion(std::move(region));
+ }
+ }
+
+ EXPECT_EQ(6, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
+
+ EXPECT_EQ((std::vector<std::string>{ "id", "url_template", "pixel_ratio", "z", "x", "y",
+ "expires", "modified", "etag", "data", "compressed",
+ "accessed", "must_revalidate" }),
+ databaseTableColumns("test/fixtures/offline_database/migrated.db", "tiles"));
+ EXPECT_EQ((std::vector<std::string>{ "id", "url", "kind", "expires", "modified", "etag", "data",
+ "compressed", "accessed", "must_revalidate" }),
+ databaseTableColumns("test/fixtures/offline_database/migrated.db", "resources"));
}
TEST(OfflineDatabase, DowngradeSchema) {
@@ -723,13 +751,13 @@ TEST(OfflineDatabase, DowngradeSchema) {
OfflineDatabase db("test/fixtures/offline_database/migrated.db", 0);
}
- EXPECT_EQ(5, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
+ EXPECT_EQ(6, databaseUserVersion("test/fixtures/offline_database/migrated.db"));
EXPECT_EQ((std::vector<std::string>{ "id", "url_template", "pixel_ratio", "z", "x", "y",
"expires", "modified", "etag", "data", "compressed",
- "accessed" }),
+ "accessed", "must_revalidate" }),
databaseTableColumns("test/fixtures/offline_database/migrated.db", "tiles"));
EXPECT_EQ((std::vector<std::string>{ "id", "url", "kind", "expires", "modified", "etag", "data",
- "compressed", "accessed" }),
+ "compressed", "accessed", "must_revalidate" }),
databaseTableColumns("test/fixtures/offline_database/migrated.db", "resources"));
}
diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp
index 27e57771c8..57780eba40 100644
--- a/test/storage/offline_download.test.cpp
+++ b/test/storage/offline_download.test.cpp
@@ -191,6 +191,11 @@ TEST(OfflineDownload, Activate) {
return test.response("sprite.png");
};
+ test.fileSource.imageResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/radar.gif", resource.url);
+ return test.response("radar.gif");
+ };
+
test.fileSource.spriteJSONResponse = [&] (const Resource& resource) {
EXPECT_EQ("http://127.0.0.1:3000/sprite.json", resource.url);
return test.response("sprite.json");
@@ -219,7 +224,7 @@ TEST(OfflineDownload, Activate) {
observer->statusChangedFn = [&] (OfflineRegionStatus status) {
if (status.complete()) {
- EXPECT_EQ(261u, status.completedResourceCount); // 256 glyphs, 1 tile, 1 style, source, sprite image, and sprite json
+ EXPECT_EQ(262u, status.completedResourceCount); // 256 glyphs, 1 tile, 1 style, source, image, sprite image, and sprite json
EXPECT_EQ(test.size, status.completedResourceSize);
download.setState(OfflineRegionDownloadState::Inactive);
@@ -299,7 +304,7 @@ TEST(OfflineDownload, GetStatusStyleComplete) {
EXPECT_EQ(OfflineRegionDownloadState::Inactive, status.downloadState);
EXPECT_EQ(1u, status.completedResourceCount);
EXPECT_EQ(test.size, status.completedResourceSize);
- EXPECT_EQ(260u, status.requiredResourceCount);
+ EXPECT_EQ(261u, status.requiredResourceCount);
EXPECT_FALSE(status.requiredResourceCountIsPrecise);
EXPECT_FALSE(status.complete());
}
@@ -325,7 +330,7 @@ TEST(OfflineDownload, GetStatusStyleAndSourceComplete) {
EXPECT_EQ(OfflineRegionDownloadState::Inactive, status.downloadState);
EXPECT_EQ(2u, status.completedResourceCount);
EXPECT_EQ(test.size, status.completedResourceSize);
- EXPECT_EQ(261u, status.requiredResourceCount);
+ EXPECT_EQ(262u, status.requiredResourceCount);
EXPECT_TRUE(status.requiredResourceCountIsPrecise);
EXPECT_FALSE(status.complete());
}
diff --git a/test/storage/online_file_source.test.cpp b/test/storage/online_file_source.test.cpp
index 1a1d2d42f8..70bfe3ac95 100644
--- a/test/storage/online_file_source.test.cpp
+++ b/test/storage/online_file_source.test.cpp
@@ -36,6 +36,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(CancelMultiple)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -62,6 +63,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(TemporaryError)) {
EXPECT_EQ("HTTP status code 500", res.error->message);
ASSERT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
} break;
@@ -73,6 +75,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(TemporaryError)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -99,6 +102,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(ConnectionError)) {
EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
ASSERT_FALSE(res.data.get());
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
@@ -126,6 +130,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(Timeout)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Hello World!", *res.data);
EXPECT_TRUE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
if (counter == 4) {
@@ -150,6 +155,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RetryDelayOnExpiredTile)) {
counter++;
EXPECT_EQ(nullptr, res.error);
EXPECT_GT(util::now(), *res.expires);
+ EXPECT_FALSE(res.mustRevalidate);
});
util::Timer timer;
@@ -170,6 +176,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RetryOnClockSkew)) {
const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/clockskew" };
std::unique_ptr<AsyncRequest> req1 = fs.request(resource, [&](Response res) {
+ EXPECT_FALSE(res.mustRevalidate);
switch (counter++) {
case 0: {
EXPECT_EQ(nullptr, res.error);
@@ -240,6 +247,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(Load)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
@@ -277,6 +285,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusChange)) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("Response", *res.data);
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
loop.stop();
@@ -315,6 +324,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusChangePreempt)) {
EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
ASSERT_FALSE(res.data.get());
EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(res.mustRevalidate);
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
diff --git a/test/storage/resource.test.cpp b/test/storage/resource.test.cpp
index 1c15fe6503..5a27aa98a5 100644
--- a/test/storage/resource.test.cpp
+++ b/test/storage/resource.test.cpp
@@ -117,6 +117,13 @@ TEST(Resource, SpriteImage) {
EXPECT_EQ("http://example.com/sprite@2x.png", resource.url);
}
+TEST(Resource, Image) {
+ using namespace mbgl;
+ Resource resource = Resource::image("http://example.com/sprite.jpg");
+ EXPECT_EQ(Resource::Kind::Image, resource.kind);
+ EXPECT_EQ("http://example.com/sprite.jpg", resource.url);
+}
+
TEST(Resource, SpriteJSON) {
using namespace mbgl;
Resource resource = Resource::spriteJSON("http://example.com/sprite", 2.0);
diff --git a/test/storage/server.js b/test/storage/server.js
index b54ff835ec..d6429e4635 100755
--- a/test/storage/server.js
+++ b/test/storage/server.js
@@ -44,8 +44,8 @@ app.get('/cache', function(req, res) {
app.get('/revalidate-same', function(req, res) {
if (req.headers['if-none-match'] == 'snowfall') {
- // Second request can be cached for 30 seconds.
- res.setHeader('Cache-Control', 'max-age=30');
+ // Second request can be cached for 1 second.
+ res.setHeader('Cache-Control', 'max-age=1, must-revalidate');
res.status(304).end();
} else {
// First request must always be revalidated.
@@ -67,7 +67,7 @@ app.get('/revalidate-modified', function(req, res) {
if (req.headers['if-modified-since']) {
var modified_since = new Date(req.headers['if-modified-since']);
if (modified_since >= jan1) {
- res.setHeader('Cache-Control', 'max-age=30');
+ res.setHeader('Cache-Control', 'max-age=1, must-revalidate');
res.status(304).end();
return;
}
diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp
index dbd7a09868..36715a2fd0 100644
--- a/test/storage/sqlite.test.cpp
+++ b/test/storage/sqlite.test.cpp
@@ -25,3 +25,14 @@ TEST(SQLite, Statement) {
ASSERT_EQ(stmt2.lastInsertRowId(), 2);
ASSERT_EQ(stmt2.changes(), 1u);
}
+
+TEST(SQLite, TEST_REQUIRES_WRITE(CantOpenException)) {
+ try {
+ // Should throw a CANTOPEN when the database doesn't exist,
+ // make sure all the backends behave the same way.
+ mapbox::sqlite::Database("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly);
+ FAIL();
+ } catch (mapbox::sqlite::Exception& ex) {
+ ASSERT_EQ(ex.code, mapbox::sqlite::Exception::Code::CANTOPEN);
+ }
+}
diff --git a/test/style/conversion/function.test.cpp b/test/style/conversion/function.test.cpp
index 08637d40cb..1eff94d939 100644
--- a/test/style/conversion/function.test.cpp
+++ b/test/style/conversion/function.test.cpp
@@ -19,26 +19,26 @@ TEST(StyleConversion, Function) {
return convert<CameraFunction<float>, JSValue>(doc, error);
};
- auto fn1 = parseFunction("{\"stops\":[]}");
+ auto fn1 = parseFunction(R"({"stops":[]})");
ASSERT_FALSE(fn1);
ASSERT_EQ("function must have at least one stop", error.message);
- auto fn2 = parseFunction("{\"stops\":[1]}");
+ auto fn2 = parseFunction(R"({"stops":[1]})");
ASSERT_FALSE(fn2);
ASSERT_EQ("function stop must be an array", error.message);
- auto fn3 = parseFunction("{\"stops\":[[]]}");
+ auto fn3 = parseFunction(R"({"stops":[[]]})");
ASSERT_FALSE(fn3);
ASSERT_EQ("function stop must have two elements", error.message);
- auto fn4 = parseFunction("{\"stops\":[[-1,-1]]}");
+ auto fn4 = parseFunction(R"({"stops":[[-1,-1]]})");
ASSERT_TRUE(bool(fn4));
- auto fn5 = parseFunction("{\"stops\":[[0,1,2]]}");
+ auto fn5 = parseFunction(R"({"stops":[[0,1,2]]})");
ASSERT_FALSE(fn5);
ASSERT_EQ("function stop must have two elements", error.message);
- auto fn6 = parseFunction("{\"stops\":[[0,\"x\"]]}");
+ auto fn6 = parseFunction(R"({"stops":[[0,"x"]]})");
ASSERT_FALSE(fn6);
ASSERT_EQ("value must be a number", error.message);
@@ -50,7 +50,7 @@ TEST(StyleConversion, Function) {
ASSERT_FALSE(fn8);
ASSERT_EQ("function must be an object", error.message);
- auto fn9 = parseFunction("{\"stops\":[[0,0]],\"base\":false}");
+ auto fn9 = parseFunction(R"({"stops":[[0,0]],"base":false})");
ASSERT_FALSE(fn9);
ASSERT_EQ("function base must be a number", error.message);
}
diff --git a/test/style/conversion/layer.test.cpp b/test/style/conversion/layer.test.cpp
index ae8d4058ab..d51d7d33e2 100644
--- a/test/style/conversion/layer.test.cpp
+++ b/test/style/conversion/layer.test.cpp
@@ -27,21 +27,11 @@ TEST(StyleConversion, LayerTransition) {
"duration": 400,
"delay": 500
}
- },
- "paint.class": {
- "background-color-transition": {
- "duration": 100
- }
}
})JSON");
- ASSERT_EQ(400ms, *layer->as<BackgroundLayer>()->impl->cascading
- .get<BackgroundColor>().getTransition({}).duration);
- ASSERT_EQ(500ms, *layer->as<BackgroundLayer>()->impl->cascading
- .get<BackgroundColor>().getTransition({}).delay);
-
- ASSERT_EQ(100ms, *layer->as<BackgroundLayer>()->impl->cascading
- .get<BackgroundColor>().getTransition({"class"}).duration);
- ASSERT_FALSE(bool(layer->as<BackgroundLayer>()->impl->cascading
- .get<BackgroundColor>().getTransition({"class"}).delay));
+ ASSERT_EQ(400ms, *layer->as<BackgroundLayer>()->impl().paint
+ .get<BackgroundColor>().options.duration);
+ ASSERT_EQ(500ms, *layer->as<BackgroundLayer>()->impl().paint
+ .get<BackgroundColor>().options.delay);
}
diff --git a/test/style/conversion/light.test.cpp b/test/style/conversion/light.test.cpp
index a2185906d6..28e22b3550 100644
--- a/test/style/conversion/light.test.cpp
+++ b/test/style/conversion/light.test.cpp
@@ -30,7 +30,7 @@ TEST(StyleConversion, Light) {
}
{
- auto light = parseLight("{\"color\":{\"stops\":[[14,\"blue\"],[16,\"red\"]]},\"intensity\":0.3,\"position\":[3,90,90]}");
+ auto light = parseLight(R"({"color":{"stops":[[14,"blue"],[16,"red"]]},"intensity":0.3,"position":[3,90,90]})");
ASSERT_TRUE((bool) light);
ASSERT_TRUE(light->getAnchor().isUndefined());
@@ -54,7 +54,7 @@ TEST(StyleConversion, Light) {
}
{
- auto light = parseLight("{\"color\":\"blue\",\"intensity\":0.3,\"color-transition\":{\"duration\":1000}}");
+ auto light = parseLight(R"({"color":"blue","intensity":0.3,"color-transition":{"duration":1000}})");
ASSERT_TRUE((bool) light);
ASSERT_FALSE(light->getColor().isUndefined());
@@ -65,35 +65,35 @@ TEST(StyleConversion, Light) {
}
{
- auto light = parseLight("{\"intensity\":false}");
+ auto light = parseLight(R"({"intensity":false})");
ASSERT_FALSE((bool) light);
ASSERT_EQ("value must be a number", error.message);
}
{
- auto light = parseLight("{\"intensity\":{\"stops\":[[15,\"red\"],[17,\"blue\"]]}}");
+ auto light = parseLight(R"({"intensity":{"stops":[[15,"red"],[17,"blue"]]}})");
ASSERT_FALSE((bool) light);
ASSERT_EQ("value must be a number", error.message);
}
{
- auto light = parseLight("{\"color\":5}");
+ auto light = parseLight(R"({"color":5})");
ASSERT_FALSE((bool) light);
ASSERT_EQ("value must be a string", error.message);
}
{
- auto light = parseLight("{\"position\":[0,5]}");
+ auto light = parseLight(R"({"position":[0,5]})");
ASSERT_FALSE((bool) light);
ASSERT_EQ("value must be an array of 3 numbers", error.message);
}
{
- auto light = parseLight("{\"anchor\":\"something\"}");
+ auto light = parseLight(R"({"anchor":"something"})");
ASSERT_FALSE((bool) light);
ASSERT_EQ("value must be a valid enumeration value", error.message);
diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp
index 1dae20b26b..0b2940a0e0 100644
--- a/test/style/conversion/stringify.test.cpp
+++ b/test/style/conversion/stringify.test.cpp
@@ -121,10 +121,17 @@ TEST(Stringify, PropertyValue) {
}
TEST(Stringify, Layout) {
- ASSERT_EQ(stringify(SymbolLayoutProperties()), "{}");
-
- SymbolLayoutProperties layout;
- layout.unevaluated.get<SymbolAvoidEdges>() = true;
- layout.unevaluated.get<IconPadding>() = 2.0;
+ auto stringify = [] (const SymbolLayoutProperties::Unevaluated& layout) {
+ rapidjson::StringBuffer s;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(s);
+ layout.stringify(writer);
+ return std::string(s.GetString());
+ };
+
+ ASSERT_EQ(stringify(SymbolLayoutProperties::Unevaluated()), "{}");
+
+ SymbolLayoutProperties::Unevaluated layout;
+ layout.get<SymbolAvoidEdges>() = true;
+ layout.get<IconPadding>() = 2.0;
ASSERT_EQ(stringify(layout), "{\"symbol-avoid-edges\":true,\"icon-padding\":2.0}");
}
diff --git a/test/style/filter.test.cpp b/test/style/filter.test.cpp
index c70792d8ef..96de125945 100644
--- a/test/style/filter.test.cpp
+++ b/test/style/filter.test.cpp
@@ -29,13 +29,13 @@ Feature feature(const PropertyMap& properties, const Geometry<double>& geometry
}
TEST(Filter, EqualsString) {
- Filter f = parse("[\"==\", \"foo\", \"bar\"]");
+ Filter f = parse(R"(["==", "foo", "bar"])");
ASSERT_TRUE(f(feature({{ "foo", std::string("bar") }})));
ASSERT_FALSE(f(feature({{ "foo", std::string("baz") }})));
}
TEST(Filter, EqualsNumber) {
- Filter f = parse("[\"==\", \"foo\", 0]");
+ Filter f = parse(R"(["==", "foo", 0])");
ASSERT_TRUE(f(feature({{ "foo", int64_t(0) }})));
ASSERT_TRUE(f(feature({{ "foo", uint64_t(0) }})));
ASSERT_TRUE(f(feature({{ "foo", double(0) }})));
@@ -50,13 +50,13 @@ TEST(Filter, EqualsNumber) {
}
TEST(Filter, EqualsType) {
- Filter f = parse("[\"==\", \"$type\", \"LineString\"]");
+ Filter f = parse(R"(["==", "$type", "LineString"])");
ASSERT_FALSE(f(feature({{}}, Point<double>())));
ASSERT_TRUE(f(feature({{}}, LineString<double>())));
}
TEST(Filter, InType) {
- Filter f = parse("[\"in\", \"$type\", \"LineString\", \"Polygon\"]");
+ Filter f = parse(R"(["in", "$type", "LineString", "Polygon"])");
ASSERT_FALSE(f(feature({{}}, Point<double>())));
ASSERT_TRUE(f(feature({{}}, LineString<double>())));
ASSERT_TRUE(f(feature({{}}, Polygon<double>())));
diff --git a/test/style/function/exponential_stops.test.cpp b/test/style/function/exponential_stops.test.cpp
new file mode 100644
index 0000000000..81438ec952
--- /dev/null
+++ b/test/style/function/exponential_stops.test.cpp
@@ -0,0 +1,20 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/style/function/exponential_stops.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+TEST(ExponentialStops, Empty) {
+ ExponentialStops<float> stops;
+ EXPECT_FALSE(bool(stops.evaluate(0)));
+}
+
+TEST(ExponentialStops, NonNumericInput) {
+ ExponentialStops<float> stops(std::map<float, float> {{0.0f, 0.0f}});
+ EXPECT_FALSE(bool(stops.evaluate(Value(NullValue()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(false))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::string()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::vector<Value>()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::unordered_map<std::string, Value>()))));
+}
diff --git a/test/style/function/interval_stops.test.cpp b/test/style/function/interval_stops.test.cpp
new file mode 100644
index 0000000000..8a5e74b8b6
--- /dev/null
+++ b/test/style/function/interval_stops.test.cpp
@@ -0,0 +1,20 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/style/function/interval_stops.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+TEST(IntervalStops, Empty) {
+ IntervalStops<float> stops;
+ EXPECT_FALSE(bool(stops.evaluate(0)));
+}
+
+TEST(IntervalStops, NonNumericInput) {
+ IntervalStops<float> stops(std::map<float, float> {{0.0f, 0.0f}});
+ EXPECT_FALSE(bool(stops.evaluate(Value(NullValue()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(false))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::string()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::vector<Value>()))));
+ EXPECT_FALSE(bool(stops.evaluate(Value(std::unordered_map<std::string, Value>()))));
+}
diff --git a/test/style/function/source_function.test.cpp b/test/style/function/source_function.test.cpp
index 260620c8d0..46ad961002 100644
--- a/test/style/function/source_function.test.cpp
+++ b/test/style/function/source_function.test.cpp
@@ -76,11 +76,14 @@ TEST(SourceFunction, Categorical) {
EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
.evaluate(oneString, 0.0f));
- EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ CategoricalStops<float>::Stops stops;
+ stops["1"s] = 1.0f;
+
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>(stops))
.evaluate(oneInteger, 0.0f));
- EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>(stops))
.evaluate(oneDouble, 0.0f));
- EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>(stops))
.evaluate(oneString, 0.0f));
EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ true, 1.0f }}))
diff --git a/test/style/paint_property.test.cpp b/test/style/properties.test.cpp
index fcca05f3bd..279fadb8c2 100644
--- a/test/style/paint_property.test.cpp
+++ b/test/style/properties.test.cpp
@@ -1,13 +1,14 @@
#include <mbgl/test/util.hpp>
-#include <mbgl/style/paint_property.hpp>
-#include <mbgl/renderer/transitioning_property.hpp>
+#include <mbgl/style/properties.hpp>
+#include <mbgl/renderer/property_evaluator.hpp>
+#include <mbgl/renderer/data_driven_property_evaluator.hpp>
using namespace mbgl;
using namespace mbgl::style;
using namespace std::literals::chrono_literals;
-float evaluate(TransitioningProperty<PropertyValue<float>>& property, Duration delta = Duration::zero()) {
+float evaluate(Transitioning<PropertyValue<float>>& property, Duration delta = Duration::zero()) {
ZoomHistory zoomHistory;
zoomHistory.update(0, TimePoint::min() + delta);
@@ -25,7 +26,7 @@ float evaluate(TransitioningProperty<PropertyValue<float>>& property, Duration d
return property.evaluate(evaluator, parameters.now);
}
-PossiblyEvaluatedPropertyValue<float> evaluate(TransitioningProperty<DataDrivenPropertyValue<float>>& property, Duration delta = Duration::zero()) {
+PossiblyEvaluatedPropertyValue<float> evaluate(Transitioning<DataDrivenPropertyValue<float>>& property, Duration delta = Duration::zero()) {
ZoomHistory zoomHistory;
zoomHistory.update(0, TimePoint::min() + delta);
@@ -43,15 +44,15 @@ PossiblyEvaluatedPropertyValue<float> evaluate(TransitioningProperty<DataDrivenP
return property.evaluate(evaluator, parameters.now);
}
-TEST(TransitioningProperty, EvaluateDefaultValue) {
- TransitioningProperty<PropertyValue<float>> property;
+TEST(TransitioningPropertyValue, EvaluateDefaultValue) {
+ Transitioning<PropertyValue<float>> property;
ASSERT_EQ(0.0f, evaluate(property));
}
-TEST(TransitioningProperty, EvaluateUntransitionedConstant) {
- TransitioningProperty<PropertyValue<float>> property {
+TEST(TransitioningPropertyValue, EvaluateUntransitionedConstant) {
+ Transitioning<PropertyValue<float>> property {
PropertyValue<float>(1.0f),
- TransitioningProperty<PropertyValue<float>>(),
+ Transitioning<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
@@ -59,18 +60,18 @@ TEST(TransitioningProperty, EvaluateUntransitionedConstant) {
ASSERT_EQ(1.0f, evaluate(property));
}
-TEST(TransitioningProperty, EvaluateTransitionedConstantWithoutDelay) {
+TEST(TransitioningPropertyValue, EvaluateTransitionedConstantWithoutDelay) {
TransitionOptions transition;
transition.duration = { 1000ms };
- TransitioningProperty<PropertyValue<float>> t0 {
+ Transitioning<PropertyValue<float>> t0 {
PropertyValue<float>(0.0f),
- TransitioningProperty<PropertyValue<float>>(),
+ Transitioning<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
- TransitioningProperty<PropertyValue<float>> t1 {
+ Transitioning<PropertyValue<float>> t1 {
PropertyValue<float>(1.0f),
t0,
transition,
@@ -82,19 +83,19 @@ TEST(TransitioningProperty, EvaluateTransitionedConstantWithoutDelay) {
ASSERT_FLOAT_EQ(1.0f, evaluate(t1, 1500ms));
}
-TEST(TransitioningProperty, EvaluateTransitionedConstantWithDelay) {
+TEST(TransitioningPropertyValue, EvaluateTransitionedConstantWithDelay) {
TransitionOptions transition;
transition.delay = { 1000ms };
transition.duration = { 1000ms };
- TransitioningProperty<PropertyValue<float>> t0 {
+ Transitioning<PropertyValue<float>> t0 {
PropertyValue<float>(0.0f),
- TransitioningProperty<PropertyValue<float>>(),
+ Transitioning<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
- TransitioningProperty<PropertyValue<float>> t1 {
+ Transitioning<PropertyValue<float>> t1 {
PropertyValue<float>(1.0f),
t0,
transition,
@@ -108,14 +109,14 @@ TEST(TransitioningProperty, EvaluateTransitionedConstantWithDelay) {
ASSERT_FLOAT_EQ(1.0f, evaluate(t1, 2500ms));
}
-TEST(TransitioningProperty, EvaluateDataDrivenValue) {
+TEST(TransitioningDataDrivenPropertyValue, Evaluate) {
TransitionOptions transition;
transition.delay = { 1000ms };
transition.duration = { 1000ms };
- TransitioningProperty<DataDrivenPropertyValue<float>> t0 {
+ Transitioning<DataDrivenPropertyValue<float>> t0 {
DataDrivenPropertyValue<float>(0.0f),
- TransitioningProperty<DataDrivenPropertyValue<float>>(),
+ Transitioning<DataDrivenPropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
@@ -125,7 +126,7 @@ TEST(TransitioningProperty, EvaluateDataDrivenValue) {
IdentityStops<float>()
};
- TransitioningProperty<DataDrivenPropertyValue<float>> t1 {
+ Transitioning<DataDrivenPropertyValue<float>> t1 {
DataDrivenPropertyValue<float>(sourceFunction),
t0,
transition,
diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp
index c60a473589..919260ffe9 100644
--- a/test/style/source.test.cpp
+++ b/test/style/source.test.cpp
@@ -3,10 +3,14 @@
#include <mbgl/test/stub_style_observer.hpp>
#include <mbgl/test/stub_render_source_observer.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/source_impl.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
+#include <mbgl/style/layers/raster_layer.cpp>
+#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/renderer/sources/render_raster_source.hpp>
#include <mbgl/renderer/sources/render_vector_source.hpp>
@@ -16,6 +20,9 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/io.hpp>
+#include <mbgl/util/premultiply.hpp>
+#include <mbgl/util/image.hpp>
+
#include <mbgl/util/tileset.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/logging.hpp>
@@ -23,12 +30,10 @@
#include <mbgl/util/range.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/annotation/annotation_source.hpp>
-
-#include <mapbox/geojsonvt.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <cstdint>
@@ -43,8 +48,10 @@ public:
Transform transform;
TransformState transformState;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ Style style { loop, fileSource, 1 };
+ AnnotationManager annotationManager { style };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -54,7 +61,9 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager,
+ 0
};
SourceTest() {
@@ -95,8 +104,8 @@ TEST(Source, LoadingFail) {
};
VectorSource source("source", "url");
- source.baseImpl->setObserver(&test.styleObserver);
- source.baseImpl->loadDescription(test.fileSource);
+ source.setObserver(&test.styleObserver);
+ source.loadDescription(test.fileSource);
test.run();
}
@@ -118,8 +127,8 @@ TEST(Source, LoadingCorrupt) {
};
VectorSource source("source", "url");
- source.baseImpl->setObserver(&test.styleObserver);
- source.baseImpl->loadDescription(test.fileSource);
+ source.setObserver(&test.styleObserver);
+ source.loadDescription(test.fileSource);
test.run();
}
@@ -133,14 +142,17 @@ TEST(Source, RasterTileEmpty) {
return response;
};
+ RasterLayer layer("id", "source");
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
RasterSource source("source", tileset, 512);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) {
- EXPECT_EQ("source", source_.baseImpl.id);
+ EXPECT_EQ("source", source_.baseImpl->id);
test.end();
};
@@ -148,9 +160,13 @@ TEST(Source, RasterTileEmpty) {
FAIL() << "Should never be called";
};
- RenderRasterSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -164,14 +180,19 @@ TEST(Source, VectorTileEmpty) {
return response;
};
+ LineLayer layer("id", "source");
+ layer.setSourceLayer("water");
+
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
VectorSource source("source", tileset);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) {
- EXPECT_EQ("source", source_.baseImpl.id);
+ EXPECT_EQ("source", source_.baseImpl->id);
test.end();
};
@@ -179,9 +200,13 @@ TEST(Source, VectorTileEmpty) {
FAIL() << "Should never be called";
};
- RenderVectorSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -197,22 +222,29 @@ TEST(Source, RasterTileFail) {
return response;
};
+ RasterLayer layer("id", "source");
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
RasterSource source("source", tileset, 512);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(SourceType::Raster, source_.baseImpl.type);
+ EXPECT_EQ(SourceType::Raster, source_.baseImpl->type);
EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID);
EXPECT_EQ("Failed by the test case", util::toString(error));
test.end();
};
- RenderRasterSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -228,22 +260,31 @@ TEST(Source, VectorTileFail) {
return response;
};
+ LineLayer layer("id", "source");
+ layer.setSourceLayer("water");
+
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
VectorSource source("source", tileset);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(SourceType::Vector, source_.baseImpl.type);
+ EXPECT_EQ(SourceType::Vector, source_.baseImpl->type);
EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID);
EXPECT_EQ("Failed by the test case", util::toString(error));
test.end();
};
- RenderVectorSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -257,23 +298,30 @@ TEST(Source, RasterTileCorrupt) {
return response;
};
+ RasterLayer layer("id", "source");
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
RasterSource source("source", tileset, 512);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source_.baseImpl.type, SourceType::Raster);
+ EXPECT_EQ(source_.baseImpl->type, SourceType::Raster);
EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID);
EXPECT_TRUE(bool(error));
// Not asserting on platform-specific error text.
test.end();
};
- RenderRasterSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -287,27 +335,31 @@ TEST(Source, VectorTileCorrupt) {
return response;
};
- // Need to have at least one layer that uses the source.
- auto layer = std::make_unique<LineLayer>("id", "source");
- layer->setSourceLayer("water");
- test.style.addLayer(std::move(layer));
+ LineLayer layer("id", "source");
+ layer.setSourceLayer("water");
+
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
Tileset tileset;
tileset.tiles = { "tiles" };
VectorSource source("source", tileset);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source_.baseImpl.type, SourceType::Vector);
+ EXPECT_EQ(source_.baseImpl->type, SourceType::Vector);
EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID);
EXPECT_EQ(util::toString(error), "unknown pbf field type exception");
test.end();
};
- RenderVectorSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -320,11 +372,14 @@ TEST(Source, RasterTileCancel) {
return optional<Response>();
};
+ RasterLayer layer("id", "source");
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
RasterSource source("source", tileset, 512);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileChanged = [&] (RenderSource&, const OverscaledTileID&) {
FAIL() << "Should never be called";
@@ -334,9 +389,13 @@ TEST(Source, RasterTileCancel) {
FAIL() << "Should never be called";
};
- RenderRasterSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -349,11 +408,16 @@ TEST(Source, VectorTileCancel) {
return optional<Response>();
};
+ LineLayer layer("id", "source");
+ layer.setSourceLayer("water");
+
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
Tileset tileset;
tileset.tiles = { "tiles" };
VectorSource source("source", tileset);
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
test.renderSourceObserver.tileChanged = [&] (RenderSource&, const OverscaledTileID&) {
FAIL() << "Should never be called";
@@ -363,9 +427,13 @@ TEST(Source, VectorTileCancel) {
FAIL() << "Should never be called";
};
- RenderVectorSource renderSource(*source.impl);
- renderSource.setObserver(&test.renderSourceObserver);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->setObserver(&test.renderSourceObserver);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -373,6 +441,9 @@ TEST(Source, VectorTileCancel) {
TEST(Source, RasterTileAttribution) {
SourceTest test;
+ RasterLayer layer("id", "source");
+ std::vector<Immutable<Layer::Impl>> layers {{ layer.baseImpl }};
+
std::string mapboxOSM = ("<a href='https://www.mapbox.com/about/maps/' target='_blank'>&copy; Mapbox</a> "
"<a href='http://www.openstreetmap.org/about/' target='_blank'>©️ OpenStreetMap</a>");
@@ -398,11 +469,15 @@ TEST(Source, RasterTileAttribution) {
};
RasterSource source("source", "url", 512);
- source.baseImpl->setObserver(&test.styleObserver);
- source.baseImpl->loadDescription(test.fileSource);
+ source.setObserver(&test.styleObserver);
+ source.loadDescription(test.fileSource);
- RenderRasterSource renderSource(*source.impl);
- renderSource.updateTiles(test.tileParameters);
+ auto renderSource = RenderSource::create(source.baseImpl);
+ renderSource->update(source.baseImpl,
+ layers,
+ true,
+ true,
+ test.tileParameters);
test.run();
}
@@ -413,7 +488,7 @@ TEST(Source, GeoJSonSourceUrlUpdate) {
test.fileSource.sourceResponse = [&] (const Resource& resource) {
EXPECT_EQ("url", resource.url);
Response response;
- response.data = std::make_unique<std::string>("{\"geometry\": {\"type\": \"Point\", \"coordinates\": [1.1, 1.1]}, \"type\": \"Feature\", \"properties\": {}}");
+ response.data = std::make_unique<std::string>(R"({"geometry": {"type": "Point", "coordinates": [1.1, 1.1]}, "type": "Feature", "properties": {}})");
return response;
};
@@ -423,10 +498,10 @@ TEST(Source, GeoJSonSourceUrlUpdate) {
};
GeoJSONSource source("source");
- source.baseImpl->setObserver(&test.styleObserver);
+ source.setObserver(&test.styleObserver);
// Load initial, so the source state will be loaded=true
- source.baseImpl->loadDescription(test.fileSource);
+ source.loadDescription(test.fileSource);
// Schedule an update
test.loop.invoke([&] () {
@@ -436,3 +511,39 @@ TEST(Source, GeoJSonSourceUrlUpdate) {
test.run();
}
+
+TEST(Source, ImageSourceImageUpdate) {
+ SourceTest test;
+
+ test.fileSource.response = [&] (const Resource& resource) {
+ EXPECT_EQ("http://url", resource.url);
+ Response response;
+ response.data = std::make_unique<std::string>(util::read_file("test/fixtures/image/no_profile.png"));
+ return response;
+ };
+ test.styleObserver.sourceChanged = [&] (Source&) {
+ // Should be called (test will hang if it doesn't)
+ test.end();
+ };
+ std::array<LatLng, 4> coords;
+
+ ImageSource source("source", coords);
+ source.setURL("http://url");
+ source.setObserver(&test.styleObserver);
+
+ // Load initial, so the source state will be loaded=true
+ source.loadDescription(test.fileSource);
+ PremultipliedImage rgba({ 1, 1 });
+ rgba.data[0] = 255;
+ rgba.data[1] = 254;
+ rgba.data[2] = 253;
+ rgba.data[3] = 0;
+
+ // Schedule an update
+ test.loop.invoke([&] () {
+ // Update the url
+ source.setImage(std::move(rgba));
+ });
+
+ test.run();
+}
diff --git a/test/style/style.test.cpp b/test/style/style.test.cpp
index 841c7b291b..9bdab37ac6 100644
--- a/test/style/style.test.cpp
+++ b/test/style/style.test.cpp
@@ -2,7 +2,7 @@
#include <mbgl/test/stub_file_source.hpp>
#include <mbgl/test/fixture_log_observer.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/source_impl.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/layer.hpp>
@@ -21,34 +21,34 @@ TEST(Style, Properties) {
ThreadPool threadPool{ 1 };
StubFileSource fileSource;
- Style style { threadPool, fileSource, 1.0 };
+ Style::Impl style { threadPool, fileSource, 1.0 };
- style.setJSON(R"STYLE({"name": "Test"})STYLE");
+ style.loadJSON(R"STYLE({"name": "Test"})STYLE");
ASSERT_EQ("Test", style.getName());
- style.setJSON(R"STYLE({"center": [10, 20]})STYLE");
+ style.loadJSON(R"STYLE({"center": [10, 20]})STYLE");
ASSERT_EQ("", style.getName());
- ASSERT_EQ((LatLng{20, 10}), style.getDefaultLatLng());
+ ASSERT_EQ((LatLng{20, 10}), *style.getDefaultCamera().center);
- style.setJSON(R"STYLE({"bearing": 24})STYLE");
+ style.loadJSON(R"STYLE({"bearing": 24})STYLE");
ASSERT_EQ("", style.getName());
- ASSERT_EQ((LatLng{0, 0}), style.getDefaultLatLng());
- ASSERT_EQ(24, style.getDefaultBearing());
+ ASSERT_EQ(LatLng {}, *style.getDefaultCamera().center);
+ ASSERT_EQ(24, *style.getDefaultCamera().angle);
- style.setJSON(R"STYLE({"zoom": 13.3})STYLE");
+ style.loadJSON(R"STYLE({"zoom": 13.3})STYLE");
ASSERT_EQ("", style.getName());
- ASSERT_EQ(13.3, style.getDefaultZoom());
+ ASSERT_EQ(13.3, *style.getDefaultCamera().zoom);
- style.setJSON(R"STYLE({"pitch": 60})STYLE");
+ style.loadJSON(R"STYLE({"pitch": 60})STYLE");
ASSERT_EQ("", style.getName());
- ASSERT_EQ(60, style.getDefaultPitch());
+ ASSERT_EQ(60, *style.getDefaultCamera().pitch);
- style.setJSON(R"STYLE({"name": 23, "center": {}, "bearing": "north", "zoom": null, "pitch": "wide"})STYLE");
+ style.loadJSON(R"STYLE({"name": 23, "center": {}, "bearing": "north", "zoom": null, "pitch": "wide"})STYLE");
ASSERT_EQ("", style.getName());
- ASSERT_EQ((LatLng{0, 0}), style.getDefaultLatLng());
- ASSERT_EQ(0, style.getDefaultBearing());
- ASSERT_EQ(0, style.getDefaultZoom());
- ASSERT_EQ(0, style.getDefaultPitch());
+ ASSERT_EQ(LatLng {}, *style.getDefaultCamera().center);
+ ASSERT_EQ(0, *style.getDefaultCamera().zoom);
+ ASSERT_EQ(0, *style.getDefaultCamera().angle);
+ ASSERT_EQ(0, *style.getDefaultCamera().pitch);
}
TEST(Style, DuplicateSource) {
@@ -56,9 +56,9 @@ TEST(Style, DuplicateSource) {
ThreadPool threadPool{ 1 };
StubFileSource fileSource;
- Style style { threadPool, fileSource, 1.0 };
+ Style::Impl style { threadPool, fileSource, 1.0 };
- style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
+ style.loadJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
style.addSource(std::make_unique<VectorSource>("sourceId", "mapbox://mapbox.mapbox-terrain-v2"));
@@ -78,9 +78,9 @@ TEST(Style, RemoveSourceInUse) {
ThreadPool threadPool{ 1 };
StubFileSource fileSource;
- Style style { threadPool, fileSource, 1.0 };
+ Style::Impl style { threadPool, fileSource, 1.0 };
- style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
+ style.loadJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
style.addSource(std::make_unique<VectorSource>("sourceId", "mapbox://mapbox.mapbox-terrain-v2"));
style.addLayer(std::make_unique<LineLayer>("layerId", "sourceId"));
diff --git a/test/style/style_image.test.cpp b/test/style/style_image.test.cpp
index 319120df83..e49bf37582 100644
--- a/test/style/style_image.test.cpp
+++ b/test/style/style_image.test.cpp
@@ -8,7 +8,7 @@ using namespace mbgl;
TEST(StyleImage, ZeroWidth) {
try {
- style::Image(PremultipliedImage({ 0, 16 }), 2.0);
+ style::Image("test", PremultipliedImage({ 0, 16 }), 2.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image dimensions may not be zero", ex.what());
@@ -17,7 +17,7 @@ TEST(StyleImage, ZeroWidth) {
TEST(StyleImage, ZeroHeight) {
try {
- style::Image(PremultipliedImage({ 16, 0 }), 2.0);
+ style::Image("test", PremultipliedImage({ 16, 0 }), 2.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite image dimensions may not be zero", ex.what());
@@ -26,7 +26,7 @@ TEST(StyleImage, ZeroHeight) {
TEST(StyleImage, ZeroRatio) {
try {
- style::Image(PremultipliedImage({ 16, 16 }), 0.0);
+ style::Image("test", PremultipliedImage({ 16, 16 }), 0.0);
FAIL() << "Expected exception";
} catch (util::SpriteImageException& ex) {
EXPECT_STREQ("Sprite pixelRatio may not be <= 0", ex.what());
@@ -34,19 +34,15 @@ TEST(StyleImage, ZeroRatio) {
}
TEST(StyleImage, Retina) {
- style::Image image(PremultipliedImage({ 32, 24 }), 2.0);
- EXPECT_EQ(16, image.getWidth());
- EXPECT_EQ(32u, image.image.size.width);
- EXPECT_EQ(12, image.getHeight());
- EXPECT_EQ(24u, image.image.size.height);
- EXPECT_EQ(2, image.pixelRatio);
+ style::Image image("test", PremultipliedImage({ 32, 24 }), 2.0);
+ EXPECT_EQ(32u, image.getImage().size.width);
+ EXPECT_EQ(24u, image.getImage().size.height);
+ EXPECT_EQ(2, image.getPixelRatio());
}
TEST(StyleImage, FractionalRatio) {
- style::Image image(PremultipliedImage({ 20, 12 }), 1.5);
- EXPECT_EQ(float(20.0 / 1.5), image.getWidth());
- EXPECT_EQ(20u, image.image.size.width);
- EXPECT_EQ(float(12.0 / 1.5), image.getHeight());
- EXPECT_EQ(12u, image.image.size.height);
- EXPECT_EQ(1.5, image.pixelRatio);
+ style::Image image("test", PremultipliedImage({ 20, 12 }), 1.5);
+ EXPECT_EQ(20u, image.getImage().size.width);
+ EXPECT_EQ(12u, image.getImage().size.height);
+ EXPECT_EQ(1.5, image.getPixelRatio());
}
diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp
index 657dc24a70..77acca2868 100644
--- a/test/style/style_layer.test.cpp
+++ b/test/style/style_layer.test.cpp
@@ -1,7 +1,7 @@
#include <mbgl/test/util.hpp>
#include <mbgl/test/stub_layer_observer.hpp>
#include <mbgl/test/stub_file_source.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
@@ -28,15 +28,6 @@ using namespace mbgl::style;
namespace {
-template <class T, class... Params> void testClone(Params... params) {
- auto layer = std::make_unique<T>(std::forward<Params>(params)...);
- auto clone = layer->baseImpl->clone();
- EXPECT_NE(layer.get(), clone.get());
- EXPECT_TRUE(reinterpret_cast<typename T::Impl*>(clone->baseImpl.get()));
- layer->impl->id = "test";
- EXPECT_EQ("test", layer->baseImpl->clone()->getID());
-}
-
const auto color = Color { 1, 0, 0, 1 };
const auto opacity = 1.0f;
const auto radius = 1.0f;
@@ -61,16 +52,6 @@ const auto duration = 1.0f;
} // namespace
-TEST(Layer, Clone) {
- testClone<BackgroundLayer>("background");
- testClone<CircleLayer>("circle", "source");
- testClone<CustomLayer>("custom", [](void*){}, [](void*, const CustomLayerRenderParameters&){}, [](void*){}, nullptr),
- testClone<FillLayer>("fill", "source");
- testClone<LineLayer>("line", "source");
- testClone<RasterLayer>("raster", "source");
- testClone<SymbolLayer>("symbol", "source");
-}
-
TEST(Layer, BackgroundProperties) {
auto layer = std::make_unique<BackgroundLayer>("background");
EXPECT_TRUE(layer->is<BackgroundLayer>());
@@ -222,11 +203,11 @@ TEST(Layer, RasterProperties) {
TEST(Layer, Observer) {
auto layer = std::make_unique<LineLayer>("line", "source");
StubLayerObserver observer;
- layer->baseImpl->setObserver(&observer);
+ layer->setObserver(&observer);
// Notifies observer on filter change.
bool filterChanged = false;
- observer.layerFilterChanged = [&] (Layer& layer_) {
+ observer.layerChanged = [&] (Layer& layer_) {
EXPECT_EQ(layer.get(), &layer_);
filterChanged = true;
};
@@ -235,7 +216,7 @@ TEST(Layer, Observer) {
// Notifies observer on visibility change.
bool visibilityChanged = false;
- observer.layerVisibilityChanged = [&] (Layer& layer_) {
+ observer.layerChanged = [&] (Layer& layer_) {
EXPECT_EQ(layer.get(), &layer_);
visibilityChanged = true;
};
@@ -244,7 +225,7 @@ TEST(Layer, Observer) {
// Notifies observer on paint property change.
bool paintPropertyChanged = false;
- observer.layerPaintPropertyChanged = [&] (Layer& layer_) {
+ observer.layerChanged = [&] (Layer& layer_) {
EXPECT_EQ(layer.get(), &layer_);
paintPropertyChanged = true;
};
@@ -253,7 +234,7 @@ TEST(Layer, Observer) {
// Notifies observer on layout property change.
bool layoutPropertyChanged = false;
- observer.layerLayoutPropertyChanged = [&] (Layer& layer_, const char *) {
+ observer.layerChanged = [&] (Layer& layer_) {
EXPECT_EQ(layer.get(), &layer_);
layoutPropertyChanged = true;
};
@@ -262,16 +243,28 @@ TEST(Layer, Observer) {
// Does not notify observer on no-op visibility change.
visibilityChanged = false;
+ observer.layerChanged = [&] (Layer& layer_) {
+ EXPECT_EQ(layer.get(), &layer_);
+ visibilityChanged = true;
+ };
layer->setVisibility(VisibilityType::None);
EXPECT_FALSE(visibilityChanged);
// Does not notify observer on no-op paint property change.
paintPropertyChanged = false;
+ observer.layerChanged = [&] (Layer& layer_) {
+ EXPECT_EQ(layer.get(), &layer_);
+ paintPropertyChanged = true;
+ };
layer->setLineColor(color);
EXPECT_FALSE(paintPropertyChanged);
// Does not notify observer on no-op layout property change.
layoutPropertyChanged = false;
+ observer.layerChanged = [&] (Layer& layer_) {
+ EXPECT_EQ(layer.get(), &layer_);
+ layoutPropertyChanged = true;
+ };
layer->setLineCap(lineCap);
EXPECT_FALSE(layoutPropertyChanged);
}
@@ -282,8 +275,8 @@ TEST(Layer, DuplicateLayer) {
// Setup style
ThreadPool threadPool{ 1 };
StubFileSource fileSource;
- Style style { threadPool, fileSource, 1.0 };
- style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
+ Style::Impl style { threadPool, fileSource, 1.0 };
+ style.loadJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
// Add initial layer
style.addLayer(std::make_unique<LineLayer>("line", "unusedsource"));
diff --git a/test/style/style_parser.test.cpp b/test/style/style_parser.test.cpp
index e3c1da582f..5fa81b47e9 100644
--- a/test/style/style_parser.test.cpp
+++ b/test/style/style_parser.test.cpp
@@ -16,8 +16,8 @@
using namespace mbgl;
-typedef std::pair<uint32_t, std::string> Message;
-typedef std::vector<Message> Messages;
+using Message = std::pair<uint32_t, std::string>;
+using Messages = std::vector<Message>;
class StyleParserTest : public ::testing::TestWithParam<std::string> {};
diff --git a/test/text/glyph_atlas.test.cpp b/test/text/glyph_loader.test.cpp
index 5aff1ee441..be197ebb46 100644
--- a/test/text/glyph_atlas.test.cpp
+++ b/test/text/glyph_loader.test.cpp
@@ -1,8 +1,7 @@
#include <mbgl/test/util.hpp>
#include <mbgl/test/stub_file_source.hpp>
-#include <mbgl/test/stub_style_observer.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/io.hpp>
@@ -10,30 +9,44 @@
using namespace mbgl;
+class StubGlyphManagerObserver : public GlyphManagerObserver {
+public:
+ void onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) override {
+ if (glyphsLoaded) glyphsLoaded(fontStack, glyphRange);
+ }
+
+ void onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) override {
+ if (glyphsError) glyphsError(fontStack, glyphRange, error);
+ }
+
+ std::function<void (const FontStack&, const GlyphRange&)> glyphsLoaded;
+ std::function<void (const FontStack&, const GlyphRange&, std::exception_ptr)> glyphsError;
+};
+
class StubGlyphRequestor : public GlyphRequestor {
public:
- void onGlyphsAvailable(GlyphPositionMap positions) override {
- if (glyphsAvailable) glyphsAvailable(std::move(positions));
+ void onGlyphsAvailable(GlyphMap glyphs) override {
+ if (glyphsAvailable) glyphsAvailable(std::move(glyphs));
}
- std::function<void (GlyphPositionMap)> glyphsAvailable;
+ std::function<void (GlyphMap)> glyphsAvailable;
};
-class GlyphAtlasTest {
+class GlyphManagerTest {
public:
util::RunLoop loop;
StubFileSource fileSource;
- StubStyleObserver observer;
+ StubGlyphManagerObserver observer;
StubGlyphRequestor requestor;
- GlyphAtlas glyphAtlas{ { 32, 32 }, fileSource };
+ GlyphManager glyphManager { fileSource };
void run(const std::string& url, GlyphDependencies dependencies) {
// Squelch logging.
Log::setObserver(std::make_unique<Log::NullObserver>());
- glyphAtlas.setURL(url);
- glyphAtlas.setObserver(&observer);
- glyphAtlas.getGlyphs(requestor, std::move(dependencies));
+ glyphManager.setURL(url);
+ glyphManager.setObserver(&observer);
+ glyphManager.getGlyphs(requestor, std::move(dependencies));
loop.run();
}
@@ -43,8 +56,8 @@ public:
}
};
-TEST(GlyphAtlas, LoadingSuccess) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingSuccess) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource& resource) {
EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
@@ -63,8 +76,8 @@ TEST(GlyphAtlas, LoadingSuccess) {
ASSERT_EQ(range, GlyphRange(0, 255));
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap positions) {
- const auto& testPositions = positions.at({{"Test Stack"}});
+ test.requestor.glyphsAvailable = [&] (GlyphMap glyphs) {
+ const auto& testPositions = glyphs.at({{"Test Stack"}});
ASSERT_EQ(testPositions.size(), 3u);
ASSERT_EQ(testPositions.count(u'a'), 1u);
@@ -82,8 +95,8 @@ TEST(GlyphAtlas, LoadingSuccess) {
});
}
-TEST(GlyphAtlas, LoadingFail) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingFail) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
Response response;
@@ -103,7 +116,7 @@ TEST(GlyphAtlas, LoadingFail) {
test.end();
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap) {
+ test.requestor.glyphsAvailable = [&] (GlyphMap) {
FAIL();
test.end();
};
@@ -115,8 +128,8 @@ TEST(GlyphAtlas, LoadingFail) {
});
}
-TEST(GlyphAtlas, LoadingCorrupted) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingCorrupted) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
Response response;
@@ -134,7 +147,7 @@ TEST(GlyphAtlas, LoadingCorrupted) {
test.end();
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap) {
+ test.requestor.glyphsAvailable = [&] (GlyphMap) {
FAIL();
test.end();
};
@@ -146,8 +159,8 @@ TEST(GlyphAtlas, LoadingCorrupted) {
});
}
-TEST(GlyphAtlas, LoadingCancel) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingCancel) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
test.end();
@@ -165,8 +178,8 @@ TEST(GlyphAtlas, LoadingCancel) {
});
}
-TEST(GlyphAtlas, LoadingInvalid) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingInvalid) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource& resource) {
EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
@@ -185,8 +198,8 @@ TEST(GlyphAtlas, LoadingInvalid) {
ASSERT_EQ(range, GlyphRange(0, 255));
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap positions) {
- const auto& testPositions = positions.at({{"Test Stack"}});
+ test.requestor.glyphsAvailable = [&] (GlyphMap glyphs) {
+ const auto& testPositions = glyphs.at({{"Test Stack"}});
ASSERT_EQ(testPositions.size(), 2u);
ASSERT_FALSE(bool(testPositions.at(u'A')));
diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp
index 83fd249535..8eedd9bd2e 100644
--- a/test/text/quads.test.cpp
+++ b/test/text/quads.test.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/anchor.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/style/image_impl.hpp>
#include <mbgl/test/util.hpp>
#include <mbgl/text/quads.hpp>
#include <mbgl/text/shaping.hpp>
@@ -12,48 +12,37 @@ using namespace mbgl::style;
TEST(getIconQuads, normal) {
SymbolLayoutProperties::Evaluated layout;
Anchor anchor(2.0, 3.0, 0.0, 0.5f, 0);
- SpriteAtlasElement image = {
- Rect<uint16_t>( 0, 0, 15, 11 ),
- style::Image(PremultipliedImage({1,1}), 1.0),
- { 0, 0 },
- 1.0f
+ ImagePosition image = {
+ mapbox::Bin(-1, 15, 11, 0, 0, 0, 0),
+ style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
};
- auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, 0);
- ASSERT_TRUE(shapedIcon);
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, SymbolAnchorType::Center, 0);
GeometryCoordinates line;
Shaping shapedText;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 16.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.anchorPoint.x, 2);
- ASSERT_EQ(quad.anchorPoint.y, 3);
- ASSERT_EQ(quad.tl.x, -8);
- ASSERT_EQ(quad.tl.y, -6);
- ASSERT_EQ(quad.tr.x, 7);
- ASSERT_EQ(quad.tr.y, -6);
- ASSERT_EQ(quad.bl.x, -8);
- ASSERT_EQ(quad.bl.y, 5);
- ASSERT_EQ(quad.br.x, 7);
- ASSERT_EQ(quad.br.y, 5);
- ASSERT_EQ(quad.anchorAngle, 0.0f);
- ASSERT_EQ(quad.glyphAngle, 0.0f);
- ASSERT_EQ(quad.minScale, 0.5f);
+ getIconQuad(shapedIcon, layout, 16.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -14);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, 1);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -14);
+ EXPECT_EQ(quad.bl.y, 1);
+ EXPECT_EQ(quad.br.x, 1);
+ EXPECT_EQ(quad.br.y, 1);
}
TEST(getIconQuads, style) {
Anchor anchor(0.0, 0.0, 0.0, 0.5f, 0);
- SpriteAtlasElement image = {
- Rect<uint16_t>( 0, 0, 20, 20 ),
- style::Image(PremultipliedImage({1,1}), 1.0),
- { 0, 0 },
- 1.0f
+ ImagePosition image = {
+ mapbox::Bin(-1, 20, 20, 0, 0, 0, 0),
+ style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
};
- auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, 0);
- ASSERT_TRUE(shapedIcon);
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
GeometryCoordinates line;
Shaping shapedText;
@@ -61,27 +50,22 @@ TEST(getIconQuads, style) {
shapedText.bottom = 30.0f;
shapedText.left = -60.0f;
shapedText.right = 20.0f;
- shapedText.positionedGlyphs.emplace_back(PositionedGlyph(32, 0.0f, 0.0f, 0));
+ shapedText.positionedGlyphs.emplace_back(PositionedGlyph(32, 0.0f, 0.0f, false));
// none
{
SymbolLayoutProperties::Evaluated layout;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.anchorPoint.x, 0);
- ASSERT_EQ(quad.anchorPoint.y, 0);
- ASSERT_EQ(quad.tl.x, -11);
- ASSERT_EQ(quad.tl.y, -11);
- ASSERT_EQ(quad.tr.x, 9);
- ASSERT_EQ(quad.tr.y, -11);
- ASSERT_EQ(quad.bl.x, -11);
- ASSERT_EQ(quad.bl.y, 9);
- ASSERT_EQ(quad.br.x, 9);
- ASSERT_EQ(quad.br.y, 9);
- ASSERT_EQ(quad.anchorAngle, 0.0f);
- ASSERT_EQ(quad.glyphAngle, 0.0f);
- ASSERT_EQ(quad.minScale, 0.5f);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -19.5);
+ EXPECT_EQ(quad.tl.y, -19.5);
+ EXPECT_EQ(quad.tr.x, 0.5);
+ EXPECT_EQ(quad.tr.y, -19.5);
+ EXPECT_EQ(quad.bl.x, -19.5);
+ EXPECT_EQ(quad.bl.y, 0.5);
+ EXPECT_EQ(quad.br.x, 0.5);
+ EXPECT_EQ(quad.br.y, 0.5);
}
// width
@@ -90,16 +74,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -60);
- ASSERT_EQ(quad.tl.y, 0);
- ASSERT_EQ(quad.tr.x, 20);
- ASSERT_EQ(quad.tr.y, 0);
- ASSERT_EQ(quad.bl.x, -60);
- ASSERT_EQ(quad.bl.y, 20);
- ASSERT_EQ(quad.br.x, 20);
- ASSERT_EQ(quad.br.y, 20);
+ getIconQuad(shapedIcon, layout, 24.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -60);
+ EXPECT_EQ(quad.tl.y, 0);
+ EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.y, 0);
+ EXPECT_EQ(quad.bl.x, -60);
+ EXPECT_EQ(quad.bl.y, 20);
+ EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.y, 20);
}
// width x textSize
@@ -108,16 +92,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -30);
- ASSERT_EQ(quad.tl.y, -5);
- ASSERT_EQ(quad.tr.x, 10);
- ASSERT_EQ(quad.tr.y, -5);
- ASSERT_EQ(quad.bl.x, -30);
- ASSERT_EQ(quad.bl.y, 15);
- ASSERT_EQ(quad.br.x, 10);
- ASSERT_EQ(quad.br.y, 15);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -30);
+ EXPECT_EQ(quad.tl.y, -5);
+ EXPECT_EQ(quad.tr.x, 10);
+ EXPECT_EQ(quad.tr.y, -5);
+ EXPECT_EQ(quad.bl.x, -30);
+ EXPECT_EQ(quad.bl.y, 15);
+ EXPECT_EQ(quad.br.x, 10);
+ EXPECT_EQ(quad.br.y, 15);
}
// width x textSize + padding
@@ -130,16 +114,16 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -40);
- ASSERT_EQ(quad.tl.y, -10);
- ASSERT_EQ(quad.tr.x, 20);
- ASSERT_EQ(quad.tr.y, -10);
- ASSERT_EQ(quad.bl.x, -40);
- ASSERT_EQ(quad.bl.y, 20);
- ASSERT_EQ(quad.br.x, 20);
- ASSERT_EQ(quad.br.y, 20);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -40);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -40);
+ EXPECT_EQ(quad.bl.y, 20);
+ EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.y, 20);
}
// height
@@ -148,16 +132,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -30);
- ASSERT_EQ(quad.tl.y, -10);
- ASSERT_EQ(quad.tr.x, -10);
- ASSERT_EQ(quad.tr.y, -10);
- ASSERT_EQ(quad.bl.x, -30);
- ASSERT_EQ(quad.bl.y, 30);
- ASSERT_EQ(quad.br.x, -10);
- ASSERT_EQ(quad.br.y, 30);
+ getIconQuad(shapedIcon, layout, 24.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -30);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, -10);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -30);
+ EXPECT_EQ(quad.bl.y, 30);
+ EXPECT_EQ(quad.br.x, -10);
+ EXPECT_EQ(quad.br.y, 30);
}
// height x textSize
@@ -166,16 +150,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -20);
- ASSERT_EQ(quad.tl.y, -5);
- ASSERT_EQ(quad.tr.x, 0);
- ASSERT_EQ(quad.tr.y, -5);
- ASSERT_EQ(quad.bl.x, -20);
- ASSERT_EQ(quad.bl.y, 15);
- ASSERT_EQ(quad.br.x, 0);
- ASSERT_EQ(quad.br.y, 15);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -20);
+ EXPECT_EQ(quad.tl.y, -5);
+ EXPECT_EQ(quad.tr.x, 0);
+ EXPECT_EQ(quad.tr.y, -5);
+ EXPECT_EQ(quad.bl.x, -20);
+ EXPECT_EQ(quad.bl.y, 15);
+ EXPECT_EQ(quad.br.x, 0);
+ EXPECT_EQ(quad.br.y, 15);
}
// height x textSize + padding
@@ -188,16 +172,16 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -30);
- ASSERT_EQ(quad.tl.y, -10);
- ASSERT_EQ(quad.tr.x, 10);
- ASSERT_EQ(quad.tr.y, -10);
- ASSERT_EQ(quad.bl.x, -30);
- ASSERT_EQ(quad.bl.y, 20);
- ASSERT_EQ(quad.br.x, 10);
- ASSERT_EQ(quad.br.y, 20);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -30);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, 10);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -30);
+ EXPECT_EQ(quad.bl.y, 20);
+ EXPECT_EQ(quad.br.x, 10);
+ EXPECT_EQ(quad.br.y, 20);
}
// both
@@ -206,16 +190,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -60);
- ASSERT_EQ(quad.tl.y, -10);
- ASSERT_EQ(quad.tr.x, 20);
- ASSERT_EQ(quad.tr.y, -10);
- ASSERT_EQ(quad.bl.x, -60);
- ASSERT_EQ(quad.bl.y, 30);
- ASSERT_EQ(quad.br.x, 20);
- ASSERT_EQ(quad.br.y, 30);
+ getIconQuad(shapedIcon, layout, 24.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -60);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -60);
+ EXPECT_EQ(quad.bl.y, 30);
+ EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.y, 30);
}
// both x textSize
@@ -224,16 +208,16 @@ TEST(getIconQuads, style) {
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -30);
- ASSERT_EQ(quad.tl.y, -5);
- ASSERT_EQ(quad.tr.x, 10);
- ASSERT_EQ(quad.tr.y, -5);
- ASSERT_EQ(quad.bl.x, -30);
- ASSERT_EQ(quad.bl.y, 15);
- ASSERT_EQ(quad.br.x, 10);
- ASSERT_EQ(quad.br.y, 15);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -30);
+ EXPECT_EQ(quad.tl.y, -5);
+ EXPECT_EQ(quad.tr.x, 10);
+ EXPECT_EQ(quad.tr.y, -5);
+ EXPECT_EQ(quad.bl.x, -30);
+ EXPECT_EQ(quad.bl.y, 15);
+ EXPECT_EQ(quad.br.x, 10);
+ EXPECT_EQ(quad.br.y, 15);
}
// both x textSize + padding
@@ -246,16 +230,16 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -40);
- ASSERT_EQ(quad.tl.y, -10);
- ASSERT_EQ(quad.tr.x, 20);
- ASSERT_EQ(quad.tr.y, -10);
- ASSERT_EQ(quad.bl.x, -40);
- ASSERT_EQ(quad.bl.y, 20);
- ASSERT_EQ(quad.br.x, 20);
- ASSERT_EQ(quad.br.y, 20);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -40);
+ EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.bl.x, -40);
+ EXPECT_EQ(quad.bl.y, 20);
+ EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.y, 20);
}
// both x textSize + padding t/r/b/l
@@ -268,16 +252,16 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[2] = 10.0f;
layout.get<IconTextFitPadding>()[3] = 15.0f;
SymbolQuad quad =
- getIconQuad(anchor, *shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
-
- ASSERT_EQ(quad.tl.x, -45);
- ASSERT_EQ(quad.tl.y, -5);
- ASSERT_EQ(quad.tr.x, 15);
- ASSERT_EQ(quad.tr.y, -5);
- ASSERT_EQ(quad.bl.x, -45);
- ASSERT_EQ(quad.bl.y, 25);
- ASSERT_EQ(quad.br.x, 15);
- ASSERT_EQ(quad.br.y, 25);
+ getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+
+ EXPECT_EQ(quad.tl.x, -45);
+ EXPECT_EQ(quad.tl.y, -5);
+ EXPECT_EQ(quad.tr.x, 15);
+ EXPECT_EQ(quad.tr.y, -5);
+ EXPECT_EQ(quad.bl.x, -45);
+ EXPECT_EQ(quad.bl.y, 25);
+ EXPECT_EQ(quad.br.x, 15);
+ EXPECT_EQ(quad.br.y, 25);
}
}
diff --git a/test/tile/annotation_tile.test.cpp b/test/tile/annotation_tile.test.cpp
index ac3e064c50..8f3f903925 100644
--- a/test/tile/annotation_tile.test.cpp
+++ b/test/tile/annotation_tile.test.cpp
@@ -4,14 +4,17 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/map/query.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/map/query.hpp>
+#include <mbgl/renderer/query.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/gl/headless_backend.hpp>
+#include <mbgl/style/style.hpp>
#include <memory>
@@ -23,8 +26,12 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ style::Style style { loop, fileSource, 1 };
+ AnnotationManager annotationManager { style };
+ HeadlessBackend backend;
+ BackendScope scope { backend };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -34,7 +41,9 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager,
+ 0
};
};
@@ -44,14 +53,13 @@ TEST(AnnotationTile, Issue8289) {
AnnotationTile tile(OverscaledTileID(0, 0, 0), test.tileParameters);
auto data = std::make_unique<AnnotationTileData>();
- data->layers.emplace("test", AnnotationTileLayer("test"));
- data->layers.at("test").features.push_back(AnnotationTileFeature(0, FeatureType::Point, GeometryCollection()));
+ data->addLayer("test")->addFeature(0, FeatureType::Point, GeometryCollection());
// Simulate layout and placement of a symbol layer.
tile.onLayout(GeometryTile::LayoutResult {
- {},
- std::make_unique<FeatureIndex>(),
- std::move(data),
+ std::unordered_map<std::string, std::shared_ptr<Bucket>>(),
+ std::make_unique<FeatureIndex>(),
+ std::move(data),
}, 0);
auto collisionTile = std::make_unique<CollisionTile>(PlacementConfig());
@@ -62,15 +70,17 @@ TEST(AnnotationTile, Issue8289) {
collisionTile->placeFeature(feature, false, false);
tile.onPlacement(GeometryTile::PlacementResult {
+ std::unordered_map<std::string, std::shared_ptr<Bucket>>(),
+ std::move(collisionTile),
+ {},
{},
- std::move(collisionTile),
}, 0);
// Simulate a second layout with empty data.
tile.onLayout(GeometryTile::LayoutResult {
- {},
- std::make_unique<FeatureIndex>(),
- std::make_unique<AnnotationTileData>(),
+ std::unordered_map<std::string, std::shared_ptr<Bucket>>(),
+ std::make_unique<FeatureIndex>(),
+ std::make_unique<AnnotationTileData>(),
}, 0);
std::unordered_map<std::string, std::vector<Feature>> result;
@@ -78,7 +88,7 @@ TEST(AnnotationTile, Issue8289) {
TransformState transformState;
RenderedQueryOptions options;
- tile.queryRenderedFeatures(result, queryGeometry, transformState, options);
+ tile.queryRenderedFeatures(result, queryGeometry, transformState, {}, options);
EXPECT_TRUE(result.empty());
}
diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp
index 18d11c2c14..953c3b8a5f 100644
--- a/test/tile/geojson_tile.test.cpp
+++ b/test/tile/geojson_tile.test.cpp
@@ -7,10 +7,12 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <memory>
@@ -23,8 +25,10 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ style::Style style { loop, fileSource, 1 };
+ AnnotationManager annotationManager { style };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -35,14 +39,16 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager,
+ 0
};
};
TEST(GeoJSONTile, Issue7648) {
GeoJSONTileTest test;
- test.style.addLayer(std::make_unique<CircleLayer>("circle", "source"));
+ CircleLayer layer("circle", "source");
mapbox::geometry::feature_collection<int16_t> features;
features.push_back(mapbox::geometry::feature<int16_t> {
@@ -55,9 +61,10 @@ TEST(GeoJSONTile, Issue7648) {
observer.tileChanged = [&] (const Tile&) {
// Once present, the bucket should never "disappear", which would cause
// flickering.
- ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));
+ ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
};
+ tile.setLayers({{ layer.baseImpl }});
tile.setObserver(&observer);
tile.setPlacementConfig({});
@@ -76,7 +83,7 @@ TEST(GeoJSONTile, Issue7648) {
TEST(GeoJSONTile, Issue9927) {
GeoJSONTileTest test;
- test.style.addLayer(std::make_unique<CircleLayer>("circle", "source"));
+ CircleLayer layer("circle", "source");
mapbox::geometry::feature_collection<int16_t> features;
features.push_back(mapbox::geometry::feature<int16_t> {
@@ -85,6 +92,7 @@ TEST(GeoJSONTile, Issue9927) {
GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features);
+ tile.setLayers({{ layer.baseImpl }});
tile.setPlacementConfig({});
while (!tile.isComplete()) {
@@ -92,18 +100,18 @@ TEST(GeoJSONTile, Issue9927) {
}
ASSERT_TRUE(tile.isRenderable());
- ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));
+ ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
// Make sure that once we've had a renderable tile and then receive erroneous data, we retain
// the previously rendered data and keep the tile renderable.
tile.setError(std::make_exception_ptr(std::runtime_error("Connection offline")));
ASSERT_TRUE(tile.isRenderable());
- ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));
+ ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
// Then simulate a parsing failure and make sure that we keep it renderable in this situation
// as well. We're using 3 as a correlationID since we've done two three calls that increment
// this counter (as part of the GeoJSONTile constructor, setLayers, and setPlacementConfig).
tile.onError(std::make_exception_ptr(std::runtime_error("Parse error")), 3);
ASSERT_TRUE(tile.isRenderable());
- ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));
+ ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
}
diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp
index a606066e9b..8b2b3dee61 100644
--- a/test/tile/raster_tile.test.cpp
+++ b/test/tile/raster_tile.test.cpp
@@ -3,13 +3,15 @@
#include <mbgl/tile/raster_tile.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/raster_bucket.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
using namespace mbgl;
@@ -19,8 +21,10 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ style::Style style { loop, fileSource, 1 };
+ AnnotationManager annotationManager { style };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -31,7 +35,9 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager,
+ 0
};
};
@@ -56,7 +62,7 @@ TEST(RasterTile, onError) {
TEST(RasterTile, onParsed) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
- tile.onParsed(std::make_unique<RasterBucket>(UnassociatedImage{}), 0);
+ tile.onParsed(std::make_unique<RasterBucket>(PremultipliedImage{}), 0);
EXPECT_TRUE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
diff --git a/test/tile/tile_id.test.cpp b/test/tile/tile_id.test.cpp
index 1ef19fea0e..2f328b78d7 100644
--- a/test/tile/tile_id.test.cpp
+++ b/test/tile/tile_id.test.cpp
@@ -127,17 +127,17 @@ TEST(TileID, Canonical) {
TEST(TileID, Overscaled) {
EXPECT_TRUE(OverscaledTileID(4, 2, 3) == OverscaledTileID(4, 2, 3));
EXPECT_FALSE(OverscaledTileID(4, 2, 3) != OverscaledTileID(4, 2, 3));
- EXPECT_TRUE(OverscaledTileID(4, { 4, 2, 3 }) == OverscaledTileID(4, 2, 3));
- EXPECT_FALSE(OverscaledTileID(4, { 4, 2, 3 }) != OverscaledTileID(4, 2, 3));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) == OverscaledTileID(4, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3) != OverscaledTileID(4, { 4, 2, 3 }));
-
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(5, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(5, { 4, 2, 3 }));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(6, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(6, { 4, 2, 3 }));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(7, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(7, { 4, 2, 3 }));
+ EXPECT_TRUE(OverscaledTileID(4, 0, { 4, 2, 3 }) == OverscaledTileID(4, 2, 3));
+ EXPECT_FALSE(OverscaledTileID(4, 0, { 4, 2, 3 }) != OverscaledTileID(4, 2, 3));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) == OverscaledTileID(4, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3) != OverscaledTileID(4, 0, { 4, 2, 3 }));
+
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(5, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(5, 0, { 4, 2, 3 }));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(6, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(6, 0, { 4, 2, 3 }));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(7, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(7, 0, { 4, 2, 3 }));
EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(4, 2, 4));
EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(4, 2, 4));
@@ -146,70 +146,70 @@ TEST(TileID, Overscaled) {
EXPECT_TRUE(OverscaledTileID(4, 2, 3) != OverscaledTileID(5, 2, 3));
EXPECT_FALSE(OverscaledTileID(4, 2, 3) == OverscaledTileID(5, 2, 3));
- EXPECT_TRUE(OverscaledTileID(7, { 4, 2, 3 }) == OverscaledTileID(7, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(7, { 4, 2, 3 }) != OverscaledTileID(7, { 4, 2, 3 }));
+ EXPECT_TRUE(OverscaledTileID(7, 0, { 4, 2, 3 }) == OverscaledTileID(7, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(7, 0, { 4, 2, 3 }) != OverscaledTileID(7, 0, { 4, 2, 3 }));
EXPECT_FALSE(OverscaledTileID(4, 2, 3) < OverscaledTileID(4, 2, 3));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(5, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(5, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(6, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(6, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
- EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(7, { 4, 2, 3 }));
- EXPECT_FALSE(OverscaledTileID(7, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
-
- EXPECT_EQ(8u, OverscaledTileID(7, { 4, 2, 3 }).overscaleFactor());
- EXPECT_EQ(4u, OverscaledTileID(6, { 4, 2, 3 }).overscaleFactor());
- EXPECT_EQ(2u, OverscaledTileID(5, { 4, 2, 3 }).overscaleFactor());
- EXPECT_EQ(1u, OverscaledTileID(4, { 4, 2, 3 }).overscaleFactor());
- EXPECT_EQ(2147483648u, OverscaledTileID(31, { 0, 0, 0 }).overscaleFactor());
-
- EXPECT_EQ(OverscaledTileID(0, { 0, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(0));
- EXPECT_EQ(OverscaledTileID(1, { 1, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(1));
- EXPECT_EQ(OverscaledTileID(2, { 2, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(2));
- EXPECT_EQ(OverscaledTileID(3, { 3, 1, 1 }), OverscaledTileID(4, 2, 3).scaledTo(3));
- EXPECT_EQ(OverscaledTileID(4, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(4));
- EXPECT_EQ(OverscaledTileID(5, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(5));
- EXPECT_EQ(OverscaledTileID(6, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(6));
- EXPECT_EQ(OverscaledTileID(7, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(7));
- EXPECT_EQ(OverscaledTileID(8, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(8));
- EXPECT_EQ(OverscaledTileID(32, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(32));
-
- EXPECT_EQ(UnwrappedTileID(0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).unwrapTo(0));
- EXPECT_EQ(UnwrappedTileID(-1, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).unwrapTo(-1));
- EXPECT_EQ(UnwrappedTileID(1, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).unwrapTo(1));
- EXPECT_EQ(UnwrappedTileID(0, { 4, 2, 3 }), OverscaledTileID(5, { 4, 2, 3 }).unwrapTo(0));
- EXPECT_EQ(UnwrappedTileID(-1, { 4, 2, 3 }), OverscaledTileID(5, { 4, 2, 3 }).unwrapTo(-1));
- EXPECT_EQ(UnwrappedTileID(1, { 4, 2, 3 }), OverscaledTileID(5, { 4, 2, 3 }).unwrapTo(1));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(5, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(5, 0, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(6, 0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(6, 0, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
+ EXPECT_TRUE(OverscaledTileID(4, 2, 3) < OverscaledTileID(7,0, { 4, 2, 3 }));
+ EXPECT_FALSE(OverscaledTileID(7, 0, { 4, 2, 3 }) < OverscaledTileID(4, 2, 3));
+
+ EXPECT_EQ(8u, OverscaledTileID(7, 0, { 4, 2, 3 }).overscaleFactor());
+ EXPECT_EQ(4u, OverscaledTileID(6, 0, { 4, 2, 3 }).overscaleFactor());
+ EXPECT_EQ(2u, OverscaledTileID(5, 0, { 4, 2, 3 }).overscaleFactor());
+ EXPECT_EQ(1u, OverscaledTileID(4, 0, { 4, 2, 3 }).overscaleFactor());
+ EXPECT_EQ(2147483648u, OverscaledTileID(31, 0, { 0, 0, 0 }).overscaleFactor());
+
+ EXPECT_EQ(OverscaledTileID(0, 0, { 0, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(0));
+ EXPECT_EQ(OverscaledTileID(1, 0, { 1, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(1));
+ EXPECT_EQ(OverscaledTileID(2, 0, { 2, 0, 0 }), OverscaledTileID(4, 2, 3).scaledTo(2));
+ EXPECT_EQ(OverscaledTileID(3, 0, { 3, 1, 1 }), OverscaledTileID(4, 2, 3).scaledTo(3));
+ EXPECT_EQ(OverscaledTileID(4, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(4));
+ EXPECT_EQ(OverscaledTileID(5, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(5));
+ EXPECT_EQ(OverscaledTileID(6, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(6));
+ EXPECT_EQ(OverscaledTileID(7, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(7));
+ EXPECT_EQ(OverscaledTileID(8, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(8));
+ EXPECT_EQ(OverscaledTileID(32, 0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).scaledTo(32));
+
+ EXPECT_EQ(UnwrappedTileID(0, { 4, 2, 3 }), OverscaledTileID(4, 2, 3).toUnwrapped());
+ EXPECT_EQ(UnwrappedTileID(-1, { 4, 2, 3 }), OverscaledTileID(4, -1, { 4, 2, 3 }).toUnwrapped());
+ EXPECT_EQ(UnwrappedTileID(1, { 4, 2, 3 }), OverscaledTileID(4, 1, { 4, 2, 3 }).toUnwrapped());
+ EXPECT_EQ(UnwrappedTileID(0, { 4, 2, 3 }), OverscaledTileID(5, 0, { 4, 2, 3 }).toUnwrapped());
+ EXPECT_EQ(UnwrappedTileID(-1, { 4, 2, 3 }), OverscaledTileID(5, -1, { 4, 2, 3 }).toUnwrapped());
+ EXPECT_EQ(UnwrappedTileID(1, { 4, 2, 3 }), OverscaledTileID(5, 1, { 4, 2, 3 }).toUnwrapped());
EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(3, 1, 1)));
EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(3, 1, 1)));
EXPECT_TRUE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(3, 1, 1)));
- EXPECT_TRUE(OverscaledTileID(5, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
- EXPECT_TRUE(OverscaledTileID(6, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
- EXPECT_TRUE(OverscaledTileID(7, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
-
- EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(5, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
- EXPECT_TRUE(OverscaledTileID(6, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
- EXPECT_TRUE(OverscaledTileID(7, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 2, 3 })));
-
- EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(5, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
- EXPECT_FALSE(OverscaledTileID(6, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
- EXPECT_TRUE(OverscaledTileID(7, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, { 4, 2, 3 })));
-
- EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
- EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
- EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
- EXPECT_FALSE(OverscaledTileID(5, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
- EXPECT_FALSE(OverscaledTileID(6, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
- EXPECT_FALSE(OverscaledTileID(7, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 4, 0, 0 })));
-
- EXPECT_FALSE(OverscaledTileID(4, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, { 3, 1, 1 })));
+ EXPECT_TRUE(OverscaledTileID(5, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
+ EXPECT_TRUE(OverscaledTileID(6, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
+ EXPECT_TRUE(OverscaledTileID(7, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(3, 1, 1)));
+
+ EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(5, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+ EXPECT_TRUE(OverscaledTileID(6, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+ EXPECT_TRUE(OverscaledTileID(7, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 2, 3 })));
+
+ EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(5, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+ EXPECT_FALSE(OverscaledTileID(6, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+ EXPECT_TRUE(OverscaledTileID(7, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(6, 0, { 4, 2, 3 })));
+
+ EXPECT_FALSE(OverscaledTileID(2, 0, 0).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+ EXPECT_FALSE(OverscaledTileID(3, 1, 1).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+ EXPECT_FALSE(OverscaledTileID(4, 2, 3).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+ EXPECT_FALSE(OverscaledTileID(5, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+ EXPECT_FALSE(OverscaledTileID(6, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+ EXPECT_FALSE(OverscaledTileID(7, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 4, 0, 0 })));
+
+ EXPECT_FALSE(OverscaledTileID(4, 0, { 4, 2, 3 }).isChildOf(OverscaledTileID(5, 0, { 3, 1, 1 })));
}
TEST(TileID, Unwrapped) {
@@ -273,10 +273,10 @@ TEST(TileID, Unwrapped) {
EXPECT_FALSE(UnwrappedTileID(0, 1, 0) < UnwrappedTileID(1, 0, 0));
EXPECT_FALSE(UnwrappedTileID(5, 3, 6) < UnwrappedTileID(5, 3, 6));
- EXPECT_EQ(OverscaledTileID(4, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(4));
- EXPECT_EQ(OverscaledTileID(5, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(5));
- EXPECT_EQ(OverscaledTileID(6, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(6));
- EXPECT_EQ(OverscaledTileID(32, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(32));
+ EXPECT_EQ(OverscaledTileID(4, 0, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(4));
+ EXPECT_EQ(OverscaledTileID(5, 0, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(5));
+ EXPECT_EQ(OverscaledTileID(6, 0, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(6));
+ EXPECT_EQ(OverscaledTileID(32, 0, { 4, 2, 3 }), UnwrappedTileID(4, 2, 3).overscaleTo(32));
EXPECT_EQ(UnwrappedTileID(-1, { 1, 0, 0 }), UnwrappedTileID(1, -2, 0));
EXPECT_EQ(UnwrappedTileID(-1, { 1, 0, 1 }), UnwrappedTileID(1, -2, 1));
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index 336076ecc2..7e8b659b7a 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -6,14 +6,16 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/map/query.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/renderer/query.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <memory>
@@ -25,8 +27,10 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ style::Style style { loop, fileSource, 1 };
+ AnnotationManager annotationManager { style };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -37,7 +41,9 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager,
+ 0
};
};
@@ -69,7 +75,7 @@ TEST(VectorTile, Issue7615) {
style::SymbolLayoutProperties::PossiblyEvaluated(),
std::map<
std::string,
- std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>(),
+ std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>>(),
16.0f, 1.0f, 0.0f, false, false);
// Simulate placement of a symbol layer.
@@ -79,16 +85,18 @@ TEST(VectorTile, Issue7615) {
symbolBucket
}},
nullptr,
+ {},
+ {},
}, 0);
// Subsequent onLayout should not cause the existing symbol bucket to be discarded.
tile.onLayout(GeometryTile::LayoutResult {
- {},
+ std::unordered_map<std::string, std::shared_ptr<Bucket>>(),
nullptr,
nullptr,
}, 0);
- EXPECT_EQ(symbolBucket.get(), tile.getBucket(*symbolLayer.baseImpl->createRenderLayer()));
+ EXPECT_EQ(symbolBucket.get(), tile.getBucket(*symbolLayer.baseImpl));
}
TEST(VectorTile, Issue8542) {
diff --git a/test/util/async_task.test.cpp b/test/util/async_task.test.cpp
index 78dc79dd19..f3025e8952 100644
--- a/test/util/async_task.test.cpp
+++ b/test/util/async_task.test.cpp
@@ -1,9 +1,12 @@
#include <mbgl/util/async_task.hpp>
#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/test/util.hpp>
+#include <atomic>
+#include <future>
#include <vector>
using namespace mbgl::util;
@@ -29,6 +32,10 @@ public:
cb();
}
+ void sync(std::promise<void> barrier) {
+ barrier.set_value();
+ }
+
private:
AsyncTask *async;
};
@@ -94,23 +101,24 @@ TEST(AsyncTask, DestroyAfterSignaling) {
TEST(AsyncTask, RequestCoalescingMultithreaded) {
RunLoop loop;
- unsigned count = 0;
+ unsigned count = 0, numThreads = 25;
AsyncTask async([&count] { ++count; });
- std::vector<std::unique_ptr<Thread<TestWorker>>> threads;
- ThreadContext context = {"Test"};
+ mbgl::ThreadPool threads(numThreads);
+ auto mailbox = std::make_shared<mbgl::Mailbox>(threads);
- unsigned numThreads = 25;
- for (unsigned i = 0; i < numThreads; ++i) {
- std::unique_ptr<Thread<TestWorker>> thread =
- std::make_unique<Thread<TestWorker>>(context, &async);
+ TestWorker worker(&async);
+ mbgl::ActorRef<TestWorker> workerRef(worker, mailbox);
- thread->invoke(&TestWorker::run);
- threads.push_back(std::move(thread));
+ for (unsigned i = 0; i < numThreads; ++i) {
+ workerRef.invoke(&TestWorker::run);
}
- // Join all the threads
- threads.clear();
+ std::promise<void> barrier;
+ std::future<void> barrierFuture = barrier.get_future();
+
+ workerRef.invoke(&TestWorker::sync, std::move(barrier));
+ barrierFuture.wait();
loop.runOnce();
@@ -120,29 +128,20 @@ TEST(AsyncTask, RequestCoalescingMultithreaded) {
TEST(AsyncTask, ThreadSafety) {
RunLoop loop;
- unsigned count = 0;
- AsyncTask async([&count] { ++count; });
+ unsigned count = 0, numThreads = 25;
+ std::atomic_uint completed(numThreads);
- unsigned numThreads = 25;
+ AsyncTask async([&count] { ++count; });
- auto callback = [&] {
- if (!--numThreads) {
- loop.stop();
- }
- };
+ mbgl::ThreadPool threads(numThreads);
+ auto mailbox = std::make_shared<mbgl::Mailbox>(threads);
- std::vector<std::unique_ptr<Thread<TestWorker>>> threads;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
- ThreadContext context = {"Test"};
+ TestWorker worker(&async);
+ mbgl::ActorRef<TestWorker> workerRef(worker, mailbox);
for (unsigned i = 0; i < numThreads; ++i) {
- std::unique_ptr<Thread<TestWorker>> thread =
- std::make_unique<Thread<TestWorker>>(context, &async);
-
- requests.push_back(
- thread->invokeWithCallback(&TestWorker::runWithCallback, callback));
-
- threads.push_back(std::move(thread));
+ // The callback runs on the worker, thus the atomic type.
+ workerRef.invoke(&TestWorker::runWithCallback, [&] { if (!--completed) loop.stop(); });
}
loop.run();
diff --git a/test/util/dtoa.test.cpp b/test/util/dtoa.test.cpp
new file mode 100644
index 0000000000..8d2fba1877
--- /dev/null
+++ b/test/util/dtoa.test.cpp
@@ -0,0 +1,24 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/util/dtoa.hpp>
+
+#include <cfloat>
+#include <cmath>
+
+using namespace mbgl;
+
+TEST(Dtoa, Precision) {
+ EXPECT_EQ(M_E, std::stod(util::dtoa(M_E)));
+ EXPECT_EQ(M_LOG2E, std::stod(util::dtoa(M_LOG2E)));
+ EXPECT_EQ(M_LOG10E, std::stod(util::dtoa(M_LOG10E)));
+ EXPECT_EQ(M_LN2, std::stod(util::dtoa(M_LN2)));
+ EXPECT_EQ(M_LN10, std::stod(util::dtoa(M_LN10)));
+ EXPECT_EQ(M_PI, std::stod(util::dtoa(M_PI)));
+ EXPECT_EQ(M_PI_2, std::stod(util::dtoa(M_PI_2)));
+ EXPECT_EQ(M_PI_4, std::stod(util::dtoa(M_PI_4)));
+ EXPECT_EQ(M_1_PI, std::stod(util::dtoa(M_1_PI)));
+ EXPECT_EQ(M_2_PI, std::stod(util::dtoa(M_2_PI)));
+ EXPECT_EQ(M_2_SQRTPI, std::stod(util::dtoa(M_2_SQRTPI)));
+ EXPECT_EQ(M_SQRT2, std::stod(util::dtoa(M_SQRT2)));
+ EXPECT_EQ(M_SQRT1_2, std::stod(util::dtoa(M_SQRT1_2)));
+}
diff --git a/test/util/image.test.cpp b/test/util/image.test.cpp
index 4cacf89253..f4a6473040 100644
--- a/test/util/image.test.cpp
+++ b/test/util/image.test.cpp
@@ -86,33 +86,49 @@ TEST(Image, WebPTile) {
}
#endif // !defined(__ANDROID__) && !defined(__APPLE__) && !defined(QT_IMAGE_DECODERS)
+TEST(Image, Resize) {
+ AlphaImage image({0, 0});
+
+ image.resize({1, 1});
+ EXPECT_EQ(image.size, Size({1, 1}));
+
+ image.fill(100);
+ image.resize({2, 1});
+ EXPECT_EQ(image.size, Size({2, 1}));
+ EXPECT_EQ(image.data[0], 100);
+ EXPECT_EQ(image.data[1], 0);
+
+ image.resize({0, 0});
+ EXPECT_EQ(image.size, Size({0, 0}));
+}
+
TEST(Image, Copy) {
PremultipliedImage src5({5, 5});
PremultipliedImage dst5({5, 5});
PremultipliedImage src10({10, 10});
PremultipliedImage dst10({10, 10});
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {5, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {0, 5}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {6, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {1, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {5, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {1, 5}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {5, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {0, 5}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {6, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {1, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {5, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {1, 5}), std::out_of_range);
const uint32_t max = std::numeric_limits<uint32_t>::max();
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {max, 0}, {0, 0}, {1, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, max}, {0, 0}, {0, 1}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {max, 0}, {1, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, max}, {0, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {max, 0}, {0, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, max}, {0, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {max, 0}, {1, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, max}, {1, 1}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {1, 0}, {0, 0}, {max, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 1}, {0, 0}, {0, max}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {1, 0}, {max, 0}), std::out_of_range);
- EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, 1}, {0, max}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {1, 0}, {0, 0}, {max, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 1}, {0, 0}, {1, max}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {1, 0}, {max, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, 1}, {1, max}), std::out_of_range);
}
TEST(Image, Move) {
@@ -142,4 +158,8 @@ TEST(Image, Premultiply) {
EXPECT_EQ(127, image.data[1]);
EXPECT_EQ(127, image.data[2]);
EXPECT_EQ(128, image.data[3]);
+ EXPECT_EQ(1u, image.size.width);
+ EXPECT_EQ(1u, image.size.height);
+ EXPECT_EQ(0u, rgba.size.width);
+ EXPECT_EQ(0u, rgba.size.height);
}
diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp
index 065d024bef..54763cd9db 100644
--- a/test/util/memory.test.cpp
+++ b/test/util/memory.test.cpp
@@ -3,12 +3,11 @@
#include <mbgl/test/util.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/backend_scope.hpp>
-#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
+#include <mbgl/gl/headless_frontend.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/style/style.hpp>
#include <algorithm>
#include <iostream>
@@ -17,7 +16,7 @@
#include <unordered_map>
#include <utility>
-#include <stdlib.h>
+#include <cstdlib>
#include <unistd.h>
using namespace mbgl;
@@ -35,9 +34,6 @@ public:
}
util::RunLoop runLoop;
- HeadlessBackend backend { test::sharedDisplay() };
- BackendScope scope { backend };
- OffscreenView view{ backend.getContext(), { 512, 512 } };
StubFileSource fileSource;
ThreadPool threadPool { 4 };
@@ -72,21 +68,27 @@ private:
TEST(Memory, Vector) {
MemoryTest test;
+ float ratio { 2 };
- Map map(test.backend, { 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still);
+ HeadlessFrontend frontend { { 256, 256 }, ratio, test.fileSource, test.threadPool };
+ Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource,
+ test.threadPool, MapMode::Still);
map.setZoom(16); // more map features
- map.setStyleURL("mapbox://streets");
+ map.getStyle().loadURL("mapbox://streets");
- test::render(map, test.view);
+ frontend.render(map);
}
TEST(Memory, Raster) {
MemoryTest test;
+ float ratio { 2 };
- Map map(test.backend, { 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://satellite");
+ HeadlessFrontend frontend { { 256, 256 }, ratio, test.fileSource, test.threadPool };
+ Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource,
+ test.threadPool, MapMode::Still);
+ map.getStyle().loadURL("mapbox://satellite");
- test::render(map, test.view);
+ frontend.render(map);
}
/**
@@ -113,53 +115,54 @@ TEST(Memory, Footprint) {
if (!shouldRunFootprint()) {
return;
}
-
+
MemoryTest test;
- auto renderMap = [&](Map& map, const char* style){
- map.setZoom(16);
- map.setStyleURL(style);
- test::render(map, test.view);
+ class FrontendAndMap {
+ public:
+ FrontendAndMap(MemoryTest& test_, const char* style)
+ : frontend(Size{ 256, 256 }, 2, test_.fileSource, test_.threadPool)
+ , map(frontend, MapObserver::nullObserver(), frontend.getSize(), 2, test_.fileSource, test_.threadPool, MapMode::Still) {
+ map.setZoom(16);
+ map.getStyle().loadURL(style);
+ frontend.render(map);
+ }
+
+ HeadlessFrontend frontend;
+ Map map;
};
// Warm up buffers and cache.
for (unsigned i = 0; i < 10; ++i) {
- Map map(test.backend, { 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still);
- renderMap(map, "mapbox://streets");
- renderMap(map, "mapbox://satellite");
- };
+ FrontendAndMap(test, "mapbox://streets");
+ FrontendAndMap(test, "mapbox://satellite");
+ }
// Process close callbacks, mostly needed by
// libuv runloop.
test.runLoop.runOnce();
- std::vector<std::unique_ptr<Map>> maps;
+ std::vector<std::unique_ptr<FrontendAndMap>> maps;
unsigned runs = 15;
long vectorInitialRSS = mbgl::test::getCurrentRSS();
for (unsigned i = 0; i < runs; ++i) {
- auto vector = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource,
- test.threadPool, MapMode::Still);
- renderMap(*vector, "mapbox://streets");
- maps.push_back(std::move(vector));
- };
+ maps.emplace_back(std::make_unique<FrontendAndMap>(test, "mapbox://streets"));
+ }
double vectorFootprint = (mbgl::test::getCurrentRSS() - vectorInitialRSS) / double(runs);
long rasterInitialRSS = mbgl::test::getCurrentRSS();
for (unsigned i = 0; i < runs; ++i) {
- auto raster = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource,
- test.threadPool, MapMode::Still);
- renderMap(*raster, "mapbox://satellite");
- maps.push_back(std::move(raster));
- };
+ maps.emplace_back(std::make_unique<FrontendAndMap>(test, "mapbox://satellite"));
+ }
double rasterFootprint = (mbgl::test::getCurrentRSS() - rasterInitialRSS) / double(runs);
RecordProperty("vectorFootprint", vectorFootprint);
RecordProperty("rasterFootprint", rasterFootprint);
- ASSERT_LT(vectorFootprint, 65.2 * 1024 * 1024) << "\
+ ASSERT_LT(vectorFootprint, 40 * 1024 * 1024) << "\
mbgl::Map footprint over 65.2MB for vector styles.";
ASSERT_LT(rasterFootprint, 25 * 1024 * 1024) << "\
diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp
index 8a3a400887..d3a2ebae03 100644
--- a/test/util/merge_lines.test.cpp
+++ b/test/util/merge_lines.test.cpp
@@ -1,50 +1,31 @@
#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_geometry_tile_feature.hpp>
#include <mbgl/layout/merge_lines.hpp>
#include <mbgl/layout/symbol_feature.hpp>
+#include <utility>
const std::u16string aaa = u"a";
const std::u16string bbb = u"b";
using namespace mbgl;
-class GeometryTileFeatureStub : public GeometryTileFeature {
-public:
- GeometryTileFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
- std::unordered_map<std::string, Value> properties_) :
- id(id_),
- type(type_),
- geometry(geometry_),
- properties(properties_)
- {}
-
- FeatureType getType() const override { return type; }
- optional<Value> getValue(const std::string& key) const override {
- auto it = properties.find(key);
- if (it != properties.end()) {
- return it->second;
- }
- return {};
- };
- std::unordered_map<std::string,Value> getProperties() const override { return properties; };
- optional<FeatureIdentifier> getID() const override { return id; };
- GeometryCollection getGeometries() const override { return geometry; };
-
- optional<FeatureIdentifier> id;
- FeatureType type;
- GeometryCollection geometry;
- std::unordered_map<std::string,Value> properties;
-};
+namespace {
+
+PropertyMap properties;
+LineString<int16_t> emptyLine;
+
+}
class SymbolFeatureStub : public SymbolFeature {
public:
SymbolFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
- std::unordered_map<std::string, Value> properties_, optional<std::u16string> text_,
- optional<std::string> icon_, std::size_t index_) :
- SymbolFeature(std::make_unique<GeometryTileFeatureStub>(id_, type_, geometry_, properties_))
+ PropertyMap properties_, optional<std::u16string> text_,
+ optional<std::string> icon_, std::size_t index_) :
+ SymbolFeature(std::make_unique<StubGeometryTileFeature>(std::move(id_), type_, std::move(geometry_), std::move(properties_)))
{
- text = text_;
- icon = icon_;
+ text = std::move(text_);
+ icon = std::move(icon_);
index = index_;
}
};
@@ -52,20 +33,20 @@ public:
TEST(MergeLines, SameText) {
// merges lines with the same text
std::vector<mbgl::SymbolFeature> input1;
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0));
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, bbb, {}, 0));
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{8, 0}, {9, 0}}}, {}, aaa, {}, 0));
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0));
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, {}, aaa, {}, 0));
- input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{5, 0}, {6, 0}}}, {}, aaa, {}, 0));
-
- const std::vector<GeometryTileFeatureStub> expected1 = {
- { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, {} },
- { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {} },
- { {}, FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, {} },
- { {}, FeatureType::LineString, {{}}, {} },
- { {}, FeatureType::LineString, {{}}, {} },
- { {}, FeatureType::LineString, {{}}, {} }
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, properties, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, properties, bbb, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{8, 0}, {9, 0}}}, properties, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, properties, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, properties, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{5, 0}, {6, 0}}}, properties, aaa, {}, 0));
+
+ const std::vector<StubGeometryTileFeature> expected1 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, properties },
+ { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, properties },
+ { {}, FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties }
};
mbgl::util::mergeLines(input1);
@@ -78,14 +59,14 @@ TEST(MergeLines, SameText) {
TEST(MergeLines, BothEnds) {
// mergeLines handles merge from both ends
std::vector<mbgl::SymbolFeature> input2;
- input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
- input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, aaa, {}, 0 });
- input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
-
- const std::vector<GeometryTileFeatureStub> expected2 = {
- { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, {} },
- { {}, FeatureType::LineString, {{}}, {} },
- { {}, FeatureType::LineString, {{}}, {} }
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, properties, aaa, {}, 0 });
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, properties, aaa, {}, 0 });
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, properties, aaa, {}, 0 });
+
+ const std::vector<StubGeometryTileFeature> expected2 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties }
};
mbgl::util::mergeLines(input2);
@@ -98,14 +79,14 @@ TEST(MergeLines, BothEnds) {
TEST(MergeLines, CircularLines) {
// mergeLines handles circular lines
std::vector<mbgl::SymbolFeature> input3;
- input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
- input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
- input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {0, 0}}}, {}, aaa, {}, 0 });
-
- const std::vector<GeometryTileFeatureStub> expected3 = {
- { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, {} },
- { {}, FeatureType::LineString, {{}}, {} },
- { {}, FeatureType::LineString, {{}}, {} }
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, properties, aaa, {}, 0 });
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, properties, aaa, {}, 0 });
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {0, 0}}}, properties, aaa, {}, 0 });
+
+ const std::vector<StubGeometryTileFeature> expected3 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties },
+ { {}, FeatureType::LineString, { emptyLine }, properties }
};
mbgl::util::mergeLines(input3);
@@ -117,9 +98,9 @@ TEST(MergeLines, CircularLines) {
TEST(MergeLines, EmptyOuterGeometry) {
std::vector<mbgl::SymbolFeature> input;
- input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, {}, aaa, {}, 0 });
+ input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, properties, aaa, {}, 0 });
- const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {}, {} } };
+ const std::vector<StubGeometryTileFeature> expected = { { {}, FeatureType::LineString, {}, properties } };
mbgl::util::mergeLines(input);
@@ -128,9 +109,9 @@ TEST(MergeLines, EmptyOuterGeometry) {
TEST(MergeLines, EmptyInnerGeometry) {
std::vector<mbgl::SymbolFeature> input;
- input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{}}, {}, aaa, {}, 0 });
+ input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, properties, aaa, {}, 0 });
- const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {{}}, {} } };
+ const std::vector<StubGeometryTileFeature> expected = { { {}, FeatureType::LineString, {}, properties } };
mbgl::util::mergeLines(input);
diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp
index feaabf2630..09c940c4c3 100644
--- a/test/util/offscreen_texture.test.cpp
+++ b/test/util/offscreen_texture.test.cpp
@@ -3,23 +3,26 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/offscreen_view.hpp>
-#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
#include <mbgl/util/offscreen_texture.hpp>
using namespace mbgl;
TEST(OffscreenTexture, EmptyRed) {
- HeadlessBackend backend { test::sharedDisplay() };
+ HeadlessBackend backend({ 512, 256 });
BackendScope scope { backend };
- OffscreenView view(backend.getContext(), { 512, 256 });
- view.bind();
+
+ // Scissor test shouldn't leak after HeadlessBackend::bind().
+ MBGL_CHECK_ERROR(glScissor(64, 64, 128, 128));
+ backend.getContext().scissorTest.setCurrentValue(true);
+
+ backend.bind();
MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
- auto image = view.readStillImage();
+ auto image = backend.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/empty-red", image, 0, 0);
}
@@ -35,7 +38,7 @@ struct Shader {
MBGL_CHECK_ERROR(glCompileShader(fragmentShader));
MBGL_CHECK_ERROR(glAttachShader(program, fragmentShader));
MBGL_CHECK_ERROR(glLinkProgram(program));
- a_pos = glGetAttribLocation(program, "a_pos");
+ a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
}
~Shader() {
@@ -69,7 +72,7 @@ struct Buffer {
TEST(OffscreenTexture, RenderToTexture) {
- HeadlessBackend backend { test::sharedDisplay() };
+ HeadlessBackend backend({ 512, 256 });
BackendScope scope { backend };
auto& context = backend.getContext();
@@ -114,13 +117,12 @@ void main() {
}
)MBGL_SHADER");
- GLuint u_texture = glGetUniformLocation(compositeShader.program, "u_texture");
+ GLuint u_texture = MBGL_CHECK_ERROR(glGetUniformLocation(compositeShader.program, "u_texture"));
Buffer triangleBuffer({ 0, 0.5, 0.5, -0.5, -0.5, -0.5 });
Buffer viewportBuffer({ -1, -1, 1, -1, -1, 1, 1, 1 });
- OffscreenView view(context, { 512, 256 });
- view.bind();
+ backend.bind();
// First, draw red to the bound FBO.
context.clear(Color::red(), {}, {});
@@ -128,6 +130,11 @@ void main() {
// Then, create a texture, bind it, and render yellow to that texture. This should not
// affect the originally bound FBO.
OffscreenTexture texture(context, { 128, 128 });
+
+ // Scissor test shouldn't leak after OffscreenTexture::bind().
+ MBGL_CHECK_ERROR(glScissor(32, 32, 64, 64));
+ context.scissorTest.setCurrentValue(true);
+
texture.bind();
context.clear(Color(), {}, {});
@@ -143,9 +150,9 @@ void main() {
test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
// Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
- view.bind();
+ backend.bind();
- image = view.readStillImage();
+ image = backend.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
// Now, composite the Framebuffer texture we've rendered to onto the main FBO.
@@ -158,6 +165,6 @@ void main() {
glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
- image = view.readStillImage();
+ image = backend.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1);
}
diff --git a/test/util/thread.test.cpp b/test/util/thread.test.cpp
index 972bddf383..76fb5ce3f0 100644
--- a/test/util/thread.test.cpp
+++ b/test/util/thread.test.cpp
@@ -1,63 +1,58 @@
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/run_loop.hpp>
-
+#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/test/util.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/thread.hpp>
+#include <mbgl/util/timer.hpp>
#include <atomic>
+#include <memory>
+using namespace mbgl;
using namespace mbgl::util;
class TestObject {
public:
- TestObject(std::thread::id otherTid)
+ TestObject(ActorRef<TestObject>, std::thread::id otherTid)
: tid(std::this_thread::get_id()) {
EXPECT_NE(tid, otherTid);
}
- void fn1(int val) {
+ ~TestObject() {
EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(val, 1);
}
- void fn2(std::function<void (int)> cb) {
+ void fn1(int val) const {
EXPECT_EQ(tid, std::this_thread::get_id());
- cb(1);
- }
-
- void transferIn(std::unique_ptr<int> val) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*val, 1);
+ EXPECT_EQ(val, 1);
}
- void transferOut(std::function<void (std::unique_ptr<int>)> cb) {
+ void fn2(std::function<void (int)> cb) const {
EXPECT_EQ(tid, std::this_thread::get_id());
- cb(std::make_unique<int>(1));
+ cb(1);
}
- void transferInOut(std::unique_ptr<int> val, std::function<void (std::unique_ptr<int>)> cb) {
+ void transferIn(std::unique_ptr<int> val) const {
EXPECT_EQ(tid, std::this_thread::get_id());
EXPECT_EQ(*val, 1);
- cb(std::move(val));
}
- void transferInShared(std::shared_ptr<int> val) {
+ void transferInShared(std::shared_ptr<int> val) const {
EXPECT_EQ(tid, std::this_thread::get_id());
EXPECT_EQ(*val, 1);
}
- void transferOutShared(std::function<void (std::shared_ptr<int>)> cb) {
+ void transferString(const std::string& string) const {
EXPECT_EQ(tid, std::this_thread::get_id());
- cb(std::make_shared<int>(1));
+ EXPECT_EQ(string, "test");
}
- void transferString(const std::string& string, std::function<void (std::string)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(string, "test");
- cb(string);
+ void checkContext(std::promise<bool> result) const {
+ result.set_value(tid == std::this_thread::get_id());
}
- void checkContext(std::function<void (bool)> cb) const {
- cb(tid == std::this_thread::get_id());
+ void sync(std::promise<void> result) const {
+ result.set_value();
}
const std::thread::id tid;
@@ -65,95 +60,61 @@ public:
TEST(Thread, invoke) {
const std::thread::id tid = std::this_thread::get_id();
+ Thread<TestObject> thread("Test", tid);
- RunLoop loop;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
+ thread.actor().invoke(&TestObject::fn1, 1);
+ thread.actor().invoke(&TestObject::fn2, [] (int result) { EXPECT_EQ(result, 1); } );
+ thread.actor().invoke(&TestObject::transferIn, std::make_unique<int>(1));
+ thread.actor().invoke(&TestObject::transferInShared, std::make_shared<int>(1));
- loop.invoke([&] {
- EXPECT_EQ(tid, std::this_thread::get_id());
- Thread<TestObject> thread({"Test"}, tid);
-
- thread.invoke(&TestObject::fn1, 1);
- requests.push_back(thread.invokeWithCallback(&TestObject::fn2, [&] (int result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(result, 1);
- }));
-
- thread.invoke(&TestObject::transferIn, std::make_unique<int>(1));
- requests.push_back(thread.invokeWithCallback(&TestObject::transferOut, [&] (std::unique_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, std::make_unique<int>(1), [&] (std::unique_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- thread.invoke(&TestObject::transferInShared, std::make_shared<int>(1));
- requests.push_back(thread.invokeWithCallback(&TestObject::transferOutShared, [&] (std::shared_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- // Cancelled request
- thread.invokeWithCallback(&TestObject::fn2, [&] (int) {
- ADD_FAILURE();
- });
+ std::string test("test");
+ thread.actor().invoke(&TestObject::transferString, test);
- std::string test("test");
- requests.push_back(thread.invokeWithCallback(&TestObject::transferString, test, [&] (std::string result){
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(result, "test");
- loop.stop();
- }));
- test.clear();
- });
-
- loop.run();
+ // Make sure the message queue was consumed before ending the test.
+ std::promise<void> result;
+ auto resultFuture = result.get_future();
+ thread.actor().invoke(&TestObject::sync, std::move(result));
+ resultFuture.get();
}
-TEST(Thread, context) {
+TEST(Thread, Context) {
const std::thread::id tid = std::this_thread::get_id();
+ Thread<TestObject> thread("Test", tid);
- RunLoop loop;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
-
- loop.invoke([&] {
- Thread<TestObject> thread({"Test"}, tid);
-
- requests.push_back(thread.invokeWithCallback(&TestObject::checkContext, [&] (bool inTestThreadContext) {
- EXPECT_EQ(inTestThreadContext, true);
- loop.stop();
- }));
- });
+ std::promise<bool> result;
+ auto resultFuture = result.get_future();
- loop.run();
+ thread.actor().invoke(&TestObject::checkContext, std::move(result));
+ EXPECT_EQ(resultFuture.get(), true);
}
class TestWorker {
public:
- TestWorker() = default;
+ TestWorker(ActorRef<TestWorker>) {}
- void send(std::function<void ()> fn, std::function<void ()> cb) {
- fn();
+ void send(std::function<void ()> cb) {
cb();
}
+
+ void sendDelayed(std::function<void ()> cb) {
+ timer.start(Milliseconds(300), mbgl::Duration::zero(), [cb] {
+ cb();
+ });
+ }
+
+private:
+ Timer timer;
};
TEST(Thread, ExecutesAfter) {
RunLoop loop;
- Thread<TestWorker> thread({"Test"});
+ Thread<TestWorker> thread("Test");
bool didWork = false;
bool didAfter = false;
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- didWork = true;
- }, [&] {
- didAfter = true;
- loop.stop();
- });
+ thread.actor().invoke(&TestWorker::send, [&] { didWork = true; });
+ thread.actor().invoke(&TestWorker::send, [&] { didAfter = true; loop.stop(); });
loop.run();
@@ -161,72 +122,92 @@ TEST(Thread, ExecutesAfter) {
EXPECT_TRUE(didAfter);
}
-TEST(Thread, WorkRequestDeletionWaitsForWorkToComplete) {
+TEST(Thread, CanSelfWakeUp) {
RunLoop loop;
+ Thread<TestWorker> thread("Test");
- Thread<TestWorker> thread({"Test"});
+ thread.actor().invoke(&TestWorker::sendDelayed, [&] {
+ loop.stop();
+ });
- std::promise<void> started;
- bool didWork = false;
+ loop.run();
+}
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- started.set_value();
- usleep(10000);
- didWork = true;
- }, [&] {});
+TEST(Thread, Concurrency) {
+ auto loop = std::make_shared<RunLoop>();
+
+ unsigned numMessages = 100000;
+ std::atomic_uint completed(numMessages);
+
+ ThreadPool threadPool(10);
+ Actor<TestWorker> poolWorker(threadPool);
+ auto poolWorkerRef = poolWorker.self();
+
+ Thread<TestWorker> threadedObject("Test");
+ auto threadedObjectRef = threadedObject.actor();
+
+ // 10 threads sending 100k messages to the Thread. The
+ // idea here is to test if the scheduler is handling concurrency
+ // correctly, otherwise this test should crash.
+ for (unsigned i = 0; i < numMessages; ++i) {
+ poolWorkerRef.invoke(&TestWorker::send, [threadedObjectRef, loop, &completed] () mutable {
+ threadedObjectRef.invoke(&TestWorker::send, [loop, &completed] () {
+ if (!--completed) {
+ loop->stop();
+ }
+ });
+ });
+ };
- started.get_future().get();
- request.reset();
- EXPECT_TRUE(didWork);
+ loop->run();
}
-TEST(Thread, WorkRequestDeletionCancelsAfter) {
- RunLoop loop;
- Thread<TestWorker> thread({"Test"});
+TEST(Thread, ThreadPoolMessaging) {
+ auto loop = std::make_shared<RunLoop>();
- std::promise<void> started;
- bool didAfter = false;
+ ThreadPool threadPool(1);
+ Actor<TestWorker> poolWorker(threadPool);
+ auto poolWorkerRef = poolWorker.self();
+
+ Thread<TestWorker> threadedObject("Test");
+ auto threadedObjectRef = threadedObject.actor();
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- started.set_value();
- }, [&] {
- didAfter = true;
+ // This is sending a message to the Thread from the main
+ // thread. Then the Thread will send another message to
+ // a worker on the ThreadPool.
+ threadedObjectRef.invoke(&TestWorker::send, [poolWorkerRef, loop] () mutable {
+ poolWorkerRef.invoke(&TestWorker::send, [loop] () { loop->stop(); });
});
- started.get_future().get();
- request.reset();
- loop.runOnce();
- EXPECT_FALSE(didAfter);
-}
+ loop->run();
-TEST(Thread, WorkRequestDeletionCancelsImmediately) {
- RunLoop loop;
- Thread<TestWorker> thread({"Test"});
+ // Same as before, but in the opposite direction.
+ poolWorkerRef.invoke(&TestWorker::send, [threadedObjectRef, loop] () mutable {
+ threadedObjectRef.invoke(&TestWorker::send, [loop] () { loop->stop(); });
+ });
- std::promise<void> started;
+ loop->run();
+}
+
+TEST(Thread, ReferenceCanOutliveThread) {
+ auto thread = std::make_unique<Thread<TestWorker>>("Test");
+ auto worker = thread->actor();
- auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] {
- usleep(10000);
- started.set_value();
- }, [&] {});
+ thread.reset();
- auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] {
- ADD_FAILURE() << "Second work item should not be invoked";
- }, [&] {});
- request2.reset();
+ for (unsigned i = 0; i < 1000; ++i) {
+ worker.invoke(&TestWorker::send, [&] { ADD_FAILURE() << "Should never happen"; });
+ }
- started.get_future().get();
- request1.reset();
+ usleep(10000);
}
TEST(Thread, DeletePausedThread) {
- RunLoop loop;
-
std::atomic_bool flag(false);
- auto thread = std::make_unique<Thread<TestWorker>>(ThreadContext{"Test"});
+ auto thread = std::make_unique<Thread<TestWorker>>("Test");
thread->pause();
- thread->invoke(&TestWorker::send, [&] { flag = true; }, [] {});
+ thread->actor().invoke(&TestWorker::send, [&] { flag = true; });
// Should not hang.
thread.reset();
@@ -240,18 +221,18 @@ TEST(Thread, Pause) {
std::atomic_bool flag(false);
- Thread<TestWorker> thread1({"Test1"});
+ Thread<TestWorker> thread1("Test1");
thread1.pause();
- Thread<TestWorker> thread2({"Test2"});
+ Thread<TestWorker> thread2("Test2");
for (unsigned i = 0; i < 100; ++i) {
- thread1.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
- thread2.invoke(&TestWorker::send, [&] { ASSERT_FALSE(flag); }, [] {});
+ thread1.actor().invoke(&TestWorker::send, [&] { flag = true; });
+ thread2.actor().invoke(&TestWorker::send, [&] { ASSERT_FALSE(flag); });
}
// Queue a message at the end of thread2 queue.
- thread2.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+ thread2.actor().invoke(&TestWorker::send, [&] { loop.stop(); });
loop.run();
}
@@ -260,16 +241,16 @@ TEST(Thread, Resume) {
std::atomic_bool flag(false);
- Thread<TestWorker> thread({"Test"});
+ Thread<TestWorker> thread("Test");
thread.pause();
for (unsigned i = 0; i < 100; ++i) {
- thread.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
+ thread.actor().invoke(&TestWorker::send, [&] { flag = true; });
}
// Thread messages are ondered, when we resume, this is going
// to me the last thing to run on the message queue.
- thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+ thread.actor().invoke(&TestWorker::send, [&] { loop.stop(); });
// This test will be flaky if the thread doesn't get paused.
ASSERT_FALSE(flag);
@@ -283,7 +264,7 @@ TEST(Thread, Resume) {
TEST(Thread, PauseResume) {
RunLoop loop;
- Thread<TestWorker> thread({"Test"});
+ Thread<TestWorker> thread("Test");
// Test if multiple pause/resume work.
for (unsigned i = 0; i < 100; ++i) {
@@ -291,6 +272,6 @@ TEST(Thread, PauseResume) {
thread.resume();
}
- thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+ thread.actor().invoke(&TestWorker::send, [&] { loop.stop(); });
loop.run();
}
diff --git a/test/util/thread_local.test.cpp b/test/util/thread_local.test.cpp
index 4ee7042580..7142697f48 100644
--- a/test/util/thread_local.test.cpp
+++ b/test/util/thread_local.test.cpp
@@ -4,13 +4,15 @@
#include <mbgl/test/util.hpp>
+#include <future>
+
using namespace mbgl::util;
namespace {
class TestThread {
public:
- TestThread(int *number_) {
+ TestThread(mbgl::ActorRef<TestThread>, int *number_) {
number.set(number_);
}
@@ -18,8 +20,8 @@ public:
number.set(nullptr);
}
- int getNumber() {
- return *number.get();
+ void getNumber(std::promise<int> result){
+ result.set_value(*number.get());
}
private:
@@ -37,15 +39,28 @@ TEST(ThreadLocalStorage, Basic) {
int number2 = 2;
int number3 = 3;
- ThreadContext context = {"Test"};
+ Thread<TestThread> thread1("Test", &number1);
+ Thread<TestThread> thread2("Test", &number2);
+ Thread<TestThread> thread3("Test", &number3);
+
+ auto thread1Ref = thread1.actor();
+ auto thread2Ref = thread2.actor();
+ auto thread3Ref = thread3.actor();
+
+ std::promise<int> result1;
+ auto result1Future = result1.get_future();
+ thread1Ref.invoke(&TestThread::getNumber, std::move(result1));
+ EXPECT_EQ(number1, result1Future.get());
- Thread<TestThread> thread1(context, &number1);
- Thread<TestThread> thread2(context, &number2);
- Thread<TestThread> thread3(context, &number3);
+ std::promise<int> result2;
+ auto result2Future = result2.get_future();
+ thread2Ref.invoke(&TestThread::getNumber, std::move(result2));
+ EXPECT_EQ(number2, result2Future.get());
- EXPECT_EQ(number1, thread1.invokeSync(&TestThread::getNumber));
- EXPECT_EQ(number2, thread2.invokeSync(&TestThread::getNumber));
- EXPECT_EQ(number3, thread3.invokeSync(&TestThread::getNumber));
+ std::promise<int> result3;
+ auto result3Future = result3.get_future();
+ thread3Ref.invoke(&TestThread::getNumber, std::move(result3));
+ EXPECT_EQ(number3, result3Future.get());
}
TEST(ThreadLocalStorage, NotSetReturnsNull) {
@@ -56,40 +71,38 @@ TEST(ThreadLocalStorage, NotSetReturnsNull) {
namespace {
-struct DtorCounter {
- ~DtorCounter() { ++(*value); }
- unsigned *value;
-};
-
-class TestThreadReclaim {
+class TestThreadDataOwnership {
public:
- TestThreadReclaim(DtorCounter* counter_) {
- counter.set(counter_);
+ TestThreadDataOwnership(mbgl::ActorRef<TestThreadDataOwnership>, int* data_) {
+ data.set(data_);
+ }
+
+ ~TestThreadDataOwnership() {
+ data.set(nullptr);
}
private:
- static ThreadLocal<DtorCounter> counter;
+ static ThreadLocal<int> data;
};
-ThreadLocal<DtorCounter> TestThreadReclaim::counter;
+ThreadLocal<int> TestThreadDataOwnership::data;
} // namespace
-TEST(ThreadLocalStorage, AutoReclaim) {
+TEST(ThreadLocalStorage, ShouldNotTakeOwnership) {
RunLoop loop;
- unsigned counter = 0;
-
- auto dtorCounter1 = new DtorCounter{ &counter };
- auto dtorCounter2 = new DtorCounter{ &counter };
-
- ThreadContext context = {"Test"};
+ auto data1 = std::make_unique<int>(10);
+ auto data2 = std::make_unique<int>(20);
- auto thread1 = std::make_unique<Thread<TestThreadReclaim>>(context, dtorCounter1);
- auto thread2 = std::make_unique<Thread<TestThreadReclaim>>(context, dtorCounter2);
+ auto thread1 = std::make_unique<Thread<TestThreadDataOwnership>>("Test", data1.get());
+ auto thread2 = std::make_unique<Thread<TestThreadDataOwnership>>("Test", data2.get());
thread1.reset();
thread2.reset();
- EXPECT_EQ(counter, 2u);
+ // Will crash if ThreadLocal destroys
+ // the pointer it is managing.
+ ASSERT_EQ(*data1, 10);
+ ASSERT_EQ(*data2, 20);
}
diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp
index c746e6dab5..933c18b5ea 100644
--- a/test/util/tile_cover.test.cpp
+++ b/test/util/tile_cover.test.cpp
@@ -84,3 +84,12 @@ TEST(TileCover, SanFranciscoZ0Wrapped) {
EXPECT_EQ((std::vector<UnwrappedTileID>{ { 0, 1, 0 } }),
util::tileCover(sanFranciscoWrapped, 0));
}
+
+TEST(TileCount, SanFranciscoZ10) {
+ EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10, util::tileSize));
+}
+
+TEST(TileCount, SanFranciscoZ22) {
+ EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22, util::tileSize));
+}
+
diff --git a/test/util/work_queue.test.cpp b/test/util/work_queue.test.cpp
deleted file mode 100644
index 60c72f7358..0000000000
--- a/test/util/work_queue.test.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <mbgl/test/util.hpp>
-
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/work_queue.hpp>
-
-#include <thread>
-
-using namespace mbgl::util;
-
-class TestThread {
-public:
- TestThread(WorkQueue* queue_) : queue(queue_) {}
-
- void send(std::function<void()>&& fn) {
- queue->push(std::move(fn));
- }
-
-private:
- WorkQueue* queue;
-};
-
-TEST(WorkQueue, push) {
- RunLoop loop;
-
- WorkQueue queue;
- Thread<TestThread> thread({"Test"}, &queue);
-
- uint8_t count = 0;
-
- auto endTest = [&]() {
- if (++count == 4) {
- loop.stop();
- }
- };
-
- thread.invoke(&TestThread::send, endTest);
- thread.invoke(&TestThread::send, endTest);
- thread.invoke(&TestThread::send, endTest);
- thread.invoke(&TestThread::send, endTest);
-
- loop.run();
-}
-
-TEST(WorkQueue, cancel) {
- RunLoop loop;
-
- WorkQueue queue;
-
- auto work = [&]() {
- FAIL() << "Should never be called";
- };
-
- queue.push(work);
- queue.push(work);
- queue.push(work);
- queue.push(work);
- queue.push(work);
-}