diff options
Diffstat (limited to 'test/util')
-rw-r--r-- | test/util/http_timeout.test.cpp | 15 | ||||
-rw-r--r-- | test/util/image.test.cpp | 29 | ||||
-rw-r--r-- | test/util/mapbox.test.cpp | 3 | ||||
-rw-r--r-- | test/util/memory.test.cpp | 54 | ||||
-rw-r--r-- | test/util/merge_lines.test.cpp | 136 | ||||
-rw-r--r-- | test/util/offscreen_texture.test.cpp | 88 | ||||
-rw-r--r-- | test/util/thread.test.cpp | 78 | ||||
-rw-r--r-- | test/util/url.test.cpp | 20 |
8 files changed, 291 insertions, 132 deletions
diff --git a/test/util/http_timeout.test.cpp b/test/util/http_timeout.test.cpp index e99c703159..c9373d955d 100644 --- a/test/util/http_timeout.test.cpp +++ b/test/util/http_timeout.test.cpp @@ -2,22 +2,25 @@ #include <mbgl/util/logging.hpp> #include <mbgl/util/http_timeout.hpp> -#include <regex> -#include <iostream> using namespace mbgl; using namespace mbgl::http; TEST(HttpRetry, OtherError) { - //Non-retryable + // Non-retryable ASSERT_EQ(Duration::max(), errorRetryTimeout(Response::Error::Reason::Other, 1)); } +TEST(HttpRetry, NotFound) { + // Non-retryable + ASSERT_EQ(Duration::max(), errorRetryTimeout(Response::Error::Reason::NotFound, 1)); +} + TEST(HttpRetry, ServerError) { // 1-3 failures -> 1 sec ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 1)); ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 3)); - + // After 3, exponential backoff ASSERT_EQ(Seconds(2), errorRetryTimeout(Response::Error::Reason::Server, 4)); ASSERT_EQ(Seconds(1u << 31), errorRetryTimeout(Response::Error::Reason::Server, 50)); @@ -32,8 +35,8 @@ TEST(HttpRetry, ConnectionError) { TEST(HttpRetry, RateLimit) { // Pre-set value from header ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 1, { util::now() + Seconds(1) })); - - //Default + + // Default ASSERT_EQ(Seconds(5), errorRetryTimeout(Response::Error::Reason::RateLimit, 1, {})); } diff --git a/test/util/image.test.cpp b/test/util/image.test.cpp index b15ddc1b3f..0cd4a7d8af 100644 --- a/test/util/image.test.cpp +++ b/test/util/image.test.cpp @@ -86,6 +86,35 @@ TEST(Image, WebPTile) { } #endif // !defined(__ANDROID__) && !defined(__APPLE__) && !defined(QT_IMAGE_DECODERS) +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(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); + + 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, {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); +} + TEST(Image, Premultiply) { UnassociatedImage rgba({ 1, 1 }); rgba.data[0] = 255; diff --git a/test/util/mapbox.test.cpp b/test/util/mapbox.test.cpp index 452106d6e6..299f0df833 100644 --- a/test/util/mapbox.test.cpp +++ b/test/util/mapbox.test.cpp @@ -3,8 +3,7 @@ #include <mbgl/util/logging.hpp> #include <mbgl/util/mapbox.hpp> #include <mbgl/util/constants.hpp> -#include <regex> -#include <iostream> +#include <stdexcept> using namespace mbgl; diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp index 984e7a3e24..d49c49018f 100644 --- a/test/util/memory.test.cpp +++ b/test/util/memory.test.cpp @@ -1,4 +1,5 @@ #include <mbgl/test/stub_file_source.hpp> +#include <mbgl/test/getrss.hpp> #include <mbgl/test/util.hpp> #include <mbgl/map/map.hpp> @@ -21,29 +22,6 @@ using namespace mbgl; using namespace std::literals::string_literals; -long getRSS() { - auto statm = util::read_file("/proc/self/statm"); - - std::vector<std::string> stats; - std::istringstream stream(statm); - - std::copy(std::istream_iterator<std::string>(stream), - std::istream_iterator<std::string>(), - std::back_inserter(stats)); - - return std::stol(stats[1]) * getpagesize(); -} - -bool isUsingJemalloc() { - const char* preload = getenv("LD_PRELOAD"); - - if (preload) { - return std::string(preload).find("libjemalloc.so") != std::string::npos; - } else { - return false; - } -} - class MemoryTest { public: MemoryTest() { @@ -109,16 +87,31 @@ TEST(Memory, Raster) { test::render(map, test.view); } +/** +On CI, we only run the memory footprint test in the Qt build, because it uses +jemalloc, which yields more consistent memory usage results. To force it to +run locally, use `DO_MEMORY_FOOTPRINT=1 make run-test-Memory.Footprint. +*/ +bool shouldRunFootprint() { + const char* preload = getenv("LD_PRELOAD"); + + if (preload) { + return std::string(preload).find("libjemalloc.so") != std::string::npos; + } else { + return getenv("DO_MEMORY_FOOTPRINT"); + } +} + // This test will measure the size of a Map object // after rendering a raster and a vector style. The // idea is to try to keep the memory footprint within // reasonable limits, so this test acts more like a // safeguard. TEST(Memory, Footprint) { - if (!isUsingJemalloc()) { + if (!shouldRunFootprint()) { return; } - + MemoryTest test; auto renderMap = [&](Map& map, const char* style){ @@ -141,7 +134,7 @@ TEST(Memory, Footprint) { std::vector<std::unique_ptr<Map>> maps; unsigned runs = 15; - long vectorInitialRSS = getRSS(); + long vectorInitialRSS = mbgl::test::getCurrentRSS(); for (unsigned i = 0; i < runs; ++i) { auto vector = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still); @@ -149,9 +142,9 @@ TEST(Memory, Footprint) { maps.push_back(std::move(vector)); }; - double vectorFootprint = (getRSS() - vectorInitialRSS) / double(runs); + double vectorFootprint = (mbgl::test::getCurrentRSS() - vectorInitialRSS) / double(runs); - long rasterInitialRSS = getRSS(); + long rasterInitialRSS = mbgl::test::getCurrentRSS(); for (unsigned i = 0; i < runs; ++i) { auto raster = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource, test.threadPool, MapMode::Still); @@ -159,7 +152,10 @@ TEST(Memory, Footprint) { maps.push_back(std::move(raster)); }; - double rasterFootprint = (getRSS() - rasterInitialRSS) / double(runs); + double rasterFootprint = (mbgl::test::getCurrentRSS() - rasterInitialRSS) / double(runs); + + RecordProperty("vectorFootprint", vectorFootprint); + RecordProperty("rasterFootprint", rasterFootprint); ASSERT_LT(vectorFootprint, 65 * 1024 * 1024) << "\ mbgl::Map footprint over 65MB for vector styles."; diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp index 9a8f01ef35..8a3a400887 100644 --- a/test/util/merge_lines.test.cpp +++ b/test/util/merge_lines.test.cpp @@ -8,95 +8,131 @@ const std::u16string bbb = u"b"; using namespace mbgl; -TEST(MergeLines, SameText) { - // merges lines with the same text - std::vector<mbgl::SymbolFeature> input1 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 }, - { FeatureType::LineString, {{{8, 0}, {9, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{5, 0}, {6, 0}}}, aaa, {}, 0 } +class GeometryTileFeatureStub : public GeometryTileFeature { +public: + GeometryTileFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_, + std::unordered_map<std::string, Value> properties_) : + id(id_), + type(type_), + geometry(geometry_), + properties(properties_) + {} + + FeatureType getType() const override { return type; } + optional<Value> getValue(const std::string& key) const override { + auto it = properties.find(key); + if (it != properties.end()) { + return it->second; + } + return {}; }; + std::unordered_map<std::string,Value> getProperties() const override { return properties; }; + optional<FeatureIdentifier> getID() const override { return id; }; + GeometryCollection getGeometries() const override { return geometry; }; + + optional<FeatureIdentifier> id; + FeatureType type; + GeometryCollection geometry; + std::unordered_map<std::string,Value> properties; +}; + +class SymbolFeatureStub : public SymbolFeature { +public: + SymbolFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_, + std::unordered_map<std::string, Value> properties_, optional<std::u16string> text_, + optional<std::string> icon_, std::size_t index_) : + SymbolFeature(std::make_unique<GeometryTileFeatureStub>(id_, type_, geometry_, properties_)) + { + text = text_; + icon = icon_; + index = index_; + } +}; - const std::vector<mbgl::SymbolFeature> expected1 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 }, - { FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 } +TEST(MergeLines, SameText) { + // merges lines with the same text + std::vector<mbgl::SymbolFeature> input1; + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0)); + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, bbb, {}, 0)); + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{8, 0}, {9, 0}}}, {}, aaa, {}, 0)); + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0)); + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, {}, aaa, {}, 0)); + input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{5, 0}, {6, 0}}}, {}, aaa, {}, 0)); + + const std::vector<GeometryTileFeatureStub> expected1 = { + { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, {} }, + { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {} }, + { {}, FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, {} }, + { {}, FeatureType::LineString, {{}}, {} }, + { {}, FeatureType::LineString, {{}}, {} }, + { {}, FeatureType::LineString, {{}}, {} } }; - + mbgl::util::mergeLines(input1); for (int i = 0; i < 6; i++) { - EXPECT_TRUE(input1[i].geometry == expected1[i].geometry); + EXPECT_TRUE(input1[i].geometry == expected1[i].getGeometries()); } } TEST(MergeLines, BothEnds) { // mergeLines handles merge from both ends - std::vector<mbgl::SymbolFeature> input2 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 } - }; - - const std::vector<mbgl::SymbolFeature> expected2 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 } + std::vector<mbgl::SymbolFeature> input2; + input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 }); + input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, aaa, {}, 0 }); + input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 }); + + const std::vector<GeometryTileFeatureStub> expected2 = { + { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, {} }, + { {}, FeatureType::LineString, {{}}, {} }, + { {}, FeatureType::LineString, {{}}, {} } }; mbgl::util::mergeLines(input2); for (int i = 0; i < 3; i++) { - EXPECT_TRUE(input2[i].geometry == expected2[i].geometry); + EXPECT_TRUE(input2[i].geometry == expected2[i].getGeometries()); } } TEST(MergeLines, CircularLines) { // mergeLines handles circular lines - std::vector<mbgl::SymbolFeature> input3 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{{4, 0}, {0, 0}}}, aaa, {}, 0 } - }; - - const std::vector<mbgl::SymbolFeature> expected3 = { - { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 }, - { FeatureType::LineString, {{}}, aaa, {}, 0 } + std::vector<mbgl::SymbolFeature> input3; + input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 }); + input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 }); + input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {0, 0}}}, {}, aaa, {}, 0 }); + + const std::vector<GeometryTileFeatureStub> expected3 = { + { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, {} }, + { {}, FeatureType::LineString, {{}}, {} }, + { {}, FeatureType::LineString, {{}}, {} } }; mbgl::util::mergeLines(input3); for (int i = 0; i < 3; i++) { - EXPECT_TRUE(input3[i].geometry == expected3[i].geometry); + EXPECT_TRUE(input3[i].geometry == expected3[i].getGeometries()); } } TEST(MergeLines, EmptyOuterGeometry) { - std::vector<mbgl::SymbolFeature> input = { - { FeatureType::LineString, {}, aaa, {}, 0 }, - }; + std::vector<mbgl::SymbolFeature> input; + input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, {}, aaa, {}, 0 }); - const std::vector<mbgl::SymbolFeature> expected = input; + const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {}, {} } }; mbgl::util::mergeLines(input); - EXPECT_EQ(expected[0].geometry, input[0].geometry); + EXPECT_EQ(input[0].geometry, expected[0].getGeometries()); } TEST(MergeLines, EmptyInnerGeometry) { - std::vector<mbgl::SymbolFeature> input = { - { FeatureType::LineString, {{}}, aaa, {}, 0 }, - }; + std::vector<mbgl::SymbolFeature> input; + input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{}}, {}, aaa, {}, 0 }); - const std::vector<mbgl::SymbolFeature> expected = input; + const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {{}}, {} } }; mbgl::util::mergeLines(input); - EXPECT_EQ(expected[0].geometry, input[0].geometry); + EXPECT_EQ(input[0].geometry, expected[0].getGeometries()); } diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp index 31fb985394..feaabf2630 100644 --- a/test/util/offscreen_texture.test.cpp +++ b/test/util/offscreen_texture.test.cpp @@ -4,6 +4,7 @@ #include <mbgl/gl/context.hpp> #include <mbgl/gl/headless_backend.hpp> #include <mbgl/gl/offscreen_view.hpp> +#include <mbgl/map/backend_scope.hpp> #include <mbgl/util/offscreen_texture.hpp> @@ -11,6 +12,7 @@ using namespace mbgl; TEST(OffscreenTexture, EmptyRed) { HeadlessBackend backend { test::sharedDisplay() }; + BackendScope scope { backend }; OffscreenView view(backend.getContext(), { 512, 256 }); view.bind(); @@ -68,6 +70,7 @@ struct Buffer { TEST(OffscreenTexture, RenderToTexture) { HeadlessBackend backend { test::sharedDisplay() }; + BackendScope scope { backend }; auto& context = backend.getContext(); MBGL_CHECK_ERROR(glEnable(GL_BLEND)); @@ -116,50 +119,45 @@ void main() { Buffer triangleBuffer({ 0, 0.5, 0.5, -0.5, -0.5, -0.5 }); Buffer viewportBuffer({ -1, -1, 1, -1, -1, 1, 1, 1 }); - // Make sure the texture gets destructed before we call context.reset(); - { - OffscreenView view(context, { 512, 256 }); - view.bind(); - - // First, draw red to the bound FBO. - context.clear(Color::red(), {}, {}); - - // 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 }); - texture.bind(); - - context.clear(Color(), {}, {}); - - MBGL_CHECK_ERROR(glUseProgram(paintShader.program)); - MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer)); - MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos)); - MBGL_CHECK_ERROR( - glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); - MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3)); - - auto image = texture.readStillImage(); - test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0); - - // Now reset the FBO back to normal and retrieve the original (restored) framebuffer. - view.bind(); - - image = view.readStillImage(); - test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0); - - // Now, composite the Framebuffer texture we've rendered to onto the main FBO. - context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear); - MBGL_CHECK_ERROR(glUseProgram(compositeShader.program)); - MBGL_CHECK_ERROR(glUniform1i(u_texture, 0)); - MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer)); - MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos)); - MBGL_CHECK_ERROR( - glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); - MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); - - image = view.readStillImage(); - test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1); - } + OffscreenView view(context, { 512, 256 }); + view.bind(); + + // First, draw red to the bound FBO. + context.clear(Color::red(), {}, {}); + + // 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 }); + texture.bind(); + + context.clear(Color(), {}, {}); + + MBGL_CHECK_ERROR(glUseProgram(paintShader.program)); + MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer)); + MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos)); + MBGL_CHECK_ERROR( + glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); + MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3)); + + auto image = texture.readStillImage(); + test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0); + + // Now reset the FBO back to normal and retrieve the original (restored) framebuffer. + view.bind(); - context.reset(); + image = view.readStillImage(); + test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0); + + // Now, composite the Framebuffer texture we've rendered to onto the main FBO. + context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear); + MBGL_CHECK_ERROR(glUseProgram(compositeShader.program)); + MBGL_CHECK_ERROR(glUniform1i(u_texture, 0)); + MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer)); + MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos)); + MBGL_CHECK_ERROR( + glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); + MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + + image = view.readStillImage(); + test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1); } diff --git a/test/util/thread.test.cpp b/test/util/thread.test.cpp index fc41fd4b78..972bddf383 100644 --- a/test/util/thread.test.cpp +++ b/test/util/thread.test.cpp @@ -3,6 +3,8 @@ #include <mbgl/test/util.hpp> +#include <atomic> + using namespace mbgl::util; class TestObject { @@ -216,3 +218,79 @@ TEST(Thread, WorkRequestDeletionCancelsImmediately) { started.get_future().get(); request1.reset(); } + +TEST(Thread, DeletePausedThread) { + RunLoop loop; + + std::atomic_bool flag(false); + + auto thread = std::make_unique<Thread<TestWorker>>(ThreadContext{"Test"}); + thread->pause(); + thread->invoke(&TestWorker::send, [&] { flag = true; }, [] {}); + + // Should not hang. + thread.reset(); + + // Should process the queue before destruction. + ASSERT_TRUE(flag); +} + +TEST(Thread, Pause) { + RunLoop loop; + + std::atomic_bool flag(false); + + Thread<TestWorker> thread1({"Test1"}); + thread1.pause(); + + Thread<TestWorker> thread2({"Test2"}); + + for (unsigned i = 0; i < 100; ++i) { + thread1.invoke(&TestWorker::send, [&] { flag = true; }, [] {}); + thread2.invoke(&TestWorker::send, [&] { ASSERT_FALSE(flag); }, [] {}); + } + + // Queue a message at the end of thread2 queue. + thread2.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {}); + loop.run(); +} + +TEST(Thread, Resume) { + RunLoop loop; + + std::atomic_bool flag(false); + + Thread<TestWorker> thread({"Test"}); + thread.pause(); + + for (unsigned i = 0; i < 100; ++i) { + thread.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(); }, [] {}); + + // This test will be flaky if the thread doesn't get paused. + ASSERT_FALSE(flag); + + thread.resume(); + loop.run(); + + ASSERT_TRUE(flag); +} + +TEST(Thread, PauseResume) { + RunLoop loop; + + Thread<TestWorker> thread({"Test"}); + + // Test if multiple pause/resume work. + for (unsigned i = 0; i < 100; ++i) { + thread.pause(); + thread.resume(); + } + + thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {}); + loop.run(); +} diff --git a/test/util/url.test.cpp b/test/util/url.test.cpp index 2acf3cb0db..ca24a5949a 100644 --- a/test/util/url.test.cpp +++ b/test/util/url.test.cpp @@ -26,6 +26,9 @@ TEST(URL, isURL) { TEST(URL, Scheme) { EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://example.com/test?query=foo").scheme); + EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://127.0.0.1:8080/test?query=foo").scheme); + EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").scheme); + EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://user:password@example.com.:80/test?query=foo").scheme); EXPECT_EQ(URL::Segment({ 0, 0 }), URL("htt").scheme); EXPECT_EQ(URL::Segment({ 0, 6 }), URL("mapbox://").scheme); EXPECT_EQ(URL::Segment({ 0, 6 }), URL("mapbox:/#").scheme); @@ -33,12 +36,17 @@ TEST(URL, Scheme) { EXPECT_EQ(URL::Segment({ 0, 0 }), URL("").scheme); EXPECT_EQ(URL::Segment({ 0, 0 }), URL("http?query://baz").scheme); EXPECT_EQ(URL::Segment({ 0, 0 }), URL(":::").scheme); + EXPECT_EQ(URL::Segment({ 0, 0 }), URL("127.0.0.1:8080/test?query=foo").scheme); + EXPECT_EQ(URL::Segment({ 0, 0 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").scheme); EXPECT_EQ(URL::Segment({ 0, 4 }), URL("data:,Hello%2C%20World!").scheme); EXPECT_EQ(URL::Segment({ 0, 4 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").scheme); } TEST(URL, Query) { EXPECT_EQ(URL::Segment({ 23, 10 }), URL("http://example.com/test?query=foo").query); + EXPECT_EQ(URL::Segment({ 26, 10 }), URL("http://127.0.0.1:8080/test?query=foo").query); + EXPECT_EQ(URL::Segment({ 47, 10 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").query); + EXPECT_EQ(URL::Segment({ 41, 10 }), URL("http://user:password@example.com.:80/test?query=foo").query); EXPECT_EQ(URL::Segment({ 23, 10 }), URL("http://example.com/test?query=foo#page-2").query); EXPECT_EQ(URL::Segment({ 23, 0 }), URL("http://example.com/test#query=foo?page-2").query); EXPECT_EQ(URL::Segment({ 0, 10 }), URL("?query=foo").query); @@ -49,12 +57,17 @@ TEST(URL, Query) { EXPECT_EQ(URL::Segment({ 12, 0 }), URL("mapbox://bar").query); EXPECT_EQ(URL::Segment({ 0, 0 }), URL("").query); EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").query); + EXPECT_EQ(URL::Segment({ 19, 10 }), URL("127.0.0.1:8080/test?query=foo").query); + EXPECT_EQ(URL::Segment({ 40, 10 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").query); EXPECT_EQ(URL::Segment({ 23, 0 }), URL("data:,Hello%2C%20World!").query); EXPECT_EQ(URL::Segment({ 47, 0 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").query); } TEST(URL, Domain) { EXPECT_EQ(URL::Segment({ 7, 11 }), URL("http://example.com/test?query=foo").domain); + EXPECT_EQ(URL::Segment({ 7, 14 }), URL("http://127.0.0.1:8080/test?query=foo").domain); + EXPECT_EQ(URL::Segment({ 7, 35 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").domain); + EXPECT_EQ(URL::Segment({ 7, 29 }), URL("http://user:password@example.com.:80/test?query=foo").domain); EXPECT_EQ(URL::Segment({ 5, 11 }), URL("http:example.com/test?query=foo").domain); EXPECT_EQ(URL::Segment({ 0, 3 }), URL("htt").domain); EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http?query://baz").domain); @@ -71,18 +84,25 @@ TEST(URL, Domain) { EXPECT_EQ(URL::Segment({ 7, 6 }), URL("http://domain?").domain); EXPECT_EQ(URL::Segment({ 7, 6 }), URL("http://domain?foo").domain); EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").domain); + EXPECT_EQ(URL::Segment({ 0, 14 }), URL("127.0.0.1:8080/test?query=foo").domain); + EXPECT_EQ(URL::Segment({ 0, 35 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").domain); EXPECT_EQ(URL::Segment({ 5, 0 }), URL("data:,Hello%2C%20World!").domain); EXPECT_EQ(URL::Segment({ 5, 17 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").domain); } TEST(URL, Path) { EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test?query=foo").path); + EXPECT_EQ(URL::Segment({ 21, 5 }), URL("http://127.0.0.1:8080/test?query=foo").path); + EXPECT_EQ(URL::Segment({ 42, 5 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").path); + EXPECT_EQ(URL::Segment({ 36, 5 }), URL("http://user:password@example.com.:80/test?query=foo").path); EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test?query=foo#bar").path); EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test#bar").path); EXPECT_EQ(URL::Segment({ 18, 0 }), URL("http://example.com?query=foo").path); EXPECT_EQ(URL::Segment({ 18, 0 }), URL("http://example.com#?query=foo").path); EXPECT_EQ(URL::Segment({ 18, 1 }), URL("http://example.com/?query=foo").path); EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").path); + EXPECT_EQ(URL::Segment({ 14, 5 }), URL("127.0.0.1:8080/test?query=foo").path); + EXPECT_EQ(URL::Segment({ 35, 5 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").path); EXPECT_EQ(URL::Segment({ 13, 0 }), URL("http://domain").path); EXPECT_EQ(URL::Segment({ 6, 4 }), URL("domain/foo?bar").path); EXPECT_EQ(URL::Segment({ 6, 17 }), URL("data:,Hello%2C%20World!").path); |