1 #include "catch.hpp" 2 3 #include "utils.hpp" 4 5 #include <osmium/io/xml_input.hpp> 6 #include <osmium/osm/relation.hpp> 7 #include <osmium/relations/relations_manager.hpp> 8 9 #include <iterator> 10 11 struct EmptyRM : public osmium::relations::RelationsManager<EmptyRM, true, true, true> { 12 }; 13 14 struct TestRM : public osmium::relations::RelationsManager<TestRM, true, true, true> { 15 16 std::size_t count_new_rels = 0; 17 std::size_t count_new_members = 0; 18 std::size_t count_complete_rels = 0; 19 std::size_t count_before = 0; 20 std::size_t count_not_in_any = 0; 21 std::size_t count_after = 0; 22 new_relationTestRM23 bool new_relation(const osmium::Relation& /*relation*/) noexcept { 24 ++count_new_rels; 25 return true; 26 } 27 new_memberTestRM28 bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& /*member*/, std::size_t /*n*/) noexcept { 29 ++count_new_members; 30 return true; 31 } 32 complete_relationTestRM33 void complete_relation(const osmium::Relation& /*relation*/) noexcept { 34 ++count_complete_rels; 35 } 36 before_nodeTestRM37 void before_node(const osmium::Node& /*node*/) noexcept { 38 ++count_before; 39 } 40 node_not_in_any_relationTestRM41 void node_not_in_any_relation(const osmium::Node& /*node*/) noexcept { 42 ++count_not_in_any; 43 } 44 after_nodeTestRM45 void after_node(const osmium::Node& /*node*/) noexcept { 46 ++count_after; 47 } 48 before_wayTestRM49 void before_way(const osmium::Way& /*way*/) noexcept { 50 ++count_before; 51 } 52 way_not_in_any_relationTestRM53 void way_not_in_any_relation(const osmium::Way& /*way*/) noexcept { 54 ++count_not_in_any; 55 } 56 after_wayTestRM57 void after_way(const osmium::Way& /*way*/) noexcept { 58 ++count_after; 59 } 60 before_relationTestRM61 void before_relation(const osmium::Relation& /*relation*/) noexcept { 62 ++count_before; 63 } 64 relation_not_in_any_relationTestRM65 void relation_not_in_any_relation(const osmium::Relation& /*relation*/) noexcept { 66 ++count_not_in_any; 67 } 68 after_relationTestRM69 void after_relation(const osmium::Relation& /*relation*/) noexcept { 70 ++count_after; 71 } 72 73 }; 74 75 struct CallbackRM : public osmium::relations::RelationsManager<CallbackRM, true, false, false> { 76 77 std::size_t count_nodes = 0; 78 new_relationCallbackRM79 static bool new_relation(const osmium::Relation& /*relation*/) noexcept { 80 return true; 81 } 82 new_memberCallbackRM83 static bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& member, std::size_t /*n*/) noexcept { 84 return member.type() == osmium::item_type::node; 85 } 86 complete_relationCallbackRM87 void complete_relation(const osmium::Relation& relation) { 88 for (const auto& member : relation.members()) { 89 if (member.type() == osmium::item_type::node) { 90 ++count_nodes; 91 const auto* node = get_member_node(member.ref()); 92 REQUIRE(node); 93 buffer().add_item(*node); 94 buffer().commit(); 95 } 96 } 97 } 98 99 }; 100 101 struct AnyRM : public osmium::relations::RelationsManager<AnyRM, true, true, true> { new_relationAnyRM102 static bool new_relation(const osmium::Relation& /*relation*/) noexcept { 103 return true; 104 } 105 new_memberAnyRM106 static bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& /*member*/, std::size_t /*n*/) noexcept { 107 return true; 108 } 109 }; 110 111 TEST_CASE("Use RelationsManager without any overloaded functions in derived class") { 112 osmium::io::File file{with_data_dir("t/relations/data.osm")}; 113 114 EmptyRM manager; 115 116 osmium::relations::read_relations(file, manager); 117 118 REQUIRE(manager.member_nodes_database().size() == 2); 119 REQUIRE(manager.member_ways_database().size() == 2); 120 REQUIRE(manager.member_relations_database().size() == 1); 121 122 REQUIRE(manager.member_database(osmium::item_type::node).size() == 2); 123 REQUIRE(manager.member_database(osmium::item_type::way).size() == 2); 124 REQUIRE(manager.member_database(osmium::item_type::relation).size() == 1); 125 126 const auto& m = manager; 127 REQUIRE(m.member_database(osmium::item_type::node).size() == 2); 128 REQUIRE(m.member_database(osmium::item_type::way).size() == 2); 129 REQUIRE(m.member_database(osmium::item_type::relation).size() == 1); 130 131 osmium::io::Reader reader{file}; 132 osmium::apply(reader, manager.handler()); 133 reader.close(); 134 } 135 136 TEST_CASE("Relations manager derived class") { 137 osmium::io::File file{with_data_dir("t/relations/data.osm")}; 138 139 TestRM manager; 140 141 osmium::relations::read_relations(file, manager); 142 143 REQUIRE(manager.member_nodes_database().size() == 2); 144 REQUIRE(manager.member_ways_database().size() == 2); 145 REQUIRE(manager.member_relations_database().size() == 1); 146 147 bool callback_called = false; 148 osmium::io::Reader reader{file}; __anon978e35a40102(osmium::memory::Buffer&& ) 149 osmium::apply(reader, manager.handler([&](osmium::memory::Buffer&& /*unused*/) { 150 callback_called = true; 151 })); 152 reader.close(); 153 REQUIRE_FALSE(callback_called); 154 155 REQUIRE(manager.count_new_rels == 3); 156 REQUIRE(manager.count_new_members == 5); 157 REQUIRE(manager.count_complete_rels == 2); 158 REQUIRE(manager.count_before == 10); 159 REQUIRE(manager.count_not_in_any == 6); 160 REQUIRE(manager.count_after == 10); 161 162 int n = 0; __anon978e35a40202(const osmium::relations::RelationHandle& handle)163 manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){ 164 ++n; 165 REQUIRE(handle->id() == 31); 166 for (const auto& member : handle->members()) { 167 const auto* obj = manager.get_member_object(member); 168 if (member.ref() == 22) { 169 REQUIRE_FALSE(obj); 170 } else { 171 REQUIRE(obj); 172 } 173 } 174 }); 175 REQUIRE(n == 1); 176 } 177 178 TEST_CASE("Relations manager with callback") { 179 osmium::io::File file{with_data_dir("t/relations/data.osm")}; 180 181 CallbackRM manager; 182 183 osmium::relations::read_relations(file, manager); 184 185 REQUIRE(manager.member_nodes_database().size() == 2); 186 REQUIRE(manager.member_ways_database().size() == 0); 187 REQUIRE(manager.member_relations_database().size() == 0); 188 189 bool callback_called = false; 190 osmium::io::Reader reader{file}; __anon978e35a40302(osmium::memory::Buffer&& buffer) 191 osmium::apply(reader, manager.handler([&](osmium::memory::Buffer&& buffer) { 192 callback_called = true; 193 REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2); 194 })); 195 reader.close(); 196 REQUIRE(manager.count_nodes == 2); 197 REQUIRE(callback_called); 198 } 199 200 TEST_CASE("Relations manager reading buffer without callback") { 201 osmium::io::File file{with_data_dir("t/relations/data.osm")}; 202 203 CallbackRM manager; 204 205 osmium::relations::read_relations(file, manager); 206 207 REQUIRE(manager.member_nodes_database().size() == 2); 208 REQUIRE(manager.member_ways_database().size() == 0); 209 REQUIRE(manager.member_relations_database().size() == 0); 210 211 osmium::io::Reader reader{file}; 212 osmium::apply(reader, manager.handler()); 213 reader.close(); 214 215 auto buffer = manager.read(); 216 REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2); 217 218 REQUIRE(manager.count_nodes == 2); 219 } 220 221 TEST_CASE("Access members via RelationsManager") { 222 EmptyRM manager; 223 224 manager.prepare_for_lookup(); 225 226 REQUIRE(nullptr == manager.get_member_node(0)); 227 REQUIRE(nullptr == manager.get_member_way(0)); 228 REQUIRE(nullptr == manager.get_member_relation(0)); 229 230 REQUIRE(nullptr == manager.get_member_node(17)); 231 REQUIRE(nullptr == manager.get_member_way(17)); 232 REQUIRE(nullptr == manager.get_member_relation(17)); 233 } 234 235 TEST_CASE("Handle duplicate members correctly") { 236 osmium::io::File file{with_data_dir("t/relations/dupl_member.osm")}; 237 238 TestRM manager; 239 240 osmium::relations::read_relations(file, manager); 241 242 auto c = manager.member_nodes_database().count(); 243 REQUIRE(c.tracked == 5); 244 REQUIRE(c.available == 0); 245 REQUIRE(c.removed == 0); 246 247 osmium::io::Reader reader{file}; 248 osmium::apply(reader, manager.handler()); 249 reader.close(); 250 251 c = manager.member_nodes_database().count(); 252 REQUIRE(c.tracked == 0); 253 REQUIRE(c.available == 0); 254 REQUIRE(c.removed == 5); 255 256 REQUIRE(manager.count_new_rels == 2); 257 REQUIRE(manager.count_new_members == 5); 258 REQUIRE(manager.count_complete_rels == 2); 259 REQUIRE(manager.count_not_in_any == 2); // 2 relations 260 } 261 262 TEST_CASE("Check handling of missing members") { 263 osmium::io::File file{with_data_dir("t/relations/missing_members.osm")}; 264 265 AnyRM manager; 266 267 osmium::relations::read_relations(file, manager); 268 269 osmium::io::Reader reader{file}; 270 osmium::apply(reader, manager.handler()); 271 reader.close(); 272 273 274 size_t nodes = 0; 275 size_t ways = 0; 276 size_t relations = 0; 277 size_t missing_nodes = 0; 278 size_t missing_ways = 0; 279 size_t missing_relations = 0; 280 __anon978e35a40402(const osmium::relations::RelationHandle& handle)281 manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){ 282 if (handle->id() != 31) { 283 // count relation 31 only 284 return; 285 } 286 for (const auto& member : handle->members()) { 287 // RelationMember::ref() is supposed to returns 0 if we are interested in the member. 288 // RelationsManagerBase::get_member_object() is supposed to return a nullptr if the 289 // member is not available (missing in the input file). 290 const osmium::OSMObject* object = manager.get_member_object(member); 291 switch (member.type()) { 292 case osmium::item_type::node : 293 ++nodes; 294 if (member.ref() != 0 && !object) { 295 ++missing_nodes; 296 } 297 break; 298 case osmium::item_type::way : 299 ++ways; 300 if (member.ref() != 0 && !object) { 301 ++missing_ways; 302 } 303 break; 304 case osmium::item_type::relation : 305 ++relations; 306 if (member.ref() != 0 && !object) { 307 ++missing_relations; 308 } 309 break; 310 default: 311 break; 312 } 313 } 314 }); 315 REQUIRE(nodes == 2); 316 REQUIRE(ways == 3); 317 REQUIRE(relations == 3); 318 REQUIRE(missing_nodes == 1); 319 REQUIRE(missing_ways == 1); 320 REQUIRE(missing_relations == 2); 321 } 322 323