#include "catch.hpp" #include "utils.hpp" #include #include #include // 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 : public osmium::io::Decompressor { std::string m_fail_in; int m_read_count = 0; public: explicit MockDecompressor(const std::string& fail_in) : Decompressor(), m_fail_in(fail_in) { if (m_fail_in == "constructor") { throw std::runtime_error{"error constructor"}; } } ~MockDecompressor() noexcept final = default; void add_node(std::string& s, int i) { s += "\n"; } std::string read() final { std::string buffer; ++m_read_count; if (m_read_count == 1) { if (m_fail_in == "first read") { throw std::runtime_error{"error first read"}; } else { buffer += "\n\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"}; } else { for (int i = 1000; i < 2000; ++i) { add_node(buffer, i); } } } else if (m_read_count == 3) { buffer += ""; } return buffer; } void close() final { 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().register_compression(osmium::io::file_compression::gzip, [](int, osmium::io::fsync) { return nullptr; }, [&](int) { return new MockDecompressor(fail_in); }, [](const char*, size_t) { return nullptr; } ); SECTION("fail in constructor") { fail_in = "constructor"; try { 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); } }