1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#include "catch.hpp"
#include "utils.hpp"
#include <osmium/io/compression.hpp>
#include <osmium/io/xml_input.hpp>
#include <stdexcept>
#include <string>
#include <utility>
// The MockDecompressor behaves like other Decompressor classes, but "invents"
// OSM data in XML format that can be read. Through a parameter to the
// constructor it can be instructed to throw an exception in specific parts
// of its code. This is then used to test the internals of the Reader.
class MockDecompressor final : public osmium::io::Decompressor {
std::string m_fail_in;
int m_read_count = 0;
public:
explicit MockDecompressor(std::string fail_in) :
m_fail_in(std::move(fail_in)) {
if (m_fail_in == "constructor") {
throw std::runtime_error{"error constructor"};
}
}
MockDecompressor(const MockDecompressor&) = delete;
MockDecompressor& operator=(const MockDecompressor&) = delete;
MockDecompressor(MockDecompressor&&) = delete;
MockDecompressor& operator=(MockDecompressor&&) = delete;
~MockDecompressor() noexcept override = default;
static void add_node(std::string& s, int i) {
s += "<node id='";
s += std::to_string(i);
s += "' version='1' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' changeset='1' lon='1.02' lat='1.02'/>\n";
}
std::string read() override {
std::string buffer;
++m_read_count;
if (m_read_count == 1) {
if (m_fail_in == "first read") {
throw std::runtime_error{"error first read"};
}
buffer += "<?xml version='1.0' encoding='UTF-8'?>\n<osm version='0.6' generator='testdata'>\n";
for (int i = 0; i < 1000; ++i) {
add_node(buffer, i);
}
} else if (m_read_count == 2) {
if (m_fail_in == "second read") {
throw std::runtime_error{"error second read"};
}
for (int i = 1000; i < 2000; ++i) {
add_node(buffer, i);
}
} else if (m_read_count == 3) {
buffer += "</osm>";
}
return buffer;
}
void close() override {
if (m_fail_in == "close") {
throw std::runtime_error{"error close"};
}
}
}; // class MockDecompressor
TEST_CASE("Test Reader using MockDecompressor") {
std::string fail_in;
osmium::io::CompressionFactory::instance().clear_register();
osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
[](int /*unused*/, osmium::io::fsync /*unused*/) { return nullptr; },
[&](int /*unused*/) { return new MockDecompressor(fail_in); },
[](const char* /*unused*/, size_t /*unused*/) { return nullptr; }
);
SECTION("fail in constructor") {
fail_in = "constructor";
try {
const osmium::io::Reader reader{with_data_dir("t/io/data.osm.gz")};
REQUIRE(false);
} catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error constructor");
}
}
SECTION("fail in first read") {
fail_in = "first read";
try {
osmium::io::Reader reader{with_data_dir("t/io/data.osm.gz")};
reader.read();
REQUIRE(false);
} catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error first read");
}
}
SECTION("fail in second read") {
fail_in = "second read";
try {
osmium::io::Reader reader{with_data_dir("t/io/data.osm.gz")};
reader.read();
reader.read();
REQUIRE(false);
} catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error second read");
}
}
SECTION("fail in close") {
fail_in = "close";
try {
osmium::io::Reader reader{with_data_dir("t/io/data.osm.gz")};
reader.read();
reader.read();
reader.read();
reader.close();
REQUIRE(false);
} catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error close");
}
}
SECTION("not failing") {
fail_in = "not";
osmium::io::Reader reader{with_data_dir("t/io/data.osm.gz")};
reader.read();
reader.close();
REQUIRE(true);
}
}
|