diff options
author | Ansis Brammanis <brammanis@gmail.com> | 2015-05-28 20:01:15 -0400 |
---|---|---|
committer | Ansis Brammanis <brammanis@gmail.com> | 2015-05-28 20:01:15 -0400 |
commit | ff6a5ce5bc674e17a24c3f18b305d5dd2f0e21b0 (patch) | |
tree | 405ec719109186590311262045ff1651b06e9506 /test/resources | |
parent | fd19eb79056b8e62f037c0ae4532f4f7cc970580 (diff) | |
parent | 6c166b564ebb3acefb56bb4d39be4813851db4a7 (diff) | |
download | qtlocation-mapboxgl-ff6a5ce5bc674e17a24c3f18b305d5dd2f0e21b0.tar.gz |
Merge remote-tracking branch 'origin/master' into new-labelling
Conflicts:
src/mbgl/map/source.cpp
src/mbgl/map/source.hpp
src/mbgl/map/tile_data.cpp
src/mbgl/map/tile_parser.cpp
src/mbgl/map/vector_tile_data.cpp
src/mbgl/renderer/painter.cpp
src/mbgl/renderer/symbol_bucket.cpp
src/mbgl/text/glyph.hpp
src/mbgl/text/glyph_store.cpp
src/mbgl/text/placement.cpp
test/suite
Diffstat (limited to 'test/resources')
-rw-r--r-- | test/resources/mock_file_source.cpp | 82 | ||||
-rw-r--r-- | test/resources/mock_file_source.hpp | 40 | ||||
-rw-r--r-- | test/resources/mock_view.hpp | 21 | ||||
-rw-r--r-- | test/resources/resource_loader.cpp | 204 |
4 files changed, 347 insertions, 0 deletions
diff --git a/test/resources/mock_file_source.cpp b/test/resources/mock_file_source.cpp new file mode 100644 index 0000000000..42067a2a73 --- /dev/null +++ b/test/resources/mock_file_source.cpp @@ -0,0 +1,82 @@ +#include "../fixtures/util.hpp" +#include "mock_file_source.hpp" + +#include <mbgl/storage/request.hpp> +#include <mbgl/util/io.hpp> +#include <mbgl/util/thread.hpp> + +namespace mbgl { + +class MockFileSource::Impl { +public: + Impl(uv_loop_t*, Type type, const std::string& match) : type_(type), match_(match) {} + + void handleRequest(Request* req) const; + +private: + void replyWithFailure(Response* res) const; + void replyWithCorruptedData(Response* res, const std::string& url) const; + void replyWithSuccess(Response* res, const std::string& url) const; + + Type type_; + std::string match_; +}; + +void MockFileSource::Impl::replyWithFailure(Response* res) const { + res->status = Response::Status::Error; + res->message = "Failed by the test case"; +} + +void MockFileSource::Impl::replyWithCorruptedData(Response* res, const std::string& url) const { + res->status = Response::Status::Successful; + res->data = util::read_file(url); + res->data.insert(0, "CORRUPTED"); +} + +void MockFileSource::Impl::replyWithSuccess(Response* res, const std::string& url) const { + res->status = Response::Status::Successful; + res->data = util::read_file(url); +} + +void MockFileSource::Impl::handleRequest(Request* req) const { + const std::string& url = req->resource.url; + std::shared_ptr<Response> response = std::make_shared<Response>(); + + if (url.find(match_) == std::string::npos) { + replyWithSuccess(response.get(), url); + req->notify(response); + return; + } + + switch (type_) { + case Type::Success: + replyWithSuccess(response.get(), url); + break; + case Type::RequestFail: + replyWithFailure(response.get()); + break; + case Type::RequestWithCorruptedData: + replyWithCorruptedData(response.get(), url); + break; + default: + EXPECT_TRUE(false) << "Should never be reached."; + } + + req->notify(response); +} + +MockFileSource::MockFileSource(Type type, const std::string& match) + : thread_(std::make_unique<util::Thread<Impl>>("FileSource", util::ThreadPriority::Low, type, match)) { +} + +Request* MockFileSource::request(const Resource& resource, uv_loop_t* loop, Callback callback) { + Request* req = new Request(resource, loop, std::move(callback)); + thread_->invoke(&Impl::handleRequest, req); + + return req; +} + +void MockFileSource::cancel(Request*) { +} + +} diff --git a/test/resources/mock_file_source.hpp b/test/resources/mock_file_source.hpp new file mode 100644 index 0000000000..bb9fb55a30 --- /dev/null +++ b/test/resources/mock_file_source.hpp @@ -0,0 +1,40 @@ +#ifndef TEST_RESOURCES_MOCK_FILE_SOURCE +#define TEST_RESOURCES_MOCK_FILE_SOURCE + +#include <mbgl/storage/file_source.hpp> + +#include <string> +#include <memory> + +namespace mbgl { + +namespace util { +template <typename T> class Thread; +} + +// This mock FileSource will read data from the disk and will fail +// the request if the URL matches a string. +class MockFileSource : public FileSource { +public: + enum Type { + Success, + RequestFail, + RequestWithCorruptedData + }; + + class Impl; + + MockFileSource(Type type, const std::string& match); + ~MockFileSource() override = default; + + // FileSource implementation. + Request* request(const Resource&, uv_loop_t*, Callback) override; + void cancel(Request*) override; + +private: + const std::unique_ptr<util::Thread<Impl>> thread_; +}; + +} + +#endif diff --git a/test/resources/mock_view.hpp b/test/resources/mock_view.hpp new file mode 100644 index 0000000000..865cd2da55 --- /dev/null +++ b/test/resources/mock_view.hpp @@ -0,0 +1,21 @@ +#ifndef TEST_RESOURCES_MOCK_VIEW +#define TEST_RESOURCES_MOCK_VIEW + +#include <mbgl/map/view.hpp> + +namespace mbgl { + +class MockView : public View { +public: + MockView() = default; + + // View implementation. + void activate() override {}; + void deactivate() override {}; + void notify() override {}; + void invalidate(std::function<void()>) override {}; +}; + +} + +#endif diff --git a/test/resources/resource_loader.cpp b/test/resources/resource_loader.cpp new file mode 100644 index 0000000000..7d57f47ee6 --- /dev/null +++ b/test/resources/resource_loader.cpp @@ -0,0 +1,204 @@ +#include "../fixtures/fixture_log_observer.hpp" +#include "../fixtures/util.hpp" +#include "mock_file_source.hpp" +#include "mock_view.hpp" + +#include <mbgl/geometry/glyph_atlas.hpp> +#include <mbgl/geometry/sprite_atlas.hpp> +#include <mbgl/map/environment.hpp> +#include <mbgl/map/map_data.hpp> +#include <mbgl/map/resource_loader.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/style/style.hpp> +#include <mbgl/text/glyph_store.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> + +using namespace mbgl; + +namespace { + +class MockMapContext : public ResourceLoader::Observer { +public: + MockMapContext(uv_loop_t* loop, + View& view, + FileSource& fileSource, + const std::function<void(std::exception_ptr error)>& callback) + : env_(fileSource), + envScope_(env_, ThreadType::Map, "Map"), + data_(view, MapMode::Still), + glyphStore_(std::make_unique<GlyphStore>(loop, env_)), + glyphAtlas_(std::make_unique<GlyphAtlas>(1024, 1024)), + spriteAtlas_(std::make_unique<SpriteAtlas>(512, 512)), + texturePool_(std::make_unique<TexturePool>()), + style_(std::make_unique<Style>()), + resourceLoader_(std::make_unique<ResourceLoader>()), + asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })), + callback_(callback) { + asyncUpdate->unref(); + + data_.transform.resize(1000, 1000, 1.0, 1000, 1000); + data_.transform.setLatLngZoom({0, 0}, 16); + + const std::string style = util::read_file("test/fixtures/resources/style.json"); + style_->loadJSON(reinterpret_cast<const uint8_t *>(style.c_str())); + + glyphStore_->setURL(style_->glyph_url); + + resourceLoader_->setGlyphStore(glyphStore_.get()); + resourceLoader_->setObserver(this); + resourceLoader_->setStyle(style_.get()); + } + + ~MockMapContext() { + resourceLoader_.reset(); + style_.reset(); + texturePool_.reset(); + spriteAtlas_.reset(); + glyphAtlas_.reset(); + glyphStore_.reset(); + } + + void update() { + const auto now = Clock::now(); + + data_.setAnimationTime(now); + data_.transform.updateTransitions(now); + + transformState_ = data_.transform.currentState(); + + resourceLoader_->update( + data_, transformState_, *glyphAtlas_, *spriteAtlas_, *texturePool_); + } + + // ResourceLoader::Observer implementation. + void onTileDataChanged() override { + util::ptr<Sprite> sprite = resourceLoader_->getSprite(); + if (sprite && sprite->isLoaded() && style_->isLoaded()) { + callback_(nullptr); + } + + asyncUpdate->send(); + }; + + void onResourceLoadingFailed(std::exception_ptr error) override { + callback_(error); + } + +private: + Environment env_; + EnvironmentScope envScope_; + + MapData data_; + TransformState transformState_; + + std::unique_ptr<GlyphStore> glyphStore_; + std::unique_ptr<GlyphAtlas> glyphAtlas_; + std::unique_ptr<SpriteAtlas> spriteAtlas_; + std::unique_ptr<TexturePool> texturePool_; + std::unique_ptr<Style> style_; + std::unique_ptr<ResourceLoader> resourceLoader_; + + std::unique_ptr<uv::async> asyncUpdate; + + std::function<void(std::exception_ptr error)> callback_; +}; + +void runTestCase(MockFileSource::Type type, + const std::string& param, + const std::string& message) { + util::RunLoop loop(uv_default_loop()); + + MockView view; + MockFileSource fileSource(type, param); + + FixtureLogObserver* log = new FixtureLogObserver(); + Log::setObserver(std::unique_ptr<Log::Observer>(log)); + + auto callback = [&loop, ¶m](std::exception_ptr error) { + try { + if (error) { + std::rethrow_exception(error); + } + } catch (const util::GlyphRangeLoadingException&) { + EXPECT_EQ(param, "glyphs.pbf"); + } catch (const util::SourceLoadingException&) { + EXPECT_EQ(param, "source.json"); + } catch (const util::SpriteLoadingException&) { + EXPECT_TRUE(param == "sprite.png" || param == "sprite.json"); + } catch (const util::TileLoadingException&) { + EXPECT_EQ(param, "vector.pbf"); + } catch (const std::exception&) { + EXPECT_TRUE(false) << "Unhandled exception."; + } + + loop.stop(); + }; + + std::unique_ptr<util::Thread<MockMapContext>> context( + std::make_unique<util::Thread<MockMapContext>>( + "Map", util::ThreadPriority::Regular, view, fileSource, callback)); + + uv_run(loop.get(), UV_RUN_DEFAULT); + + // Needed because it will make the Map thread + // join and cease logging after this point. + context.reset(); + + const FixtureLogObserver::LogMessage logMessage { + EventSeverity::Error, + Event::ResourceLoader, + int64_t(-1), + message, + }; + + if (type == MockFileSource::Success) { + EXPECT_EQ(log->count(logMessage), 0u); + } else { + EXPECT_GT(log->count(logMessage), 0u); + } + + // Clear the remaining error messages + log->unchecked().size(); +} + +} + +class ResourceLoaderTest : public ::testing::TestWithParam<std::string> { +}; + +TEST_P(ResourceLoaderTest, Success) { + runTestCase(MockFileSource::Success, GetParam(), std::string()); +} + +TEST_P(ResourceLoaderTest, RequestFail) { + std::stringstream message; + message << "Failed to load [test/fixtures/resources/" << GetParam() << "]: Failed by the test case"; + + runTestCase(MockFileSource::RequestFail, GetParam(), message.str()); +} + +TEST_P(ResourceLoaderTest, RequestWithCorruptedData) { + const std::string param(GetParam()); + + std::stringstream message; + message << "Failed to parse "; + + if (param == "vector.pbf") { + message << "[15/16384/16384]: pbf unknown field type exception"; + } else { + message << "[test/fixtures/resources/" << param << "]"; + } + + if (param.find("json") != std::string::npos) { + message << ": 0 - Expect either an object or array at root"; + } + + runTestCase(MockFileSource::RequestWithCorruptedData, GetParam(), message.str()); +} + +INSTANTIATE_TEST_CASE_P(ResourceLoader, ResourceLoaderTest, + ::testing::Values("source.json", "sprite.json", "sprite.png", "vector.pbf", "glyphs.pbf")); |