diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2016-02-18 12:41:09 +0100 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-03-22 11:56:01 -0700 |
commit | db5ac4785fdc02b4e233201bb3c6f55270e3c65d (patch) | |
tree | 0c730d62e471d211924c486e1eeadf5efb305eaf /test/src | |
parent | 61920071cd221d0d0627e01893185f0f19b55a98 (diff) | |
download | qtlocation-mapboxgl-db5ac4785fdc02b4e233201bb3c6f55270e3c65d.tar.gz |
[test] rearrange test files so they're not in the fixtures folder
Diffstat (limited to 'test/src')
-rw-r--r-- | test/src/fixture_log_observer.cpp | 105 | ||||
-rw-r--r-- | test/src/main.cpp | 6 | ||||
-rw-r--r-- | test/src/stub_file_source.cpp | 69 | ||||
-rw-r--r-- | test/src/util.cpp | 129 |
4 files changed, 309 insertions, 0 deletions
diff --git a/test/src/fixture_log_observer.cpp b/test/src/fixture_log_observer.cpp new file mode 100644 index 0000000000..302fdc7081 --- /dev/null +++ b/test/src/fixture_log_observer.cpp @@ -0,0 +1,105 @@ +#include <mbgl/test/fixture_log_observer.hpp> +#include <mbgl/test/util.hpp> + +namespace mbgl { + +FixtureLog::Message::Message(EventSeverity severity_, + Event event_, + int64_t code_, + const std::string& msg_) + : severity(severity_), event(event_), code(code_), msg(msg_) { +} + +bool FixtureLog::Message::operator==(const Message& rhs) const { + return severity == rhs.severity && event == rhs.event && code == rhs.code && msg == rhs.msg; +} + +FixtureLog::Message::Message() : severity(), event(), code(), msg() { +} + +FixtureLog::Observer::Observer(FixtureLog* log_) : log(log_) { +} + +FixtureLog::Observer::~Observer() { + if (log) { + log->observer = nullptr; + } + std::cerr << unchecked(); +} + +bool FixtureLog::Observer::onRecord(EventSeverity severity, + Event event, + int64_t code, + const std::string& msg) { + std::lock_guard<std::mutex> lock(messagesMutex); + + messages.emplace_back(severity, event, code, msg); + + return true; +} + +bool FixtureLog::Observer::empty() const { + std::lock_guard<std::mutex> lock(messagesMutex); + + return messages.empty(); +} + +size_t FixtureLog::Observer::count(const Message& message) const { + std::lock_guard<std::mutex> lock(messagesMutex); + + size_t message_count = 0; + for (const auto& msg : messages) { + if (msg == message) { + message_count++; + msg.checked = true; + } + } + return message_count; +} + +FixtureLog::FixtureLog() : observer(new FixtureLogObserver(this)) { + Log::setObserver(std::unique_ptr<Log::Observer>(observer)); +} + +bool FixtureLog::empty() const { + return observer ? observer->empty() : true; +} + +size_t FixtureLog::count(const FixtureLog::Message& message) const { + return observer ? observer->count(message) : 0; +} + +FixtureLog::~FixtureLog() { + if (observer) { + Log::removeObserver(); + } +} + +std::vector<FixtureLog::Message> FixtureLogObserver::unchecked() const { + std::lock_guard<std::mutex> lock(messagesMutex); + + std::vector<Message> unchecked_messages; + for (const auto& msg : messages) { + if (!msg.checked) { + unchecked_messages.push_back(msg); + msg.checked = true; + } + } + return unchecked_messages; +} + +::std::ostream& operator<<(::std::ostream& os, const std::vector<FixtureLog::Message>& messages) { + for (const auto& message : messages) { + os << "- " << message; + } + return os; +} + +::std::ostream& operator<<(::std::ostream& os, const FixtureLog::Message& message) { + os << "[\"" << message.severity << "\", \"" << message.event << "\""; + os << ", " << message.code; + os << ", \"" << message.msg << "\""; + return os << "]" << std::endl; +} + +} // namespace mbgl diff --git a/test/src/main.cpp b/test/src/main.cpp new file mode 100644 index 0000000000..f2d2944ec7 --- /dev/null +++ b/test/src/main.cpp @@ -0,0 +1,6 @@ +#include <mbgl/test/util.hpp> + +GTEST_API_ int main(int argc, char *argv[]) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/src/stub_file_source.cpp b/test/src/stub_file_source.cpp new file mode 100644 index 0000000000..5a062672bb --- /dev/null +++ b/test/src/stub_file_source.cpp @@ -0,0 +1,69 @@ +#include <mbgl/test/stub_file_source.hpp> + +namespace mbgl { + +using namespace std::chrono_literals; + +class StubFileRequest : public FileRequest { +public: + StubFileRequest(StubFileSource& fileSource_) + : fileSource(fileSource_) { + } + + ~StubFileRequest() { + fileSource.pending.erase(this); + } + + StubFileSource& fileSource; +}; + +StubFileSource::StubFileSource() { + timer.start(10ms, 10ms, [this] { + // Explicit copy to avoid iterator invalidation if ~StubFileRequest gets called within the loop. + auto pending_ = pending; + for (auto& pair : pending_) { + optional<Response> res = std::get<1>(pair.second)(std::get<0>(pair.second)); + if (res) { + std::get<2>(pair.second)(*res); + } + } + }); +} + +StubFileSource::~StubFileSource() = default; + +std::unique_ptr<FileRequest> StubFileSource::request(const Resource& resource, Callback callback) { + auto req = std::make_unique<StubFileRequest>(*this); + pending.emplace(req.get(), std::make_tuple(resource, response, callback)); + return std::move(req); +} + +optional<Response> StubFileSource::defaultResponse(const Resource& resource) { + switch (resource.kind) { + case Resource::Kind::Style: + if (!styleResponse) throw std::runtime_error("unexpected style request"); + return styleResponse(resource); + case Resource::Kind::Source: + if (!sourceResponse) throw std::runtime_error("unexpected source request"); + return sourceResponse(resource); + case Resource::Kind::Tile: + if (!tileResponse) throw std::runtime_error("unexpected tile request"); + return tileResponse(resource); + case Resource::Kind::Glyphs: + if (!glyphsResponse) throw std::runtime_error("unexpected glyphs request"); + return glyphsResponse(resource); + case Resource::Kind::SpriteJSON: + if (!spriteJSONResponse) throw std::runtime_error("unexpected sprite JSON request"); + return spriteJSONResponse(resource); + case Resource::Kind::SpriteImage: + if (!spriteImageResponse) throw std::runtime_error("unexpected sprite image request"); + return spriteImageResponse(resource); + case Resource::Kind::Unknown: + throw std::runtime_error("unknown resource type"); + } + + // The above switch is exhaustive, but placate GCC nonetheless: + return Response(); +} + +} // namespace mbgl diff --git a/test/src/util.cpp b/test/src/util.cpp new file mode 100644 index 0000000000..ca2282a4b5 --- /dev/null +++ b/test/src/util.cpp @@ -0,0 +1,129 @@ +#include <mbgl/test/util.hpp> + +#include <mbgl/map/map.hpp> +#include <mbgl/platform/log.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/util/io.hpp> +#include <mbgl/util/chrono.hpp> + +#include <mapbox/pixelmatch.hpp> + +#include <csignal> +#include <future> + +#include <unistd.h> + +namespace mbgl { +namespace test { + +Server::Server(const char* executable) { + int input[2]; + int output[2]; + + if (pipe(input)) { + throw std::runtime_error("Cannot create server input pipe"); + } + if (pipe(output)) { + throw std::runtime_error("Cannot create server output pipe"); + } + + // Store the parent => child pipe so that we can close it in the destructor. + fd = input[1]; + + pid_t pid = fork(); + if (pid < 0) { + Log::Error(Event::Setup, "Cannot create server process"); + exit(1); + } else if (pid == 0) { + // This is the child process. + + // Connect the parent => child pipe to stdin. + while ((dup2(input[0], STDIN_FILENO) == -1) && (errno == EINTR)) {} + close(input[0]); + close(input[1]); + + // Move the child => parent side of the pipe to stdout. + while ((dup2(output[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} + close(output[1]); + close(output[0]); + + // Launch the actual server process. + int ret = execl(executable, executable, nullptr); + + // This call should not return. In case execl failed, we exit anyway. + if (ret < 0) { + Log::Error(Event::Setup, "Failed to start server: %s", strerror(errno)); + } + exit(0); + } else { + // This is the parent process. + + // Close the unneeded sides of the pipes. + close(output[1]); + close(input[0]); + + // Wait until the server process sends at least 2 bytes or closes the handle. + char buffer[2]; + ssize_t bytes, total = 0; + while (total < 2 && (bytes = read(output[0], buffer + total, 2 - total)) != 0) { + total += bytes; + } + + // Close child => parent pipe. + close(output[0]); + + // Check signature + if (total != 2 || strncmp(buffer, "OK", 2) != 0) { + throw std::runtime_error("Failed to start server: Invalid signature"); + } + } +} + +Server::~Server() { + if (fd > 0) { + close(fd); + } +} + +PremultipliedImage render(Map& map) { + std::promise<PremultipliedImage> promise; + map.renderStill([&](std::exception_ptr, PremultipliedImage&& image) { + promise.set_value(std::move(image)); + }); + return promise.get_future().get(); +} + +void checkImage(const std::string& base, + const PremultipliedImage& actual, + double imageThreshold, + double pixelThreshold) { +#if !TEST_READ_ONLY + if (getenv("UPDATE")) { + util::write_file(base + "/expected.png", encodePNG(actual)); + return; + } +#endif + + PremultipliedImage expected = decodeImage(util::read_file(base + "/expected.png")); + PremultipliedImage diff { expected.width, expected.height }; + + ASSERT_EQ(expected.width, actual.width); + ASSERT_EQ(expected.height, actual.height); + + double pixels = mapbox::pixelmatch(actual.data.get(), + expected.data.get(), + expected.width, + expected.height, + diff.data.get(), + pixelThreshold); + + EXPECT_LE(pixels / (expected.width * expected.height), imageThreshold); + +#if !TEST_READ_ONLY + util::write_file(base + "/actual.png", encodePNG(actual)); + util::write_file(base + "/diff.png", encodePNG(diff)); +#endif +} + +} // namespace test +} // namespace mbgl |