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.cpp146
-rw-r--r--test/api/annotations.test.cpp109
-rw-r--r--test/api/api_misuse.test.cpp28
-rw-r--r--test/api/custom_layer.test.cpp7
-rw-r--r--test/api/query.test.cpp5
-rw-r--r--test/api/render_missing.test.cpp3
-rw-r--r--test/api/repeated_render.test.cpp81
-rw-r--r--test/fixtures/annotations/readd_image/expected.pngbin0 -> 1031 bytes
-rw-r--r--test/fixtures/api/repeated_render/expected.pngbin0 -> 31046 bytes
-rw-r--r--test/fixtures/api/z0/expected.pngbin0 -> 5042 bytes
-rw-r--r--test/fixtures/api/z1/expected.pngbin0 -> 5648 bytes
-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/offline_download/radar.gifbin0 -> 10958 bytes
-rw-r--r--test/fixtures/offline_download/style.json10
-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/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/geometry/binpack.test.cpp51
-rw-r--r--test/gl/bucket.test.cpp30
-rw-r--r--test/map/map.test.cpp209
-rw-r--r--test/map/transform.test.cpp21
-rw-r--r--test/programs/symbol_program.test.cpp61
-rw-r--r--test/renderer/group_by_layout.test.cpp2
-rw-r--r--test/renderer/image_manager.test.cpp147
-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/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_layer_observer.hpp26
-rw-r--r--test/src/mbgl/test/stub_style_observer.hpp20
-rw-r--r--test/storage/asset_file_source.test.cpp19
-rw-r--r--test/storage/default_file_source.test.cpp25
-rw-r--r--test/storage/local_file_source.test.cpp2
-rw-r--r--test/storage/offline_download.test.cpp11
-rw-r--r--test/storage/resource.test.cpp7
-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/properties.test.cpp (renamed from test/style/paint_property.test.cpp)43
-rw-r--r--test/style/source.test.cpp228
-rw-r--r--test/style/style.test.cpp24
-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.cpp280
-rw-r--r--test/tile/annotation_tile.test.cpp40
-rw-r--r--test/tile/geojson_tile.test.cpp16
-rw-r--r--test/tile/raster_tile.test.cpp13
-rw-r--r--test/tile/vector_tile.test.cpp19
-rw-r--r--test/util/async_task.test.cpp59
-rw-r--r--test/util/image.test.cpp52
-rw-r--r--test/util/memory.test.cpp11
-rw-r--r--test/util/merge_lines.test.cpp7
-rw-r--r--test/util/offscreen_texture.test.cpp14
-rw-r--r--test/util/thread.test.cpp273
-rw-r--r--test/util/thread_local.test.cpp43
-rw-r--r--test/util/work_queue.test.cpp59
78 files changed, 1775 insertions, 1411 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..3d97469628 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.
diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp
index 97ccaae684..7594d5ed73 100644
--- a/test/api/annotations.test.cpp
+++ b/test/api/annotations.test.cpp
@@ -3,6 +3,7 @@
#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>
@@ -16,9 +17,12 @@ 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 {
@@ -42,8 +46,8 @@ 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");
@@ -64,7 +68,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 +83,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 +96,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 +117,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,27 +142,17 @@ 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);
@@ -170,7 +164,7 @@ TEST(Annotations, AddMultiple) {
TEST(Annotations, NonImmediateAdd) {
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::render(test.map, test.view);
Polygon<double> polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} };
@@ -184,9 +178,9 @@ 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);
@@ -198,9 +192,9 @@ 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);
@@ -216,7 +210,7 @@ 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);
@@ -233,7 +227,7 @@ 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);
@@ -250,7 +244,7 @@ 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);
@@ -267,7 +261,7 @@ 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);
@@ -280,8 +274,8 @@ 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);
@@ -298,7 +292,7 @@ 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);
@@ -311,7 +305,7 @@ 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);
}
@@ -319,21 +313,34 @@ TEST(Annotations, ImmediateRemoveShape) {
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.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::render(test.map, test.view);
+
+ 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" });
@@ -356,8 +363,8 @@ TEST(Annotations, QueryFractionalZoomLevels) {
auto viewSize = test.view.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) {
@@ -388,8 +395,8 @@ TEST(Annotations, VisibleFeatures) {
auto viewSize = test.view.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;
@@ -419,6 +426,12 @@ TEST(Annotations, VisibleFeatures) {
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 +439,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 +452,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..54cde8d9b5 100644
--- a/test/api/api_misuse.test.cpp
+++ b/test/api/api_misuse.test.cpp
@@ -44,31 +44,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..2b1138a1d3 100644
--- a/test/api/custom_layer.test.cpp
+++ b/test/api/custom_layer.test.cpp
@@ -7,6 +7,7 @@
#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.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>
@@ -93,9 +94,9 @@ TEST(CustomLayer, Basic) {
ThreadPool threadPool(4);
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+ 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 +111,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);
}
diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp
index c509753d2d..0b6d75ec4f 100644
--- a/test/api/query.test.cpp
+++ b/test/api/query.test.cpp
@@ -8,6 +8,7 @@
#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>
@@ -19,8 +20,8 @@ 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);
diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp
index 6e99501708..2e0c4401f4 100644
--- a/test/api/render_missing.test.cpp
+++ b/test/api/render_missing.test.cpp
@@ -10,6 +10,7 @@
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/style/style.hpp>
#include <future>
@@ -40,7 +41,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
// 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.getStyle().loadJSON(style);
map.renderStill(view, [&](std::exception_ptr err) {
ASSERT_TRUE(err.operator bool());
try {
diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp
index 0b9726d3fa..dd9085efd7 100644
--- a/test/api/repeated_render.test.cpp
+++ b/test/api/repeated_render.test.cpp
@@ -10,6 +10,9 @@
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
#include <future>
@@ -24,7 +27,7 @@ TEST(API, RepeatedRender) {
HeadlessBackend backend { test::sharedDisplay() };
BackendScope scope { backend };
- OffscreenView view { backend.getContext(), { 256, 512 } };
+ OffscreenView view { backend.getContext(), { 512, 512 } };
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
ThreadPool threadPool(4);
@@ -33,7 +36,7 @@ TEST(API, RepeatedRender) {
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
{
- map.setStyleJSON(style);
+ map.getStyle().loadJSON(style);
PremultipliedImage result;
map.renderStill(view, [&](std::exception_ptr) {
result = view.readStillImage();
@@ -43,15 +46,13 @@ TEST(API, RepeatedRender) {
loop.runOnce();
}
- ASSERT_EQ(256u, result.size.width);
+ ASSERT_EQ(512u, result.size.width);
ASSERT_EQ(512u, result.size.height);
-#if !TEST_READ_ONLY
- util::write_file("test/fixtures/api/1.png", encodePNG(result));
-#endif
+ test::checkImage("test/fixtures/api/repeated_render", result, 0.0003, 0.1);
}
{
- map.setStyleJSON(style);
+ map.getStyle().loadJSON(style);
PremultipliedImage result;
map.renderStill(view, [&](std::exception_ptr) {
result = view.readStillImage();
@@ -61,11 +62,69 @@ TEST(API, RepeatedRender) {
loop.runOnce();
}
- ASSERT_EQ(256u, result.size.width);
+ ASSERT_EQ(512u, result.size.width);
ASSERT_EQ(512u, result.size.height);
-#if !TEST_READ_ONLY
- util::write_file("test/fixtures/api/2.png", encodePNG(result));
-#endif
+ test::checkImage("test/fixtures/api/repeated_render", result, 0.0003, 0.1);
+ }
+
+ auto observer = Log::removeObserver();
+ auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+ auto unchecked = flo->unchecked();
+ EXPECT_TRUE(unchecked.empty()) << unchecked;
+}
+
+TEST(API, ZoomHistory) {
+ util::RunLoop loop;
+
+ const auto style = util::read_file("test/fixtures/api/empty.json");
+
+ HeadlessBackend backend { test::sharedDisplay() };
+ BackendScope scope { backend };
+ OffscreenView view { backend.getContext(), { 512, 512 } };
+ DefaultFileSource fileSource(":memory:", ".");
+ ThreadPool threadPool(4);
+
+ Log::setObserver(std::make_unique<FixtureLogObserver>());
+
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
+ map.getStyle().loadJSON(style);
+
+ auto geojson = mapbox::geojson::parse(R"t({ "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [ [ -150, -75 ], [ 150, 75 ] ] } } ] })t");
+ auto source = std::make_unique<mbgl::style::GeoJSONSource>("testSource");
+ source->setGeoJSON(std::move(geojson));
+ map.getStyle().addSource(std::move(source));
+
+ auto layer = std::make_unique<mbgl::style::LineLayer>("testLayer", "testSource");
+ layer->setLineDasharray({ { 1.0f, 2.0f } });
+ layer->setLineWidth({ 16.0f });
+ map.getStyle().addLayer(std::move(layer));
+
+ {
+ PremultipliedImage result;
+ map.renderStill(view, [&](std::exception_ptr) {
+ result = view.readStillImage();
+ });
+
+ while (!result.valid()) {
+ loop.runOnce();
+ }
+
+ test::checkImage("test/fixtures/api/z0", result, 0.0002, 0.1);
+ }
+
+ {
+ map.setZoom(1.0);
+
+ PremultipliedImage result;
+ map.renderStill(view, [&](std::exception_ptr) {
+ result = view.readStillImage();
+ });
+
+ while (!result.valid()) {
+ loop.runOnce();
+ }
+
+ test::checkImage("test/fixtures/api/z1", result, 0.0002, 0.1);
}
auto observer = Log::removeObserver();
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/repeated_render/expected.png b/test/fixtures/api/repeated_render/expected.png
new file mode 100644
index 0000000000..927f6d4c82
--- /dev/null
+++ b/test/fixtures/api/repeated_render/expected.png
Binary files differ
diff --git a/test/fixtures/api/z0/expected.png b/test/fixtures/api/z0/expected.png
new file mode 100644
index 0000000000..0867a8cbf6
--- /dev/null
+++ b/test/fixtures/api/z0/expected.png
Binary files differ
diff --git a/test/fixtures/api/z1/expected.png b/test/fixtures/api/z1/expected.png
new file mode 100644
index 0000000000..897dc196cc
--- /dev/null
+++ b/test/fixtures/api/z1/expected.png
Binary files differ
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/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/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/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/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..ee9ea54414 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -1,28 +1,30 @@
#include <mbgl/test/util.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>
using namespace mbgl;
TEST(Buckets, CircleBucket) {
- CircleBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
+ CircleBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
}
TEST(Buckets, FillBucket) {
- FillBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
+ FillBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
}
TEST(Buckets, LineBucket) {
- LineBucket bucket { { {0, 0, 0}, MapMode::Still }, {}, {} };
+ LineBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {}, {} };
ASSERT_FALSE(bucket.hasData());
}
@@ -36,3 +38,17 @@ TEST(Buckets, SymbolBucket) {
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
}
+
+TEST(Buckets, RasterBucket) {
+ gl::Context context;
+ UnassociatedImage rgba({ 1, 1 });
+
+ RasterBucket bucket = { std::move(rgba) };
+ ASSERT_TRUE(bucket.needsUpload());
+
+ bucket.upload(context);
+ ASSERT_FALSE(bucket.needsUpload());
+
+ bucket.clear();
+ ASSERT_TRUE(bucket.needsUpload());
+}
diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp
index c24f736fcd..a820590fb4 100644
--- a/test/map/map.test.cpp
+++ b/test/map/map.test.cpp
@@ -16,6 +16,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>
@@ -28,6 +29,26 @@ class BackendTest : public HeadlessBackend {
public:
BackendTest() : HeadlessBackend(test::sharedDisplay()) {}
+ void invalidate() {
+ if (invalidateCallback) {
+ invalidateCallback();
+ }
+ }
+
+ std::function<void()> invalidateCallback;
+
+ void onWillStartLoadingMap() final {
+ if (onWillStartLoadingMapCallback) {
+ onWillStartLoadingMapCallback();
+ }
+ }
+
+ void onDidFinishLoadingMap() final {
+ if (onDidFinishLoadingMapCallback) {
+ onDidFinishLoadingMapCallback();
+ }
+ }
+
void onDidFailLoadingMap(std::exception_ptr) final {
if (didFailLoadingMapCallback) {
didFailLoadingMapCallback();
@@ -40,6 +61,8 @@ public:
}
}
+ std::function<void()> onWillStartLoadingMapCallback;
+ std::function<void()> onDidFinishLoadingMapCallback;
std::function<void()> didFailLoadingMapCallback;
std::function<void()> didFinishLoadingStyleCallback;
};
@@ -57,8 +80,6 @@ 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"));
-
map.setLatLngZoom({ 1, 1 }, 0);
auto latLng1 = map.getLatLng();
@@ -123,7 +144,7 @@ TEST(Map, Offline) {
NetworkStatus::Set(NetworkStatus::Status::Offline);
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL(prefix + "style.json");
+ map.getStyle().loadURL(prefix + "style.json");
test::checkImage("test/fixtures/map/offline",
test::render(map, test.view),
@@ -146,7 +167,7 @@ TEST(Map, SetStyleInvalidJSON) {
{
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool,
MapMode::Still);
- map.setStyleJSON("invalid");
+ map.getStyle().loadJSON("invalid");
}
EXPECT_TRUE(fail);
@@ -175,7 +196,7 @@ TEST(Map, SetStyleInvalidURL) {
};
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://bar");
+ map.getStyle().loadURL("mapbox://bar");
test.runLoop.run();
}
@@ -184,8 +205,8 @@ TEST(Map, DoubleStyleLoad) {
MapTest test;
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON("");
- map.setStyleJSON("");
+ map.getStyle().loadJSON("");
+ map.getStyle().loadJSON("");
}
TEST(Map, StyleFresh) {
@@ -195,7 +216,7 @@ TEST(Map, StyleFresh) {
FakeFileSource fileSource;
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
+ map.getStyle().loadURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
Response response;
@@ -215,7 +236,7 @@ TEST(Map, StyleExpired) {
FakeFileSource fileSource;
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
+ map.getStyle().loadURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
Response response;
@@ -225,12 +246,12 @@ TEST(Map, StyleExpired) {
fileSource.respond(Resource::Style, response);
EXPECT_EQ(1u, fileSource.requests.size());
- map.addLayer(std::make_unique<style::BackgroundLayer>("bg"));
+ map.getStyle().addLayer(std::make_unique<style::BackgroundLayer>("bg"));
EXPECT_EQ(1u, fileSource.requests.size());
fileSource.respond(Resource::Style, response);
EXPECT_EQ(0u, fileSource.requests.size());
- EXPECT_NE(nullptr, map.getLayer("bg"));
+ EXPECT_NE(nullptr, map.getStyle().getLayer("bg"));
}
TEST(Map, StyleExpiredWithAnnotations) {
@@ -242,7 +263,7 @@ TEST(Map, StyleExpiredWithAnnotations) {
FakeFileSource fileSource;
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://styles/test");
+ map.getStyle().loadURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
Response response;
@@ -259,6 +280,32 @@ TEST(Map, StyleExpiredWithAnnotations) {
EXPECT_EQ(1u, fileSource.requests.size());
}
+TEST(Map, StyleExpiredWithRender) {
+ // Rendering should not prevent revalidation of an expired style.
+
+ using namespace std::chrono_literals;
+
+ MapTest test;
+ FakeFileSource fileSource;
+
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
+ map.getStyle().loadURL("mapbox://styles/test");
+ EXPECT_EQ(1u, 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());
+
+ map.render(test.view);
+ EXPECT_EQ(1u, fileSource.requests.size());
+
+ fileSource.respond(Resource::Style, response);
+ EXPECT_EQ(1u, fileSource.requests.size());
+}
+
TEST(Map, StyleEarlyMutation) {
// An early mutation should not prevent the initial style load.
@@ -266,15 +313,43 @@ TEST(Map, StyleEarlyMutation) {
FakeFileSource fileSource;
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"));
+ map.getStyle().loadURL("mapbox://styles/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);
EXPECT_EQ(0u, fileSource.requests.size());
- EXPECT_NE(nullptr, map.getLayer("water"));
+ EXPECT_NE(nullptr, map.getStyle().getLayer("water"));
+}
+
+TEST(Map, MapLoadingSignal) {
+ MapTest test;
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
+
+ bool emitted = false;
+ test.backend.onWillStartLoadingMapCallback = [&]() {
+ emitted = true;
+ };
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ EXPECT_TRUE(emitted);
+}
+
+TEST(Map, MapLoadedSignal) {
+ MapTest test;
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Continuous);
+
+ test.backend.onDidFinishLoadingMapCallback = [&]() {
+ test.runLoop.stop();
+ };
+
+ test.backend.invalidateCallback = [&]() {
+ map.render(test.view);
+ };
+
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
+ test.runLoop.run();
}
TEST(Map, StyleLoadedSignal) {
@@ -286,12 +361,12 @@ TEST(Map, StyleLoadedSignal) {
test.backend.didFinishLoadingStyleCallback = [&]() {
emitted = true;
};
- map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
+ 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");
+ map.getStyle().loadJSON("invalid");
EXPECT_FALSE(emitted);
}
@@ -301,7 +376,7 @@ TEST(Map, TEST_REQUIRES_SERVER(StyleNetworkErrorRetry)) {
OnlineFileSource fileSource;
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");
+ map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-500");
test.backend.didFinishLoadingStyleCallback = [&]() {
test.runLoop.stop();
@@ -315,7 +390,7 @@ TEST(Map, TEST_REQUIRES_SERVER(StyleNotFound)) {
OnlineFileSource fileSource;
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");
+ map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-404");
using namespace std::chrono_literals;
util::Timer timer;
@@ -334,7 +409,7 @@ 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");
+ map.getStyle().loadURL("http://127.0.0.1:3000/style-fail-once-404-cache");
test.runLoop.run();
}
@@ -342,11 +417,11 @@ TEST(Map, AddLayer) {
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"));
+ 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.getStyle().addLayer(std::move(layer));
test::checkImage("test/fixtures/map/add_layer", test::render(map, test.view));
}
@@ -359,7 +434,7 @@ TEST(Map, WithoutVAOExtension) {
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+ 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);
}
@@ -368,12 +443,12 @@ TEST(Map, RemoveLayer) {
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"));
+ 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");
+ map.getStyle().addLayer(std::move(layer));
+ map.getStyle().removeLayer("background");
test::checkImage("test/fixtures/map/remove_layer", test::render(map, test.view));
}
@@ -400,7 +475,7 @@ TEST(Map, DisabledSources) {
// 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(
+ map.getStyle().loadJSON(R"STYLE(
{
"version": 8,
"name": "Test",
@@ -439,87 +514,11 @@ TEST(Map, DisabledSources) {
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(Map, DontLoadUnneededTiles) {
MapTest test;
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleJSON(R"STYLE({
+ map.getStyle().loadJSON(R"STYLE({
"sources": {
"a": { "type": "vector", "tiles": [ "a/{z}/{x}/{y}" ] }
},
@@ -616,6 +615,6 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) {
render.send();
};
- map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+ map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
util::RunLoop::Get()->run();
}
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..ef1e71c269
--- /dev/null
+++ b/test/programs/symbol_program.test.cpp
@@ -0,0 +1,61 @@
+#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);
+ EXPECT_EQ(uniformValues.get<uniforms::u_layout_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);
+ EXPECT_EQ(uniformValues.get<uniforms::u_layout_size>().t, 10.0f);
+
+ 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);
+ EXPECT_EQ(uniformValues.get<uniforms::u_layout_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);
+ EXPECT_EQ(uniformValues.get<uniforms::u_layout_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/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..203e05d492
--- /dev/null
+++ b/test/renderer/image_manager.test.cpp
@@ -0,0 +1,147 @@
+#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) final {
+ if (imagesAvailable) imagesAvailable(images);
+ }
+
+ std::function<void (ImageMap)> imagesAvailable;
+};
+
+TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) {
+ ImageManager imageManager;
+ StubImageRequestor requestor;
+ bool notified = false;
+
+ requestor.imagesAvailable = [&] (ImageMap) {
+ notified = true;
+ };
+
+ imageManager.getImages(requestor, {"one"});
+ ASSERT_FALSE(notified);
+
+ imageManager.onSpriteLoaded();
+ ASSERT_TRUE(notified);
+}
+
+TEST(ImageManager, NotifiesRequestorImmediatelyIfDependenciesAreSatisfied) {
+ ImageManager imageManager;
+ StubImageRequestor requestor;
+ bool notified = false;
+
+ requestor.imagesAvailable = [&] (ImageMap) {
+ notified = true;
+ };
+
+ imageManager.addImage(makeMutable<style::Image::Impl>("one", PremultipliedImage({ 16, 16 }), 2));
+ imageManager.getImages(requestor, {"one"});
+
+ 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/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_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/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..41e305a692 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;
@@ -482,7 +484,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,10 +492,27 @@ 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(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());
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_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/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/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/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..eaa3c72877 100644
--- a/test/style/source.test.cpp
+++ b/test/style/source.test.cpp
@@ -7,6 +7,9 @@
#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 +19,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 +29,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 +47,9 @@ public:
Transform transform;
TransformState transformState;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ AnnotationManager annotationManager;
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -54,7 +59,8 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager
};
SourceTest() {
@@ -95,8 +101,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 +124,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 +139,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 +157,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 +177,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 +197,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 +219,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 +257,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 +295,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 +332,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 +369,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 +386,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 +405,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 +424,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 +438,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 +466,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 +485,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 +495,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 +508,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);
+ UnassociatedImage rgba({ 1, 1 });
+ rgba.data[0] = 255;
+ rgba.data[1] = 254;
+ rgba.data[2] = 253;
+ rgba.data[3] = 128;
+
+ // 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..ab58eb1024 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,29 +21,29 @@ 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());
- 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());
- 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());
- style.setJSON(R"STYLE({"pitch": 60})STYLE");
+ style.loadJSON(R"STYLE({"pitch": 60})STYLE");
ASSERT_EQ("", style.getName());
ASSERT_EQ(60, style.getDefaultPitch());
- 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());
@@ -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..efc3912aaa 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,42 @@ 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),
+ style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
};
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, 0);
- ASSERT_TRUE(shapedIcon);
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(anchor, shapedIcon, line, layout, 16.0f, SymbolPlacementType::Point, shapedText);
+
+ EXPECT_EQ(quad.anchorPoint.x, 2);
+ EXPECT_EQ(quad.anchorPoint.y, 3);
+ 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);
+ EXPECT_EQ(quad.anchorAngle, 0.0f);
+ EXPECT_EQ(quad.glyphAngle, 0.0f);
+ EXPECT_EQ(quad.minScale, 0.5f);
}
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),
+ style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
};
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, 0);
- ASSERT_TRUE(shapedIcon);
GeometryCoordinates line;
Shaping shapedText;
@@ -67,21 +61,21 @@ TEST(getIconQuads, style) {
{
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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, shapedText);
+
+ EXPECT_EQ(quad.anchorPoint.x, 0);
+ EXPECT_EQ(quad.anchorPoint.y, 0);
+ 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);
+ EXPECT_EQ(quad.anchorAngle, 0.0f);
+ EXPECT_EQ(quad.glyphAngle, 0.0f);
+ EXPECT_EQ(quad.minScale, 0.5f);
}
// width
@@ -90,16 +84,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(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, 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 +102,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +124,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +142,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(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, 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 +160,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +182,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +200,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(anchor, shapedIcon, line, layout, 24.0f, SymbolPlacementType::Point, 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 +218,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +240,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 +262,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(anchor, shapedIcon, line, layout, 12.0f, SymbolPlacementType::Point, 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 4d71c5b0b4..6d00a3236a 100644
--- a/test/tile/annotation_tile.test.cpp
+++ b/test/tile/annotation_tile.test.cpp
@@ -5,13 +5,17 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/map/query.hpp>
-#include <mbgl/style/style.hpp>
+#include <mbgl/renderer/render_style.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/map/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/map/backend_scope.hpp>
+#include <mbgl/gl/headless_backend.hpp>
#include <memory>
@@ -23,8 +27,12 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ AnnotationManager annotationManager;
+ HeadlessBackend backend { test::sharedDisplay() };
+ BackendScope scope { backend };
+ RenderStyle style { threadPool, fileSource };
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -34,7 +42,8 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager
};
};
@@ -44,15 +53,14 @@ 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),
- 0
+ std::make_unique<FeatureIndex>(),
+ std::move(data),
+ 0
});
auto collisionTile = std::make_unique<CollisionTile>(PlacementConfig());
@@ -64,16 +72,18 @@ TEST(AnnotationTile, Issue8289) {
tile.onPlacement(GeometryTile::PlacementResult {
{},
- std::move(collisionTile),
- 0
+ std::move(collisionTile),
+ {},
+ {},
+ 0
});
// Simulate a second layout with empty data.
tile.onLayout(GeometryTile::LayoutResult {
{},
- std::make_unique<FeatureIndex>(),
- std::make_unique<AnnotationTileData>(),
- 0
+ std::make_unique<FeatureIndex>(),
+ std::make_unique<AnnotationTileData>(),
+ 0
});
std::unordered_map<std::string, std::vector<Feature>> result;
@@ -81,7 +91,7 @@ TEST(AnnotationTile, Issue8289) {
TransformState transformState;
RenderedQueryOptions options;
- tile.queryRenderedFeatures(result, queryGeometry, transformState, options);
+ tile.queryRenderedFeatures(result, queryGeometry, transformState, test.style, options);
EXPECT_TRUE(result.empty());
}
diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp
index a0383f06c9..2aa85c3860 100644
--- a/test/tile/geojson_tile.test.cpp
+++ b/test/tile/geojson_tile.test.cpp
@@ -7,10 +7,11 @@
#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/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 +24,9 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ AnnotationManager annotationManager;
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -35,14 +37,15 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager
};
};
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 +58,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({});
diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp
index f841a82e68..a0666c2146 100644
--- a/test/tile/raster_tile.test.cpp
+++ b/test/tile/raster_tile.test.cpp
@@ -6,10 +6,11 @@
#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 +20,9 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ AnnotationManager annotationManager;
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -31,7 +33,8 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager
};
};
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index 37bfe8512d..f24733dc9b 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -7,13 +7,14 @@
#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/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 +26,9 @@ public:
TransformState transformState;
util::RunLoop loop;
ThreadPool threadPool { 1 };
- AnnotationManager annotationManager { 1.0 };
- style::Style style { threadPool, fileSource, 1.0 };
+ AnnotationManager annotationManager;
+ ImageManager imageManager;
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -37,7 +39,8 @@ public:
fileSource,
MapMode::Continuous,
annotationManager,
- style
+ imageManager,
+ glyphManager
};
};
@@ -68,7 +71,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.
@@ -78,6 +81,8 @@ TEST(VectorTile, Issue7615) {
symbolBucket
}},
nullptr,
+ {},
+ {},
0
});
@@ -89,7 +94,7 @@ TEST(VectorTile, Issue7615) {
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/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..bca538c6c6 100644
--- a/test/util/memory.test.cpp
+++ b/test/util/memory.test.cpp
@@ -9,6 +9,7 @@
#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 +18,7 @@
#include <unordered_map>
#include <utility>
-#include <stdlib.h>
+#include <cstdlib>
#include <unistd.h>
using namespace mbgl;
@@ -75,7 +76,7 @@ TEST(Memory, Vector) {
Map map(test.backend, { 256, 256 }, 2, 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);
}
@@ -84,7 +85,7 @@ TEST(Memory, Raster) {
MemoryTest test;
Map map(test.backend, { 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still);
- map.setStyleURL("mapbox://satellite");
+ map.getStyle().loadURL("mapbox://satellite");
test::render(map, test.view);
}
@@ -118,7 +119,7 @@ TEST(Memory, Footprint) {
auto renderMap = [&](Map& map, const char* style){
map.setZoom(16);
- map.setStyleURL(style);
+ map.getStyle().loadURL(style);
test::render(map, test.view);
};
@@ -159,7 +160,7 @@ TEST(Memory, Footprint) {
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..6c8387c451 100644
--- a/test/util/merge_lines.test.cpp
+++ b/test/util/merge_lines.test.cpp
@@ -2,6 +2,7 @@
#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";
@@ -12,10 +13,10 @@ class GeometryTileFeatureStub : public GeometryTileFeature {
public:
GeometryTileFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
std::unordered_map<std::string, Value> properties_) :
- id(id_),
+ id(std::move(id_)),
type(type_),
- geometry(geometry_),
- properties(properties_)
+ geometry(std::move(geometry_)),
+ properties(std::move(properties_))
{}
FeatureType getType() const override { return type; }
diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp
index feaabf2630..8c0d4f7011 100644
--- a/test/util/offscreen_texture.test.cpp
+++ b/test/util/offscreen_texture.test.cpp
@@ -14,6 +14,11 @@ TEST(OffscreenTexture, EmptyRed) {
HeadlessBackend backend { test::sharedDisplay() };
BackendScope scope { backend };
OffscreenView view(backend.getContext(), { 512, 256 });
+
+ // Scissor test shouldn't leak after OffscreenView::bind().
+ MBGL_CHECK_ERROR(glScissor(64, 64, 128, 128));
+ backend.getContext().scissorTest.setCurrentValue(true);
+
view.bind();
MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
@@ -35,7 +40,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() {
@@ -114,7 +119,7 @@ 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 });
@@ -128,6 +133,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(), {}, {});
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..0590e8b4dc 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();
- Thread<TestThread> thread1(context, &number1);
- Thread<TestThread> thread2(context, &number2);
- Thread<TestThread> thread3(context, &number3);
+ std::promise<int> result1;
+ auto result1Future = result1.get_future();
+ thread1Ref.invoke(&TestThread::getNumber, std::move(result1));
+ EXPECT_EQ(number1, result1Future.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> result2;
+ auto result2Future = result2.get_future();
+ thread2Ref.invoke(&TestThread::getNumber, std::move(result2));
+ EXPECT_EQ(number2, result2Future.get());
+
+ std::promise<int> result3;
+ auto result3Future = result3.get_future();
+ thread3Ref.invoke(&TestThread::getNumber, std::move(result3));
+ EXPECT_EQ(number3, result3Future.get());
}
TEST(ThreadLocalStorage, NotSetReturnsNull) {
@@ -63,7 +78,7 @@ struct DtorCounter {
class TestThreadReclaim {
public:
- TestThreadReclaim(DtorCounter* counter_) {
+ TestThreadReclaim(mbgl::ActorRef<TestThreadReclaim>, DtorCounter* counter_) {
counter.set(counter_);
}
@@ -83,10 +98,8 @@ TEST(ThreadLocalStorage, AutoReclaim) {
auto dtorCounter1 = new DtorCounter{ &counter };
auto dtorCounter2 = new DtorCounter{ &counter };
- ThreadContext context = {"Test"};
-
- auto thread1 = std::make_unique<Thread<TestThreadReclaim>>(context, dtorCounter1);
- auto thread2 = std::make_unique<Thread<TestThreadReclaim>>(context, dtorCounter2);
+ auto thread1 = std::make_unique<Thread<TestThreadReclaim>>("Test", dtorCounter1);
+ auto thread2 = std::make_unique<Thread<TestThreadReclaim>>("Test", dtorCounter2);
thread1.reset();
thread2.reset();
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);
-}