diff --git a/.travis.yml b/.travis.yml index f2349fdd3..d88fa71e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,9 @@ env: matrix: - BUILDTYPE=Release - BUILDTYPE=Debug + global: + - secure: "bG4YYWMfl9API0MSRgmOaJrlGLv06tRg9KJNawBieZvBJbITPpxVGJZT3/l/SEJ+Rl15e2dRex4k+MGQlmT2SqPQxTEYWv1qxNigKPPcla7IWeNmWWqW8uVvFjdglojgBOK2k/xErVQtA4zDfi3mwSXH4DKwquXWsoEKmX2SV7M=" + - secure: "Cbvap9ubVKgjPe3hUhI6JGeDZzBXHpOG9RaYKh+SdoIPhKnlJiNOYm1egomi+e4uqJInlFKuVHTw7Ng9Cun6Zm0jIxpkSchv1GpsR7hmB3UGnGed19Dw8121FwuUaktN+4YnbVlsyd+u8EHD3+h58t4eELrLrZolM4rS7DL6caA=" before_install: - source ./scripts/setup_travis.sh diff --git a/Makefile b/Makefile index 65f781298..d7f6f37c4 100644 --- a/Makefile +++ b/Makefile @@ -29,12 +29,16 @@ test: build/test/Makefile # Runs all test cases run-tests: test - (cd build/${BUILDTYPE} && exec find . -maxdepth 1 -name "test_*" -exec {} \;) + BUILDTYPE=$(BUILDTYPE) ./scripts/run_tests.sh test/%: build/test/Makefile $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $* (cd build/$(BUILDTYPE) && exec ./test_$*) +# build Mac OS X project for Xcode +xtest: config.gypi clear_xcode_cache node + deps/run_gyp test/test.gyp --depth=. -Goutput_dir=.. --generator-output=./build -f xcode + open ./build/test/test.xcodeproj ##### Makefile builds ########################################################## diff --git a/common/headless_view.hpp b/common/headless_view.hpp index a203d477e..b3e1c11b9 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -29,14 +29,14 @@ private: private: -#ifdef LLMR_USE_CGL +#if LLMR_USE_CGL CGLContextObj gl_context; GLuint fbo = 0; GLuint fbo_depth_stencil = 0; GLuint fbo_color = 0; #endif -#ifdef LLMR_USE_GLX +#if LLMR_USE_GLX GLXContext gl_context = nullptr; XVisualInfo *x_info = nullptr; Display *x_display = nullptr; diff --git a/include/llmr/util/error.hpp b/include/llmr/util/error.hpp new file mode 100644 index 000000000..95106ff2c --- /dev/null +++ b/include/llmr/util/error.hpp @@ -0,0 +1,20 @@ +#ifndef LLMR_UTIL_ERROR +#define LLMR_UTIL_ERROR + +#include +#include + +namespace llmr { +namespace error { + +struct style_parse : std::exception { + inline style_parse(size_t offset, const char *msg) : offset(offset), msg(msg) {} + inline const char* what() const noexcept { return msg.c_str(); } + const size_t offset; + const std::string msg; +}; +} + +} + +#endif \ No newline at end of file diff --git a/include/llmr/util/image.hpp b/include/llmr/util/image.hpp index dccc18589..ac20473e8 100644 --- a/include/llmr/util/image.hpp +++ b/include/llmr/util/image.hpp @@ -13,7 +13,7 @@ std::string compress_png(int width, int height, void *rgba, bool flip = false); class Image { public: - Image(const std::string &img); + Image(const std::string &img, bool flip = false); ~Image(); inline const char *getData() const { return img; } diff --git a/include/llmr/util/io.hpp b/include/llmr/util/io.hpp index f1e560ffe..cdad97913 100644 --- a/include/llmr/util/io.hpp +++ b/include/llmr/util/io.hpp @@ -7,6 +7,7 @@ namespace llmr { namespace util { void write_file(const std::string &filename, const std::string &data); +std::string read_file(const std::string &filename); } } diff --git a/llmr.gyp b/llmr.gyp index 89c006ffd..0983d23ce 100644 --- a/llmr.gyp +++ b/llmr.gyp @@ -7,7 +7,7 @@ { 'target_name': 'shaders', 'type': 'none', - # 'hard_dependency': 1, + 'hard_dependency': 1, 'actions': [ { 'action_name': 'Build Shaders', diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100755 index 000000000..3d0c0bdd9 --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +cd build/$BUILDTYPE + +for TEST in test_* ; do + ./$TEST +done diff --git a/src/style/style.cpp b/src/style/style.cpp index fc2364da8..006376172 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,9 @@ void Style::loadJSON(const uint8_t *const data) { rapidjson::Document doc; doc.Parse<0>((const char *const)data); + if (doc.HasParseError()) { + throw error::style_parse(doc.GetErrorOffset(), doc.GetParseError()); + } StyleParser parser; parser.parse(const_cast(doc)); diff --git a/src/util/image.cpp b/src/util/image.cpp index 2d4eb3602..f29f3451b 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -84,7 +84,7 @@ void warningHandler(png_structp, png_const_charp error_msg) { fprintf(stderr, "PNG: %s\n", error_msg); } -Image::Image(const std::string &data) { +Image::Image(const std::string &data, bool flip) { Buffer buffer(data); if (buffer.length < 8 || !png_check_sig((const png_bytep)buffer.data, 8)) { @@ -148,7 +148,7 @@ Image::Image(const std::string &data) { png_bytep *rows = nullptr; } pointers(height); for (unsigned i = 0; i < height; ++i) { - pointers.rows[i] = (png_bytep)(surface + (i * rowbytes)); + pointers.rows[flip ? height - 1 - i : i] = (png_bytep)(surface + (i * rowbytes)); } // Read image data diff --git a/src/util/io.cpp b/src/util/io.cpp index bf519b057..1312b907b 100644 --- a/src/util/io.cpp +++ b/src/util/io.cpp @@ -1,8 +1,15 @@ #include #include +#include +#include +#include +#include -void llmr::util::write_file(const std::string &filename, const std::string &data) { +namespace llmr { +namespace util { + +void write_file(const std::string &filename, const std::string &data) { FILE *fd = fopen(filename.c_str(), "wb"); if (fd) { fwrite(data.data(), sizeof(std::string::value_type), data.size(), fd); @@ -11,3 +18,17 @@ void llmr::util::write_file(const std::string &filename, const std::string &data fprintf(stderr, "Failed to open file\n"); } } + +std::string read_file(const std::string &filename) { + std::ifstream file(filename); + if (file.good()) { + std::stringstream data; + data << file.rdbuf(); + return data.str(); + } else { + throw std::runtime_error("Cannot read file " + filename); + } +} + +} +} \ No newline at end of file diff --git a/test/fixtures/fixture_request.cpp b/test/fixtures/fixture_request.cpp new file mode 100644 index 000000000..5cbbfda3f --- /dev/null +++ b/test/fixtures/fixture_request.cpp @@ -0,0 +1,100 @@ +#include +#include +#include + +const std::string base_directory = []{ + std::string fn = __FILE__; + fn.erase(fn.find_last_of("/")); + return fn; +}(); + + +namespace llmr { + +std::shared_ptr +platform::request_http(const std::string &url, + std::function callback, + std::shared_ptr loop) { + uv_loop_t *l = nullptr; + if (loop) { + l = **loop; + } else { + l = uv_default_loop(); + } + + std::string clean_url = base_directory + "/" + url; + auto pos = clean_url.find("://"); + if (pos != std::string::npos) { + clean_url.replace(pos, 3, "/"); + } + + std::replace(clean_url.begin(), clean_url.end(), '+', ' '); + + std::shared_ptr req = std::make_shared(url, callback, loop); + + int err; + + uv_fs_t open_req; + err = uv_fs_open(l, &open_req, clean_url.c_str(), O_RDONLY, S_IRUSR, nullptr); + uv_fs_req_cleanup(&open_req); + if (err < 0) { + req->res->code = err; + req->res->error_message = uv_strerror(err); + req->complete(); + return req; + } + uv_file fd = err; + + uv_fs_t stat_req; + uv_fs_fstat(l, &stat_req, fd, nullptr); + uv_fs_req_cleanup(&stat_req); + err = uv_fs_fstat(l, &stat_req, fd, nullptr); + if (err < 0) { + req->res->code = err; + req->res->error_message = uv_strerror(err); + req->complete(); + return req; + } + + const uint64_t size = static_cast(stat_req.ptr)->st_size; + + + std::string body; + body.resize(size); + uv_buf_t uvbuf = uv_buf_init(const_cast(body.data()), body.size()); + + uv_fs_t read_req; + err = uv_fs_read(l, &read_req, fd, &uvbuf, 1, 0, nullptr); + uv_fs_req_cleanup(&read_req); + if (err < 0) { + req->res->code = err; + req->res->error_message = uv_strerror(err); + req->complete(); + return req; + } + + + uv_fs_t close_req; + err = uv_fs_close(l, &close_req, fd, nullptr); + uv_fs_req_cleanup(&close_req); + if (err < 0) { + req->res->code = err; + req->res->error_message = uv_strerror(err); + req->complete(); + return req; + } + + req->res->body.swap(body); + req->res->code = 200; + req->complete(); + + return req; +} + +void platform::cancel_request_http(const std::shared_ptr &req) { + if (req) { + req->cancelled = true; + } +} + +} // end namespace llmr diff --git a/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf b/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf new file mode 100644 index 000000000..cea1c094d Binary files /dev/null and b/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf differ diff --git a/test/fixtures/sprites/outdoors.json b/test/fixtures/sprites/outdoors.json new file mode 100644 index 000000000..b2a7ddf53 --- /dev/null +++ b/test/fixtures/sprites/outdoors.json @@ -0,0 +1 @@ +{"wetland_noveg_64":{"x":0,"y":0,"width":64,"height":32,"pixelRatio":1},"wetland_64":{"x":66,"y":0,"width":64,"height":32,"pixelRatio":1},"airport-24":{"x":0,"y":34,"width":24,"height":24,"pixelRatio":1},"wetland_32":{"x":26,"y":34,"width":32,"height":16,"pixelRatio":1},"wetland_noveg_32":{"x":60,"y":34,"width":32,"height":16,"pixelRatio":1},"night-library-12":{"x":94,"y":34,"width":12,"height":12,"pixelRatio":1},"bakery-12":{"x":108,"y":34,"width":12,"height":12,"pixelRatio":1},"bank-12":{"x":0,"y":60,"width":12,"height":12,"pixelRatio":1},"bar-12":{"x":14,"y":60,"width":12,"height":12,"pixelRatio":1},"baseball-12":{"x":28,"y":60,"width":12,"height":12,"pixelRatio":1},"basketball-12":{"x":42,"y":60,"width":12,"height":12,"pixelRatio":1},"beer-12":{"x":56,"y":60,"width":12,"height":12,"pixelRatio":1},"bicycle-12":{"x":70,"y":60,"width":12,"height":12,"pixelRatio":1},"building-12":{"x":84,"y":60,"width":12,"height":12,"pixelRatio":1},"bus-12":{"x":98,"y":60,"width":12,"height":12,"pixelRatio":1},"cafe-12":{"x":112,"y":60,"width":12,"height":12,"pixelRatio":1},"camera-12":{"x":0,"y":74,"width":12,"height":12,"pixelRatio":1},"campsite-12":{"x":14,"y":74,"width":12,"height":12,"pixelRatio":1},"car-12":{"x":28,"y":74,"width":12,"height":12,"pixelRatio":1},"cemetery-12":{"x":42,"y":74,"width":12,"height":12,"pixelRatio":1},"chemist-12":{"x":56,"y":74,"width":12,"height":12,"pixelRatio":1},"cinema-12":{"x":70,"y":74,"width":12,"height":12,"pixelRatio":1},"circle-12":{"x":84,"y":74,"width":12,"height":12,"pixelRatio":1},"circle-stroked-12":{"x":98,"y":74,"width":12,"height":12,"pixelRatio":1},"city-12":{"x":112,"y":74,"width":12,"height":12,"pixelRatio":1},"clothing-store-12":{"x":0,"y":88,"width":12,"height":12,"pixelRatio":1},"college-12":{"x":14,"y":88,"width":12,"height":12,"pixelRatio":1},"commercial-12":{"x":28,"y":88,"width":12,"height":12,"pixelRatio":1},"cricket-12":{"x":42,"y":88,"width":12,"height":12,"pixelRatio":1},"cross-12":{"x":56,"y":88,"width":12,"height":12,"pixelRatio":1},"dam-12":{"x":70,"y":88,"width":12,"height":12,"pixelRatio":1},"danger-12":{"x":84,"y":88,"width":12,"height":12,"pixelRatio":1},"disability-12":{"x":98,"y":88,"width":12,"height":12,"pixelRatio":1},"dog-park-12":{"x":112,"y":88,"width":12,"height":12,"pixelRatio":1},"embassy-12":{"x":0,"y":102,"width":12,"height":12,"pixelRatio":1},"emergency-telephone-12":{"x":14,"y":102,"width":12,"height":12,"pixelRatio":1},"entrance-12":{"x":28,"y":102,"width":12,"height":12,"pixelRatio":1},"farm-12":{"x":42,"y":102,"width":12,"height":12,"pixelRatio":1},"fast-food-12":{"x":56,"y":102,"width":12,"height":12,"pixelRatio":1},"ferry-12":{"x":70,"y":102,"width":12,"height":12,"pixelRatio":1},"fire-station-12":{"x":84,"y":102,"width":12,"height":12,"pixelRatio":1},"fuel-12":{"x":98,"y":102,"width":12,"height":12,"pixelRatio":1},"garden-12":{"x":112,"y":102,"width":12,"height":12,"pixelRatio":1},"golf-12":{"x":0,"y":116,"width":12,"height":12,"pixelRatio":1},"grocery-12":{"x":14,"y":116,"width":12,"height":12,"pixelRatio":1},"hairdresser-12":{"x":28,"y":116,"width":12,"height":12,"pixelRatio":1},"harbor-12":{"x":42,"y":116,"width":12,"height":12,"pixelRatio":1},"heart-12":{"x":56,"y":116,"width":12,"height":12,"pixelRatio":1},"heliport-12":{"x":70,"y":116,"width":12,"height":12,"pixelRatio":1},"hospital-12":{"x":84,"y":116,"width":12,"height":12,"pixelRatio":1},"industrial-12":{"x":98,"y":116,"width":12,"height":12,"pixelRatio":1},"land-use-12":{"x":112,"y":116,"width":12,"height":12,"pixelRatio":1},"laundry-12":{"x":132,"y":0,"width":12,"height":12,"pixelRatio":1},"library-12":{"x":132,"y":14,"width":12,"height":12,"pixelRatio":1},"lighthouse-12":{"x":132,"y":28,"width":12,"height":12,"pixelRatio":1},"lodging-12":{"x":132,"y":42,"width":12,"height":12,"pixelRatio":1},"logging-12":{"x":132,"y":56,"width":12,"height":12,"pixelRatio":1},"london-underground-12":{"x":132,"y":70,"width":12,"height":12,"pixelRatio":1},"marker-12":{"x":132,"y":84,"width":12,"height":12,"pixelRatio":1},"marker-stroked-12":{"x":132,"y":98,"width":12,"height":12,"pixelRatio":1},"minefield-12":{"x":132,"y":112,"width":12,"height":12,"pixelRatio":1},"mobilephone-12":{"x":0,"y":130,"width":12,"height":12,"pixelRatio":1},"monument-12":{"x":14,"y":130,"width":12,"height":12,"pixelRatio":1},"museum-12":{"x":28,"y":130,"width":12,"height":12,"pixelRatio":1},"music-12":{"x":42,"y":130,"width":12,"height":12,"pixelRatio":1},"night-airfield-12":{"x":56,"y":130,"width":12,"height":12,"pixelRatio":1},"night-airport-12":{"x":70,"y":130,"width":12,"height":12,"pixelRatio":1},"night-alcohol-shop-12":{"x":84,"y":130,"width":12,"height":12,"pixelRatio":1},"night-america-football-12":{"x":98,"y":130,"width":12,"height":12,"pixelRatio":1},"night-art-gallery-12":{"x":112,"y":130,"width":12,"height":12,"pixelRatio":1},"night-bakery-12":{"x":126,"y":130,"width":12,"height":12,"pixelRatio":1},"night-bank-12":{"x":146,"y":0,"width":12,"height":12,"pixelRatio":1},"night-bar-12":{"x":146,"y":14,"width":12,"height":12,"pixelRatio":1},"night-baseball-12":{"x":146,"y":28,"width":12,"height":12,"pixelRatio":1},"night-basketball-12":{"x":146,"y":42,"width":12,"height":12,"pixelRatio":1},"night-beer-12":{"x":146,"y":56,"width":12,"height":12,"pixelRatio":1},"night-bicycle-12":{"x":146,"y":70,"width":12,"height":12,"pixelRatio":1},"night-building-12":{"x":146,"y":84,"width":12,"height":12,"pixelRatio":1},"night-bus-12":{"x":146,"y":98,"width":12,"height":12,"pixelRatio":1},"night-cafe-12":{"x":146,"y":112,"width":12,"height":12,"pixelRatio":1},"night-camera-12":{"x":146,"y":126,"width":12,"height":12,"pixelRatio":1},"night-campsite-12":{"x":0,"y":144,"width":12,"height":12,"pixelRatio":1},"night-car-12":{"x":14,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cemetery-12":{"x":28,"y":144,"width":12,"height":12,"pixelRatio":1},"night-chemist-12":{"x":42,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cinema-12":{"x":56,"y":144,"width":12,"height":12,"pixelRatio":1},"night-circle-12":{"x":70,"y":144,"width":12,"height":12,"pixelRatio":1},"night-circle-stroked-12":{"x":84,"y":144,"width":12,"height":12,"pixelRatio":1},"night-city-12":{"x":98,"y":144,"width":12,"height":12,"pixelRatio":1},"night-clothing-store-12":{"x":112,"y":144,"width":12,"height":12,"pixelRatio":1},"night-college-12":{"x":126,"y":144,"width":12,"height":12,"pixelRatio":1},"night-commercial-12":{"x":140,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cricket-12":{"x":160,"y":0,"width":12,"height":12,"pixelRatio":1},"night-cross-12":{"x":160,"y":14,"width":12,"height":12,"pixelRatio":1},"night-dam-12":{"x":160,"y":28,"width":12,"height":12,"pixelRatio":1},"night-danger-12":{"x":160,"y":42,"width":12,"height":12,"pixelRatio":1},"night-disability-12":{"x":160,"y":56,"width":12,"height":12,"pixelRatio":1},"night-dog-park-12":{"x":160,"y":70,"width":12,"height":12,"pixelRatio":1},"night-embassy-12":{"x":160,"y":84,"width":12,"height":12,"pixelRatio":1},"night-emergency-telephone-12":{"x":160,"y":98,"width":12,"height":12,"pixelRatio":1},"night-entrance-12":{"x":160,"y":112,"width":12,"height":12,"pixelRatio":1},"night-farm-12":{"x":160,"y":126,"width":12,"height":12,"pixelRatio":1},"night-fast-food-12":{"x":160,"y":140,"width":12,"height":12,"pixelRatio":1},"night-ferry-12":{"x":0,"y":158,"width":12,"height":12,"pixelRatio":1},"night-fire-station-12":{"x":14,"y":158,"width":12,"height":12,"pixelRatio":1},"night-fuel-12":{"x":28,"y":158,"width":12,"height":12,"pixelRatio":1},"night-garden-12":{"x":42,"y":158,"width":12,"height":12,"pixelRatio":1},"night-golf-12":{"x":56,"y":158,"width":12,"height":12,"pixelRatio":1},"night-grocery-12":{"x":70,"y":158,"width":12,"height":12,"pixelRatio":1},"night-hairdresser-12":{"x":84,"y":158,"width":12,"height":12,"pixelRatio":1},"night-harbor-12":{"x":98,"y":158,"width":12,"height":12,"pixelRatio":1},"night-heart-12":{"x":112,"y":158,"width":12,"height":12,"pixelRatio":1},"night-heliport-12":{"x":126,"y":158,"width":12,"height":12,"pixelRatio":1},"night-hospital-12":{"x":140,"y":158,"width":12,"height":12,"pixelRatio":1},"night-industrial-12":{"x":154,"y":158,"width":12,"height":12,"pixelRatio":1},"night-land-use-12":{"x":174,"y":0,"width":12,"height":12,"pixelRatio":1},"night-laundry-12":{"x":174,"y":14,"width":12,"height":12,"pixelRatio":1},"airport-12":{"x":174,"y":28,"width":12,"height":12,"pixelRatio":1},"night-lighthouse-12":{"x":174,"y":42,"width":12,"height":12,"pixelRatio":1},"night-lodging-12":{"x":174,"y":56,"width":12,"height":12,"pixelRatio":1},"night-logging-12":{"x":174,"y":70,"width":12,"height":12,"pixelRatio":1},"night-london-underground-12":{"x":174,"y":84,"width":12,"height":12,"pixelRatio":1},"night-marker-12":{"x":174,"y":98,"width":12,"height":12,"pixelRatio":1},"night-marker-stroked-12":{"x":174,"y":112,"width":12,"height":12,"pixelRatio":1},"night-minefield-12":{"x":174,"y":126,"width":12,"height":12,"pixelRatio":1},"night-mobilephone-12":{"x":174,"y":140,"width":12,"height":12,"pixelRatio":1},"night-monument-12":{"x":174,"y":154,"width":12,"height":12,"pixelRatio":1},"night-museum-12":{"x":0,"y":172,"width":12,"height":12,"pixelRatio":1},"night-music-12":{"x":14,"y":172,"width":12,"height":12,"pixelRatio":1},"night-oil-well-12":{"x":28,"y":172,"width":12,"height":12,"pixelRatio":1},"night-park-12":{"x":42,"y":172,"width":12,"height":12,"pixelRatio":1},"night-park2-12":{"x":56,"y":172,"width":12,"height":12,"pixelRatio":1},"night-parking-12":{"x":70,"y":172,"width":12,"height":12,"pixelRatio":1},"night-parking-garage-12":{"x":84,"y":172,"width":12,"height":12,"pixelRatio":1},"night-pharmacy-12":{"x":98,"y":172,"width":12,"height":12,"pixelRatio":1},"night-pitch-12":{"x":112,"y":172,"width":12,"height":12,"pixelRatio":1},"night-place-of-worship-12":{"x":126,"y":172,"width":12,"height":12,"pixelRatio":1},"night-playground-12":{"x":140,"y":172,"width":12,"height":12,"pixelRatio":1},"night-police-12":{"x":154,"y":172,"width":12,"height":12,"pixelRatio":1},"night-polling-place-12":{"x":168,"y":172,"width":12,"height":12,"pixelRatio":1},"night-post-12":{"x":188,"y":0,"width":12,"height":12,"pixelRatio":1},"night-prison-12":{"x":188,"y":14,"width":12,"height":12,"pixelRatio":1},"night-rail-12":{"x":188,"y":28,"width":12,"height":12,"pixelRatio":1},"night-rail-above-12":{"x":188,"y":42,"width":12,"height":12,"pixelRatio":1},"night-rail-light-12":{"x":188,"y":56,"width":12,"height":12,"pixelRatio":1},"night-rail-metro-12":{"x":188,"y":70,"width":12,"height":12,"pixelRatio":1},"night-rail-underground-12":{"x":188,"y":84,"width":12,"height":12,"pixelRatio":1},"night-religious-christian-12":{"x":188,"y":98,"width":12,"height":12,"pixelRatio":1},"night-religious-jewish-12":{"x":188,"y":112,"width":12,"height":12,"pixelRatio":1},"night-religious-muslim-12":{"x":188,"y":126,"width":12,"height":12,"pixelRatio":1},"night-restaurant-12":{"x":188,"y":140,"width":12,"height":12,"pixelRatio":1},"night-roadblock-12":{"x":188,"y":154,"width":12,"height":12,"pixelRatio":1},"night-rocket-12":{"x":188,"y":168,"width":12,"height":12,"pixelRatio":1},"night-school-12":{"x":0,"y":186,"width":12,"height":12,"pixelRatio":1},"night-scooter-12":{"x":14,"y":186,"width":12,"height":12,"pixelRatio":1},"night-shop-12":{"x":28,"y":186,"width":12,"height":12,"pixelRatio":1},"night-skiing-12":{"x":42,"y":186,"width":12,"height":12,"pixelRatio":1},"night-slaughterhouse-12":{"x":56,"y":186,"width":12,"height":12,"pixelRatio":1},"night-soccer-12":{"x":70,"y":186,"width":12,"height":12,"pixelRatio":1},"night-square-12":{"x":84,"y":186,"width":12,"height":12,"pixelRatio":1},"night-square-stroked-12":{"x":98,"y":186,"width":12,"height":12,"pixelRatio":1},"night-star-12":{"x":112,"y":186,"width":12,"height":12,"pixelRatio":1},"night-star-stroked-12":{"x":126,"y":186,"width":12,"height":12,"pixelRatio":1},"night-suitcase-12":{"x":140,"y":186,"width":12,"height":12,"pixelRatio":1},"night-swimming-12":{"x":154,"y":186,"width":12,"height":12,"pixelRatio":1},"night-telephone-12":{"x":168,"y":186,"width":12,"height":12,"pixelRatio":1},"night-tennis-12":{"x":182,"y":186,"width":12,"height":12,"pixelRatio":1},"night-theatre-12":{"x":202,"y":0,"width":12,"height":12,"pixelRatio":1},"night-toilets-12":{"x":202,"y":14,"width":12,"height":12,"pixelRatio":1},"night-town-12":{"x":202,"y":28,"width":12,"height":12,"pixelRatio":1},"night-town-hall-12":{"x":202,"y":42,"width":12,"height":12,"pixelRatio":1},"night-triangle-12":{"x":202,"y":56,"width":12,"height":12,"pixelRatio":1},"night-triangle-stroked-12":{"x":202,"y":70,"width":12,"height":12,"pixelRatio":1},"night-village-12":{"x":202,"y":84,"width":12,"height":12,"pixelRatio":1},"night-warehouse-12":{"x":202,"y":98,"width":12,"height":12,"pixelRatio":1},"night-waste-basket-12":{"x":202,"y":112,"width":12,"height":12,"pixelRatio":1},"night-water-12":{"x":202,"y":126,"width":12,"height":12,"pixelRatio":1},"night-wetland-12":{"x":202,"y":140,"width":12,"height":12,"pixelRatio":1},"night-zoo-12":{"x":202,"y":154,"width":12,"height":12,"pixelRatio":1},"oil-well-12":{"x":202,"y":168,"width":12,"height":12,"pixelRatio":1},"park-12":{"x":202,"y":182,"width":12,"height":12,"pixelRatio":1},"park2-12":{"x":0,"y":200,"width":12,"height":12,"pixelRatio":1},"parking-12":{"x":14,"y":200,"width":12,"height":12,"pixelRatio":1},"parking-garage-12":{"x":28,"y":200,"width":12,"height":12,"pixelRatio":1},"pharmacy-12":{"x":42,"y":200,"width":12,"height":12,"pixelRatio":1},"pitch-12":{"x":56,"y":200,"width":12,"height":12,"pixelRatio":1},"place-of-worship-12":{"x":70,"y":200,"width":12,"height":12,"pixelRatio":1},"playground-12":{"x":84,"y":200,"width":12,"height":12,"pixelRatio":1},"police-12":{"x":98,"y":200,"width":12,"height":12,"pixelRatio":1},"polling-place-12":{"x":112,"y":200,"width":12,"height":12,"pixelRatio":1},"post-12":{"x":126,"y":200,"width":12,"height":12,"pixelRatio":1},"prison-12":{"x":140,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-12":{"x":154,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-above-12":{"x":168,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-light-12":{"x":182,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-metro-12":{"x":196,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-underground-12":{"x":216,"y":0,"width":12,"height":12,"pixelRatio":1},"religious-christian-12":{"x":216,"y":14,"width":12,"height":12,"pixelRatio":1},"religious-jewish-12":{"x":216,"y":28,"width":12,"height":12,"pixelRatio":1},"religious-muslim-12":{"x":216,"y":42,"width":12,"height":12,"pixelRatio":1},"restaurant-12":{"x":216,"y":56,"width":12,"height":12,"pixelRatio":1},"roadblock-12":{"x":216,"y":70,"width":12,"height":12,"pixelRatio":1},"rocket-12":{"x":216,"y":84,"width":12,"height":12,"pixelRatio":1},"school-12":{"x":216,"y":98,"width":12,"height":12,"pixelRatio":1},"scooter-12":{"x":216,"y":112,"width":12,"height":12,"pixelRatio":1},"shop-12":{"x":216,"y":126,"width":12,"height":12,"pixelRatio":1},"skiing-12":{"x":216,"y":140,"width":12,"height":12,"pixelRatio":1},"slaughterhouse-12":{"x":216,"y":154,"width":12,"height":12,"pixelRatio":1},"soccer-12":{"x":216,"y":168,"width":12,"height":12,"pixelRatio":1},"square-12":{"x":216,"y":182,"width":12,"height":12,"pixelRatio":1},"square-stroked-12":{"x":216,"y":196,"width":12,"height":12,"pixelRatio":1},"star-12":{"x":0,"y":214,"width":12,"height":12,"pixelRatio":1},"star-stroked-12":{"x":14,"y":214,"width":12,"height":12,"pixelRatio":1},"suitcase-12":{"x":28,"y":214,"width":12,"height":12,"pixelRatio":1},"swimming-12":{"x":42,"y":214,"width":12,"height":12,"pixelRatio":1},"telephone-12":{"x":56,"y":214,"width":12,"height":12,"pixelRatio":1},"tennis-12":{"x":70,"y":214,"width":12,"height":12,"pixelRatio":1},"theatre-12":{"x":84,"y":214,"width":12,"height":12,"pixelRatio":1},"toilets-12":{"x":98,"y":214,"width":12,"height":12,"pixelRatio":1},"town-12":{"x":112,"y":214,"width":12,"height":12,"pixelRatio":1},"town-hall-12":{"x":126,"y":214,"width":12,"height":12,"pixelRatio":1},"triangle-12":{"x":140,"y":214,"width":12,"height":12,"pixelRatio":1},"triangle-stroked-12":{"x":154,"y":214,"width":12,"height":12,"pixelRatio":1},"village-12":{"x":168,"y":214,"width":12,"height":12,"pixelRatio":1},"warehouse-12":{"x":182,"y":214,"width":12,"height":12,"pixelRatio":1},"waste-basket-12":{"x":196,"y":214,"width":12,"height":12,"pixelRatio":1},"water-12":{"x":210,"y":214,"width":12,"height":12,"pixelRatio":1},"wetland-12":{"x":230,"y":0,"width":12,"height":12,"pixelRatio":1},"airfield-12":{"x":230,"y":14,"width":12,"height":12,"pixelRatio":1},"alcohol-shop-12":{"x":230,"y":28,"width":12,"height":12,"pixelRatio":1},"america-football-12":{"x":230,"y":42,"width":12,"height":12,"pixelRatio":1},"art-gallery-12":{"x":230,"y":56,"width":12,"height":12,"pixelRatio":1},"zoo-12":{"x":230,"y":70,"width":12,"height":12,"pixelRatio":1},"wetland_noveg_16":{"x":0,"y":228,"width":16,"height":8,"pixelRatio":1},"wetland_16":{"x":18,"y":228,"width":16,"height":8,"pixelRatio":1}} \ No newline at end of file diff --git a/test/fixtures/sprites/outdoors.png b/test/fixtures/sprites/outdoors.png new file mode 100644 index 000000000..61e99085f Binary files /dev/null and b/test/fixtures/sprites/outdoors.png differ diff --git a/test/fixtures/styles/0.actual.png b/test/fixtures/styles/0.actual.png new file mode 100644 index 000000000..34e984cce Binary files /dev/null and b/test/fixtures/styles/0.actual.png differ diff --git a/test/fixtures/styles/0.expected.png b/test/fixtures/styles/0.expected.png new file mode 100644 index 000000000..34e984cce Binary files /dev/null and b/test/fixtures/styles/0.expected.png differ diff --git a/test/fixtures/styles/0.info.json b/test/fixtures/styles/0.info.json new file mode 100644 index 000000000..3501d30ed --- /dev/null +++ b/test/fixtures/styles/0.info.json @@ -0,0 +1,8 @@ +{ + "zoom": 0, + "latitude": 0, + "longitude": 0, + "angle": 0, + "width": 512, + "height": 512 +} diff --git a/test/fixtures/styles/0.style.json b/test/fixtures/styles/0.style.json new file mode 100644 index 000000000..06d7a1db1 --- /dev/null +++ b/test/fixtures/styles/0.style.json @@ -0,0 +1,34 @@ +{ + "version": 3, + "sources": { + "mapbox": { + "type": "vector", + "url": "tiles/%d-%d-%d.vector.pbf", + "tileSize": 512, + "maxZoom": 14 + } + }, + "layers": [ + { + "id": "background", + "render": { + "type": "background" + }, + "style": { + "background-color": "red" + } + }, + { + "id": "water", + "source": "mapbox", + "source-layer": "water", + "render": { + "type": "fill" + }, + "style": { + "fill-color": "blue", + "fill-antialias": false + } + } + ] +} diff --git a/test/fixtures/styles/1.actual.png b/test/fixtures/styles/1.actual.png new file mode 100644 index 000000000..d34c46a6c Binary files /dev/null and b/test/fixtures/styles/1.actual.png differ diff --git a/test/fixtures/styles/1.expected.png b/test/fixtures/styles/1.expected.png new file mode 100644 index 000000000..d34c46a6c Binary files /dev/null and b/test/fixtures/styles/1.expected.png differ diff --git a/test/fixtures/styles/1.info.json b/test/fixtures/styles/1.info.json new file mode 100644 index 000000000..3501d30ed --- /dev/null +++ b/test/fixtures/styles/1.info.json @@ -0,0 +1,8 @@ +{ + "zoom": 0, + "latitude": 0, + "longitude": 0, + "angle": 0, + "width": 512, + "height": 512 +} diff --git a/test/fixtures/styles/1.style.json b/test/fixtures/styles/1.style.json new file mode 100644 index 000000000..d35c4bc0f --- /dev/null +++ b/test/fixtures/styles/1.style.json @@ -0,0 +1,33 @@ +{ + "version": 3, + "sources": { + "mapbox": { + "type": "vector", + "url": "tiles/%d-%d-%d.vector.pbf", + "tileSize": 512, + "maxZoom": 14 + } + }, + "layers": [ + { + "id": "background", + "render": { + "type": "background" + }, + "style": { + "background-color": "red" + } + }, + { + "id": "water", + "source": "mapbox", + "source-layer": "water", + "render": { + "type": "fill" + }, + "style": { + "fill-color": "blue" + } + } + ] +} diff --git a/test/fixtures/tiles/0-0-0.vector.pbf b/test/fixtures/tiles/0-0-0.vector.pbf new file mode 100644 index 000000000..5eee52935 Binary files /dev/null and b/test/fixtures/tiles/0-0-0.vector.pbf differ diff --git a/test/fixtures/tiles/2-1-1.vector.pbf b/test/fixtures/tiles/2-1-1.vector.pbf new file mode 100644 index 000000000..00a5435b7 Binary files /dev/null and b/test/fixtures/tiles/2-1-1.vector.pbf differ diff --git a/test/fixtures/tiles/2-1-2.vector.pbf b/test/fixtures/tiles/2-1-2.vector.pbf new file mode 100644 index 000000000..4d26226c5 Binary files /dev/null and b/test/fixtures/tiles/2-1-2.vector.pbf differ diff --git a/test/fixtures/tiles/2-2-1.vector.pbf b/test/fixtures/tiles/2-2-1.vector.pbf new file mode 100644 index 000000000..a92e85b60 Binary files /dev/null and b/test/fixtures/tiles/2-2-1.vector.pbf differ diff --git a/test/fixtures/tiles/2-2-2.vector.pbf b/test/fixtures/tiles/2-2-2.vector.pbf new file mode 100644 index 000000000..209014708 Binary files /dev/null and b/test/fixtures/tiles/2-2-2.vector.pbf differ diff --git a/test/headless.cpp b/test/headless.cpp index 385170209..0ed6e0a09 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -3,18 +3,39 @@ #include #include #include -#include +#include + +#include #include "../common/headless_view.hpp" -#include -#include +const std::string base_directory = []{ + std::string fn = __FILE__; + fn.erase(fn.find_last_of("/")); + return fn; +}(); -TEST(Headless, initialize) { - const int width = 1024; - const int height = 768; +class HeadlessTest : public ::testing::TestWithParam {}; - llmr::util::timer timer; +TEST_P(HeadlessTest, render) { + const char *base = GetParam(); + + const std::string style = llmr::util::read_file(base_directory + "/fixtures/styles/" + base + ".style.json"); + const std::string info = llmr::util::read_file(base_directory + "/fixtures/styles/" + base + ".info.json"); + const std::string expected_image = base_directory + "/fixtures/styles/" + base + ".expected.png"; + const std::string actual_image = base_directory + "/fixtures/styles/" + base + ".actual.png"; + + // Parse settings. + rapidjson::Document doc; + doc.Parse<0>((const char *const)info.c_str()); + ASSERT_EQ(false, doc.HasParseError()); + + const double zoom = doc.HasMember("zoom") ? doc["zoom"].GetDouble() : 0; + const double angle = doc.HasMember("angle") ? doc["angle"].GetDouble() : 0; + const double longitude = doc.HasMember("longitude") ? doc["longitude"].GetDouble() : 0; + const double latitude = doc.HasMember("latitude") ? doc["latitude"].GetDouble() : 0; + const unsigned int width = doc.HasMember("width") ? doc["width"].GetUint() : 0; + const unsigned int height = doc.HasMember("height") ? doc["height"].GetUint() : 0; // Setup OpenGL llmr::HeadlessView view; @@ -23,41 +44,27 @@ TEST(Headless, initialize) { view.resize(width, height); map.resize(width, height); - timer.report("map setup"); + map.setStyleJSON(style); - std::ifstream stylefile("./style.min.js"); - ASSERT_TRUE(stylefile.good()); - std::stringstream stylejson; - stylejson << stylefile.rdbuf(); - - map.setStyleJSON(stylejson.str()); - - map.setLonLatZoom(0, 0, 2); - map.setAngle(0); + map.setLonLatZoom(longitude, latitude, zoom); + map.setAngle(angle); map.setDebug(false); - timer.report("map style"); - // Run the loop. It will terminate when we don't have any further listeners. map.run(); - timer.report("map loop"); + const std::unique_ptr pixels(new uint32_t[width * height]); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); - uint32_t *pixels = new uint32_t[width * height]; + const std::string image = llmr::util::compress_png(width, height, pixels.get(), true); + llmr::util::write_file(actual_image, image); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - timer.report("gl readpixels"); - - std::string result = llmr::util::compress_png(width, height, pixels, true); - - timer.report("compress png"); - - llmr::util::write_file("out.png", result); - - timer.report("save file"); - - delete[] pixels; - - timer.report("destruct"); + const std::string expected_image_data(llmr::util::read_file(expected_image)); + const llmr::util::Image expected(expected_image_data, true); + ASSERT_EQ(width, expected.getWidth()); + ASSERT_EQ(height, expected.getHeight()); + ASSERT_EQ(0, std::memcmp(pixels.get(), expected.getData(), width * height * 4)); } + +INSTANTIATE_TEST_CASE_P(Headless, HeadlessTest, + ::testing::Values("0", "1")); diff --git a/test/test.gyp b/test/test.gyp index e3e08c3fd..1dce41053 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -15,6 +15,11 @@ '-framework OpenGL', ], }, + 'xcode_settings': { + 'OTHER_LDFLAGS': [ + '-framework OpenGL', + ], + }, }, { 'link_settings': { 'libraries': [ @@ -161,16 +166,13 @@ "./headless.cpp", "../common/headless_view.hpp", "../common/headless_view.cpp", - "../common/curl_request.hpp", - "../common/curl_request.cpp", + "./fixtures/fixture_request.cpp", ], "dependencies": [ "../deps/gtest/gtest.gyp:gtest", "../llmr.gyp:llmr-x86", "link_gl", - "link_curl", '../llmr.gyp:copy_default_stylesheet', - '../llmr.gyp:copy_certificate_bundle', ] }, { diff --git a/travis/travis-resources.template b/travis/travis-resources.template new file mode 100644 index 000000000..afe0478e3 --- /dev/null +++ b/travis/travis-resources.template @@ -0,0 +1,74 @@ + +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "mapbox-gl-native travis resources", + "Resources": { + "BuildUser": { + "Type": "AWS::IAM::User", + "Properties": { + "Policies": [ + { + "PolicyName": "list", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mapbox-gl-testing" + ] + } + ] + } + }, + { + "PolicyName": "build", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject", + "s3:GetObject", + "s3:GetObjectAcl", + "s3:PutObject", + "s3:PutObjectAcl" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mapbox-gl-testing/*" + ] + } + ] + } + } + ] + } + }, + "BuildUserKey": { + "Type": "AWS::IAM::AccessKey", + "Properties": { + "UserName": { + "Ref": "BuildUser" + } + } + } + }, + "Outputs": { + "AccessKeyId": { + "Value": { + "Ref": "BuildUserKey" + } + }, + "SecretAccessKey": { + "Value": { + "Fn::GetAtt": [ + "BuildUserKey", + "SecretAccessKey" + ] + } + } + } +} +