summaryrefslogtreecommitdiff
path: root/test/style
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-02-01 14:07:26 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-02-01 15:29:42 -0800
commit716997b99eed50ecf35fd1ec3124a85760a05753 (patch)
treed2314e6ba16273b4ab232d2c38995d1ce59210eb /test/style
parent0e66d4dcc53fad046673346f3db83346ad54e3e8 (diff)
downloadqtlocation-mapboxgl-716997b99eed50ecf35fd1ec3124a85760a05753.tar.gz
[tests] Refactor and make MockFileSource more general
Now it works more like StubStyleObserver: you can assign std::functions to specific slots based on resource type. Rewrite resource loading tests in that style, making them less like integration tests of Style and more like unit tests of Source, GlyphStore, and SpriteStore.
Diffstat (limited to 'test/style')
-rw-r--r--test/style/glyph_store.cpp81
-rw-r--r--test/style/pending_resources.cpp62
-rw-r--r--test/style/resource_loading.cpp283
-rw-r--r--test/style/source.cpp290
-rw-r--r--test/style/style.cpp45
5 files changed, 379 insertions, 382 deletions
diff --git a/test/style/glyph_store.cpp b/test/style/glyph_store.cpp
index 0215dff3ff..a4bc0e3135 100644
--- a/test/style/glyph_store.cpp
+++ b/test/style/glyph_store.cpp
@@ -1,22 +1,21 @@
#include "../fixtures/util.hpp"
-#include "../fixtures/mock_file_source.hpp"
+#include "../fixtures/stub_file_source.hpp"
#include "../fixtures/stub_style_observer.hpp"
#include <mbgl/text/font_stack.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/io.hpp>
#include <mbgl/platform/log.hpp>
using namespace mbgl;
class GlyphStoreTest {
public:
- GlyphStoreTest(MockFileSource::Type type, const std::string& resource)
- : fileSource(type, resource) {}
-
util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
util::RunLoop loop;
- MockFileSource fileSource;
+ StubFileSource fileSource;
StubStyleObserver observer;
GlyphStore glyphStore;
@@ -40,7 +39,14 @@ public:
};
TEST(GlyphStore, LoadingSuccess) {
- GlyphStoreTest test(MockFileSource::Success, "");
+ GlyphStoreTest test;
+
+ test.fileSource.glyphsResponse = [&] (const Resource& resource) {
+ EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
+ Response response;
+ response.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/glyphs.pbf"));
+ return response;
+ };
test.observer.glyphsError = [&] (const std::string&, const GlyphRange&, std::exception_ptr) {
FAIL();
@@ -64,12 +70,22 @@ TEST(GlyphStore, LoadingSuccess) {
}
TEST(GlyphStore, LoadingFail) {
- GlyphStoreTest test(MockFileSource::RequestFail, "glyphs.pbf");
+ GlyphStoreTest test;
+
+ test.fileSource.glyphsResponse = [&] (const Resource&) {
+ Response response;
+ response.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other,
+ "Failed by the test case");
+ return response;
+ };
test.observer.glyphsError = [&] (const std::string& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
- ASSERT_TRUE(error != nullptr);
- ASSERT_EQ(fontStack, "Test Stack");
- ASSERT_EQ(glyphRange, GlyphRange(0, 255));
+ EXPECT_EQ(fontStack, "Test Stack");
+ EXPECT_EQ(glyphRange, GlyphRange(0, 255));
+
+ EXPECT_TRUE(error != nullptr);
+ EXPECT_EQ(util::toString(error), "Failed by the test case");
auto stack = test.glyphStore.getFontStack("Test Stack");
ASSERT_TRUE(stack->getSDFs().empty());
@@ -85,12 +101,20 @@ TEST(GlyphStore, LoadingFail) {
}
TEST(GlyphStore, LoadingCorrupted) {
- GlyphStoreTest test(MockFileSource::RequestWithCorruptedData, "glyphs.pbf");
+ GlyphStoreTest test;
+
+ test.fileSource.glyphsResponse = [&] (const Resource&) {
+ Response response;
+ response.data = std::make_unique<std::string>("CORRUPTED");
+ return response;
+ };
test.observer.glyphsError = [&] (const std::string& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
- ASSERT_TRUE(error != nullptr);
- ASSERT_EQ(fontStack, "Test Stack");
- ASSERT_EQ(glyphRange, GlyphRange(0, 255));
+ EXPECT_EQ(fontStack, "Test Stack");
+ EXPECT_EQ(glyphRange, GlyphRange(0, 255));
+
+ EXPECT_TRUE(error != nullptr);
+ EXPECT_EQ(util::toString(error), "pbf unknown field type exception");
auto stack = test.glyphStore.getFontStack("Test Stack");
ASSERT_TRUE(stack->getSDFs().empty());
@@ -106,36 +130,19 @@ TEST(GlyphStore, LoadingCorrupted) {
}
TEST(GlyphStore, LoadingCancel) {
- GlyphStoreTest test(MockFileSource::Success, "glyphs.pbf");
+ GlyphStoreTest test;
- test.observer.glyphsLoaded = [&] (const std::string&, const GlyphRange&) {
- FAIL() << "Should never be called";
- };
-
- test.fileSource.requestEnqueuedCallback = [&]{
+ test.fileSource.glyphsResponse = [&] (const Resource&) {
test.end();
+ return Response();
};
- test.run(
- "test/fixtures/resources/glyphs.pbf",
- "Test Stack",
- {{0, 255}});
-}
-
-TEST(GlyphStore, InvalidURL) {
- GlyphStoreTest test(MockFileSource::Success, "");
-
- test.observer.glyphsError = [&] (const std::string&, const GlyphRange&, std::exception_ptr error) {
- ASSERT_TRUE(error != nullptr);
-
- auto stack = test.glyphStore.getFontStack("Test Stack");
- ASSERT_TRUE(stack->getSDFs().empty());
-
- test.end();
+ test.observer.glyphsLoaded = [&] (const std::string&, const GlyphRange&) {
+ FAIL() << "Should never be called";
};
test.run(
- "foo bar",
+ "test/fixtures/resources/glyphs.pbf",
"Test Stack",
{{0, 255}});
}
diff --git a/test/style/pending_resources.cpp b/test/style/pending_resources.cpp
deleted file mode 100644
index 1115274227..0000000000
--- a/test/style/pending_resources.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "../fixtures/fixture_log_observer.hpp"
-#include "../fixtures/mock_file_source.hpp"
-#include "../fixtures/util.hpp"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/platform/default/headless_display.hpp>
-#include <mbgl/platform/default/headless_view.hpp>
-#include <mbgl/util/async_task.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-using namespace mbgl;
-
-class PendingResources : public ::testing::TestWithParam<std::string> {
-};
-
-// This test will load a Style but one of the resources requested will not be
-// replied immediately like the others. We get an notification by the
-// MockFileSource when some resource is artificially delayed and we destroy
-// the Map object after that. The idea here is to test if these pending requests
-// are getting canceled correctly if on shutdown.
-TEST_P(PendingResources, DeleteMapObjectWithPendingRequest) {
- util::RunLoop loop;
-
- auto display = std::make_shared<mbgl::HeadlessDisplay>();
- HeadlessView view(display, 1, 1000, 1000);
- MockFileSource fileSource(MockFileSource::Success, GetParam());
-
- std::unique_ptr<Map> map = std::make_unique<Map>(view, fileSource, MapMode::Still);
-
- util::AsyncTask endTest([&map, &loop] {
- map.reset();
- loop.stop();
- });
-
- fileSource.requestEnqueuedCallback = [&endTest] { endTest.send(); };
-
- const std::string style = util::read_file("test/fixtures/resources/style.json");
- map->setStyleJSON(style, ".");
-
- map->renderStill([](std::exception_ptr, PremultipliedImage&&) {
- EXPECT_TRUE(false) << "Should never happen.";
- });
-
- loop.run();
-}
-
-// In the test data below, "sprite" will match both "sprite.json" and "sprite.png" and cause two
-// requests to be canceled. "resources" will match everything but in practice will only test the
-// cancellation of the sprites and "source_*.json" because we only load the rest after "source_*.json"
-// gets parsed.
-INSTANTIATE_TEST_CASE_P(Style, PendingResources,
- ::testing::Values(
- "source_raster.json",
- "source_vector.json",
- "sprite.json",
- "sprite.png",
- "sprite",
- "raster.png",
- "vector.pbf",
- "glyphs.pbf",
- "resources"));
diff --git a/test/style/resource_loading.cpp b/test/style/resource_loading.cpp
deleted file mode 100644
index b4a539643a..0000000000
--- a/test/style/resource_loading.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-#include "../fixtures/fixture_log_observer.hpp"
-#include "../fixtures/util.hpp"
-#include "../fixtures/mock_file_source.hpp"
-#include "../fixtures/mock_view.hpp"
-#include "../fixtures/stub_style_observer.hpp"
-
-#include <mbgl/map/map_data.hpp>
-#include <mbgl/map/transform.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/texture_pool.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/string.hpp>
-
-using namespace mbgl;
-
-class ResourceLoadingTest {
-public:
- ResourceLoadingTest(MockFileSource::Type type, const std::string& resource)
- : fileSource(type, resource) {}
-
- util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
- util::RunLoop loop;
- MockFileSource fileSource;
- StubStyleObserver observer;
- std::function<void ()> onFullyLoaded;
-
- MapData data { MapMode::Still, GLContextMode::Unique, 1.0 };
- MockView view;
- Transform transform { view, ConstrainMode::HeightOnly };
- TexturePool texturePool;
- Style style { data };
-
- void run(const std::string& stylePath) {
- // Squelch logging.
- Log::setObserver(std::make_unique<Log::NullObserver>());
-
- util::ThreadContext::Set(&context);
- util::ThreadContext::setFileSource(&fileSource);
-
- observer.resourceLoaded = [&] () {
- style.update(transform.getState(), texturePool);
- if (style.isLoaded() && onFullyLoaded) {
- onFullyLoaded();
- }
- };
-
- transform.resize({{ 512, 512 }});
- transform.setLatLngZoom({0, 0}, 0);
-
- style.setObserver(&observer);
- style.setJSON(util::read_file(stylePath), "");
- style.cascade();
- style.recalculate(0);
-
- loop.run();
- }
-
- void end() {
- loop.stop();
- }
-};
-
-TEST(ResourceLoading, Success) {
- ResourceLoadingTest test(MockFileSource::Success, "");
-
- test.observer.resourceError = [&] (std::exception_ptr error) {
- FAIL() << util::toString(error);
- };
-
- test.onFullyLoaded = [&] () {
- SUCCEED();
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, RasterSourceFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "source_raster.json");
-
- test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
- EXPECT_EQ(source.id, "rastersource");
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, VectorSourceFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "source_vector.json");
-
- test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
- EXPECT_EQ(source.id, "vectorsource");
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, SpriteJSONFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "sprite.json");
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, SpriteImageFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "sprite.png");
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, RasterTileFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "raster.png");
-
- test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source.id, "rastersource");
- EXPECT_EQ(std::string(tileID), "0/0/0");
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, VectorTileFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "vector.pbf");
-
- test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source.id, "vectorsource");
- EXPECT_EQ(std::string(tileID), "0/0/0");
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, GlyphsFail) {
- ResourceLoadingTest test(MockFileSource::RequestFail, "glyphs.pbf");
-
- test.observer.glyphsError = [&] (const std::string& fontStack, const GlyphRange&, std::exception_ptr error) {
- EXPECT_EQ(fontStack, "Open Sans Regular,Arial Unicode MS Regular");
- EXPECT_EQ(util::toString(error), "Failed by the test case");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, RasterSourceCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "source_raster.json");
-
- test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
- EXPECT_EQ(source.id, "rastersource");
- EXPECT_EQ(util::toString(error), "0 - Invalid value.");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, VectorSourceCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "source_vector.json");
-
- test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
- EXPECT_EQ(source.id, "vectorsource");
- EXPECT_EQ(util::toString(error), "0 - Invalid value.");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, SpriteJSONCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "sprite.json");
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_EQ(util::toString(error), "Failed to parse JSON: Invalid value. at offset 0");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, SpriteImageCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "sprite.png");
-
- test.observer.spriteError = [&] (std::exception_ptr error) {
- EXPECT_TRUE(bool(error));
- // Not asserting on platform-specific error text.
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, RasterTileCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "raster.png");
-
- test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source.id, "rastersource");
- EXPECT_EQ(std::string(tileID), "0/0/0");
- EXPECT_TRUE(bool(error));
- // Not asserting on platform-specific error text.
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, VectorTileCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "vector.pbf");
-
- test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
- EXPECT_EQ(source.id, "vectorsource");
- EXPECT_EQ(std::string(tileID), "0/0/0");
- EXPECT_EQ(util::toString(error), "pbf unknown field type exception");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, GlyphsCorrupt) {
- ResourceLoadingTest test(MockFileSource::RequestWithCorruptedData, "glyphs.pbf");
-
- test.observer.glyphsError = [&] (const std::string& fontStack, const GlyphRange&, std::exception_ptr error) {
- EXPECT_EQ(fontStack, "Open Sans Regular,Arial Unicode MS Regular");
- EXPECT_EQ(util::toString(error), "pbf unknown field type exception");
- test.end();
- };
-
- test.run("test/fixtures/resources/style.json");
-}
-
-TEST(ResourceLoading, UnusedSource) {
- ResourceLoadingTest test(MockFileSource::Success, "");
-
- test.onFullyLoaded = [&] () {
- Source *usedSource = test.style.getSource("usedsource");
- EXPECT_TRUE(usedSource);
- EXPECT_TRUE(usedSource->isLoaded());
-
- Source *unusedSource = test.style.getSource("unusedsource");
- EXPECT_TRUE(unusedSource);
- EXPECT_FALSE(unusedSource->isLoaded());
-
- test.end();
- };
-
- test.run("test/fixtures/resources/style-unused-sources.json");
-}
-
-TEST(ResourceLoading, UnusedSourceActiveViaClassUpdate) {
- ResourceLoadingTest test(MockFileSource::Success, "");
-
- test.data.addClass("visible");
-
- test.onFullyLoaded = [&] () {
- Source *unusedSource = test.style.getSource("unusedsource");
- EXPECT_TRUE(unusedSource);
- EXPECT_TRUE(unusedSource->isLoaded());
-
- test.end();
- };
-
- test.run("test/fixtures/resources/style-unused-sources.json");
-}
diff --git a/test/style/source.cpp b/test/style/source.cpp
new file mode 100644
index 0000000000..d1944f3842
--- /dev/null
+++ b/test/style/source.cpp
@@ -0,0 +1,290 @@
+#include "../fixtures/util.hpp"
+#include "../fixtures/stub_file_source.hpp"
+#include "../fixtures/mock_view.hpp"
+#include "../fixtures/stub_style_observer.hpp"
+
+#include <mbgl/map/source.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <mbgl/map/transform.hpp>
+#include <mbgl/map/map_data.hpp>
+#include <mbgl/util/worker.hpp>
+#include <mbgl/util/texture_pool.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_update_parameters.hpp>
+#include <mbgl/layer/line_layer.hpp>
+
+using namespace mbgl;
+
+class SourceTest {
+public:
+ util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
+ util::RunLoop loop;
+ StubFileSource fileSource;
+ StubStyleObserver observer;
+ MockView view;
+ Transform transform { view, ConstrainMode::HeightOnly };
+ TransformState transformState;
+ Worker worker { 1 };
+ TexturePool texturePool;
+ MapData mapData { MapMode::Still, GLContextMode::Unique, 1.0 };
+ Style style { mapData };
+
+ StyleUpdateParameters updateParameters {
+ 1.0,
+ MapDebugOptions(),
+ TimePoint(),
+ transformState,
+ worker,
+ texturePool,
+ true,
+ MapMode::Continuous,
+ mapData,
+ style
+ };
+
+ SourceTest() {
+ // Squelch logging.
+ Log::setObserver(std::make_unique<Log::NullObserver>());
+
+ util::ThreadContext::Set(&context);
+ util::ThreadContext::setFileSource(&fileSource);
+
+ transform.resize({{ 512, 512 }});
+ transform.setLatLngZoom({0, 0}, 0);
+
+ transformState = transform.getState();
+ }
+
+ void run() {
+ loop.run();
+ }
+
+ void end() {
+ loop.stop();
+ }
+};
+
+TEST(Source, LoadingFail) {
+ SourceTest test;
+
+ test.fileSource.sourceResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("url", resource.url);
+ Response response;
+ response.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other,
+ "Failed by the test case");
+ return response;
+ };
+
+ test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
+ EXPECT_EQ("url", source.url);
+ EXPECT_EQ("Failed by the test case", util::toString(error));
+ test.end();
+ };
+
+ Source source(SourceType::Vector, "source", "url", 512, nullptr, nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+
+ test.run();
+}
+
+TEST(Source, LoadingCorrupt) {
+ SourceTest test;
+
+ test.fileSource.sourceResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("url", resource.url);
+ Response response;
+ response.data = std::make_unique<std::string>("CORRUPTED");
+ return response;
+ };
+
+ test.observer.sourceError = [&] (Source& source, std::exception_ptr error) {
+ EXPECT_EQ("url", source.url);
+ EXPECT_EQ("0 - Invalid value.", util::toString(error));
+ test.end();
+ };
+
+ Source source(SourceType::Vector, "source", "url", 512, nullptr, nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+
+ test.run();
+}
+
+TEST(Source, RasterTileFail) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other,
+ "Failed by the test case");
+ return response;
+ };
+
+ test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
+ EXPECT_EQ(SourceType::Raster, source.type);
+ EXPECT_EQ("0/0/0", std::string(tileID));
+ EXPECT_EQ("Failed by the test case", util::toString(error));
+ test.end();
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, VectorTileFail) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other,
+ "Failed by the test case");
+ return response;
+ };
+
+ test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
+ EXPECT_EQ(SourceType::Vector, source.type);
+ EXPECT_EQ("0/0/0", std::string(tileID));
+ EXPECT_EQ("Failed by the test case", util::toString(error));
+ test.end();
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, RasterTileCorrupt) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.data = std::make_unique<std::string>("CORRUPTED");
+ return response;
+ };
+
+ test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
+ EXPECT_EQ(source.type, SourceType::Raster);
+ EXPECT_EQ(std::string(tileID), "0/0/0");
+ EXPECT_TRUE(bool(error));
+ // Not asserting on platform-specific error text.
+ test.end();
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, VectorTileCorrupt) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.data = std::make_unique<std::string>("CORRUPTED");
+ return response;
+ };
+
+ test.observer.tileError = [&] (Source& source, const TileID& tileID, std::exception_ptr error) {
+ EXPECT_EQ(source.type, SourceType::Vector);
+ EXPECT_EQ(std::string(tileID), "0/0/0");
+ EXPECT_EQ(util::toString(error), "pbf unknown field type exception");
+ test.end();
+ };
+
+ // Need to have at least one layer that uses the source.
+ auto layer = std::make_unique<LineLayer>();
+ layer->source = "source";
+ layer->sourceLayer = "water";
+ test.style.addLayer(std::move(layer));
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, RasterTileCancel) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ test.end();
+ return Response();
+ };
+
+ test.observer.tileLoaded = [&] (Source&, const TileID&, bool) {
+ FAIL() << "Should never be called";
+ };
+
+ test.observer.tileError = [&] (Source&, const TileID&, std::exception_ptr) {
+ FAIL() << "Should never be called";
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, VectorTileCancel) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ test.end();
+ return Response();
+ };
+
+ test.observer.tileLoaded = [&] (Source&, const TileID&, bool) {
+ FAIL() << "Should never be called";
+ };
+
+ test.observer.tileError = [&] (Source&, const TileID&, std::exception_ptr) {
+ FAIL() << "Should never be called";
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load();
+ source.update(test.updateParameters);
+
+ test.run();
+}
diff --git a/test/style/style.cpp b/test/style/style.cpp
new file mode 100644
index 0000000000..59366ea7dd
--- /dev/null
+++ b/test/style/style.cpp
@@ -0,0 +1,45 @@
+#include "../fixtures/util.hpp"
+
+#include <mbgl/map/map_data.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/util/io.hpp>
+
+using namespace mbgl;
+
+TEST(Style, UnusedSource) {
+ util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
+ util::ThreadContext::Set(&context);
+
+ MapData data { MapMode::Still, GLContextMode::Unique, 1.0 };
+ Style style { data };
+
+ style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"), "");
+ style.cascade();
+ style.recalculate(0);
+
+ Source *usedSource = style.getSource("usedsource");
+ EXPECT_TRUE(usedSource);
+ EXPECT_TRUE(usedSource->isLoaded());
+
+ Source *unusedSource = style.getSource("unusedsource");
+ EXPECT_TRUE(unusedSource);
+ EXPECT_FALSE(unusedSource->isLoaded());
+}
+
+TEST(Style, UnusedSourceActiveViaClassUpdate) {
+ util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
+ util::ThreadContext::Set(&context);
+
+ MapData data { MapMode::Still, GLContextMode::Unique, 1.0 };
+ Style style { data };
+
+ data.addClass("visible");
+
+ style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"), "");
+ style.cascade();
+ style.recalculate(0);
+
+ Source *unusedSource = style.getSource("unusedsource");
+ EXPECT_TRUE(unusedSource);
+ EXPECT_TRUE(unusedSource->isLoaded());
+}