[test] rearrange test files so they're not in the fixtures folder
This commit is contained in:
committed by
John Firebaugh
parent
61920071cd
commit
db5ac4785f
105
test/src/fixture_log_observer.cpp
Normal file
105
test/src/fixture_log_observer.cpp
Normal file
@@ -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
|
||||
6
test/src/main.cpp
Normal file
6
test/src/main.cpp
Normal file
@@ -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();
|
||||
}
|
||||
69
test/src/stub_file_source.cpp
Normal file
69
test/src/stub_file_source.cpp
Normal file
@@ -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
|
||||
129
test/src/util.cpp
Normal file
129
test/src/util.cpp
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user