Skip to content

Commit 9bcc5e1

Browse files
committed
Extend CheckOrder handler class: Optionally work with history files
1 parent cab4f46 commit 9bcc5e1

2 files changed

Lines changed: 200 additions & 6 deletions

File tree

include/osmium/handler/check_order.hpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,11 @@ namespace osmium {
7676
* IDs are ordered first then positive IDs, both ordered by absolute
7777
* value.
7878
*
79-
* IDs have to be unique for each type. This check will fail for
80-
* history files.
79+
* Constructor has a single bool parameter. If this is false (default)
80+
* the check is done for normal OSM data files, i.e. IDs have to be
81+
* unique for each type. If this is true, the check is done for OSM
82+
* history files, the combination ID/version has to be unique and the
83+
* versions need to be in order.
8184
*
8285
* To use this, add a CheckOrder member variable to your handler and
8386
* call the node(), way(), and relation() methods from your node(),
@@ -89,12 +92,17 @@ namespace osmium {
8992
osmium::object_id_type m_max_node_id = 0;
9093
osmium::object_id_type m_max_way_id = 0;
9194
osmium::object_id_type m_max_relation_id = 0;
95+
osmium::object_version_type m_last_version = 0;
9296
bool m_has_node = false;
9397
bool m_has_way = false;
9498
bool m_has_relation = false;
99+
bool m_with_history;
95100

96101
public:
97102

103+
CheckOrder(bool with_history = false) : m_with_history(with_history) {
104+
}
105+
98106
void node(const osmium::Node& node) {
99107
if (m_has_way) {
100108
throw out_of_order_error{"Found a node after a way.", node.id()};
@@ -105,7 +113,13 @@ namespace osmium {
105113

106114
if (m_has_node) {
107115
if (m_max_node_id == node.id()) {
108-
throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
116+
if (m_with_history) {
117+
if (node.version() <= m_last_version) {
118+
throw out_of_order_error{"Versions out of order", node.id()};
119+
}
120+
} else {
121+
throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
122+
}
109123
}
110124
if (id_order{}(node.id(), m_max_node_id)) {
111125
throw out_of_order_error{"Node IDs out of order: " + std::to_string(node.id()), node.id()};
@@ -115,6 +129,10 @@ namespace osmium {
115129
m_max_node_id = node.id();
116130
m_has_node = true;
117131
}
132+
133+
if (m_with_history) {
134+
m_last_version = node.version();
135+
}
118136
}
119137

120138
void way(const osmium::Way& way) {
@@ -124,7 +142,13 @@ namespace osmium {
124142

125143
if (m_has_way) {
126144
if (m_max_way_id == way.id()) {
127-
throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
145+
if (m_with_history) {
146+
if (way.version() <= m_last_version) {
147+
throw out_of_order_error{"Versions out of order", way.id()};
148+
}
149+
} else {
150+
throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
151+
}
128152
}
129153
if (id_order{}(way.id(), m_max_way_id)) {
130154
throw out_of_order_error{"Way IDs out of order: " + std::to_string(way.id()), way.id()};
@@ -134,12 +158,22 @@ namespace osmium {
134158
m_max_way_id = way.id();
135159
m_has_way = true;
136160
}
161+
162+
if (m_with_history) {
163+
m_last_version = way.version();
164+
}
137165
}
138166

139167
void relation(const osmium::Relation& relation) {
140168
if (m_has_relation) {
141169
if (m_max_relation_id == relation.id()) {
142-
throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
170+
if (m_with_history) {
171+
if (relation.version() <= m_last_version) {
172+
throw out_of_order_error{"Versions out of order", relation.id()};
173+
}
174+
} else {
175+
throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
176+
}
143177
}
144178
if (id_order{}(relation.id(), m_max_relation_id)) {
145179
throw out_of_order_error{"Relation IDs out of order: " + std::to_string(relation.id()), relation.id()};
@@ -149,6 +183,10 @@ namespace osmium {
149183
m_max_relation_id = relation.id();
150184
m_has_relation = true;
151185
}
186+
187+
if (m_with_history) {
188+
m_last_version = relation.version();
189+
}
152190
}
153191

154192
osmium::object_id_type max_node_id() const noexcept {

test/t/handler/test_check_order_handler.cpp

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <osmium/opl.hpp>
66
#include <osmium/visitor.hpp>
77

8-
TEST_CASE("CheckOrder handler if everything is in order") {
8+
TEST_CASE("CheckOrder handler: everything is in order") {
99
osmium::memory::Buffer buffer{1024};
1010

1111
REQUIRE(osmium::opl_parse("n-126", buffer));
@@ -126,3 +126,159 @@ TEST_CASE("CheckOrder handler: Ways after relations") {
126126
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
127127
}
128128

129+
TEST_CASE("CheckOrder handler for history: everything is in order") {
130+
osmium::memory::Buffer buffer{1024};
131+
132+
REQUIRE(osmium::opl_parse("n-126", buffer));
133+
REQUIRE(osmium::opl_parse("n123", buffer));
134+
REQUIRE(osmium::opl_parse("n124", buffer));
135+
REQUIRE(osmium::opl_parse("n128", buffer));
136+
REQUIRE(osmium::opl_parse("w-100", buffer));
137+
REQUIRE(osmium::opl_parse("w100", buffer));
138+
REQUIRE(osmium::opl_parse("w102", buffer));
139+
REQUIRE(osmium::opl_parse("r-200", buffer));
140+
REQUIRE(osmium::opl_parse("r100", buffer));
141+
142+
osmium::handler::CheckOrder handler{true};
143+
osmium::apply(buffer, handler);
144+
REQUIRE(handler.max_node_id() == 128);
145+
REQUIRE(handler.max_way_id() == 102);
146+
REQUIRE(handler.max_relation_id() == 100);
147+
}
148+
149+
TEST_CASE("CheckOrder handler for history: versions in order") {
150+
osmium::memory::Buffer buffer{1024};
151+
152+
REQUIRE(osmium::opl_parse("n1 v1", buffer));
153+
REQUIRE(osmium::opl_parse("n1 v2", buffer));
154+
REQUIRE(osmium::opl_parse("n2 v2", buffer));
155+
REQUIRE(osmium::opl_parse("n3 v1", buffer));
156+
157+
REQUIRE(osmium::opl_parse("w1 v1", buffer));
158+
REQUIRE(osmium::opl_parse("w1 v2", buffer));
159+
REQUIRE(osmium::opl_parse("w2 v2", buffer));
160+
REQUIRE(osmium::opl_parse("w3 v1", buffer));
161+
162+
REQUIRE(osmium::opl_parse("r1 v1", buffer));
163+
REQUIRE(osmium::opl_parse("r1 v2", buffer));
164+
REQUIRE(osmium::opl_parse("r2 v2", buffer));
165+
REQUIRE(osmium::opl_parse("r3 v1", buffer));
166+
167+
osmium::handler::CheckOrder handler{true};
168+
osmium::apply(buffer, handler);
169+
REQUIRE(handler.max_node_id() == 3);
170+
REQUIRE(handler.max_way_id() == 3);
171+
REQUIRE(handler.max_relation_id() == 3);
172+
}
173+
174+
TEST_CASE("CheckOrder handler for history: Nodes must be in order") {
175+
osmium::memory::Buffer buffer{1024};
176+
177+
REQUIRE(osmium::opl_parse("n3", buffer));
178+
179+
SECTION("Positive ID") {
180+
REQUIRE(osmium::opl_parse("n2", buffer));
181+
}
182+
SECTION("Negative ID") {
183+
REQUIRE(osmium::opl_parse("n-2", buffer));
184+
}
185+
186+
osmium::handler::CheckOrder handler{true};
187+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
188+
}
189+
190+
TEST_CASE("CheckOrder handler for history: Ways must be in order") {
191+
osmium::memory::Buffer buffer{1024};
192+
193+
REQUIRE(osmium::opl_parse("w3", buffer));
194+
SECTION("Positive ID") {
195+
REQUIRE(osmium::opl_parse("w2", buffer));
196+
}
197+
SECTION("Negative ID") {
198+
REQUIRE(osmium::opl_parse("w-2", buffer));
199+
}
200+
201+
osmium::handler::CheckOrder handler{true};
202+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
203+
}
204+
205+
TEST_CASE("CheckOrder handler for history: Relations must be in order") {
206+
osmium::memory::Buffer buffer{1024};
207+
208+
REQUIRE(osmium::opl_parse("r3", buffer));
209+
SECTION("Positive ID") {
210+
REQUIRE(osmium::opl_parse("r2", buffer));
211+
}
212+
SECTION("Negative ID") {
213+
REQUIRE(osmium::opl_parse("r-2", buffer));
214+
}
215+
216+
osmium::handler::CheckOrder handler{true};
217+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
218+
}
219+
220+
TEST_CASE("CheckOrder handler for history: Same id/version twice is not allowed") {
221+
osmium::memory::Buffer buffer{1024};
222+
223+
REQUIRE(osmium::opl_parse("n3 v1", buffer));
224+
REQUIRE(osmium::opl_parse("n3 v1", buffer));
225+
226+
osmium::handler::CheckOrder handler{true};
227+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
228+
}
229+
230+
TEST_CASE("CheckOrder handler for history: Versions must be ordered") {
231+
osmium::memory::Buffer buffer{1024};
232+
233+
REQUIRE(osmium::opl_parse("n3 v2", buffer));
234+
REQUIRE(osmium::opl_parse("n3 v1", buffer));
235+
236+
osmium::handler::CheckOrder handler{true};
237+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
238+
}
239+
240+
TEST_CASE("CheckOrder handler for history: Nodes after ways") {
241+
osmium::memory::Buffer buffer{1024};
242+
243+
REQUIRE(osmium::opl_parse("w50", buffer));
244+
SECTION("Positive ID") {
245+
REQUIRE(osmium::opl_parse("n30", buffer));
246+
}
247+
SECTION("Negative ID") {
248+
REQUIRE(osmium::opl_parse("n-30", buffer));
249+
}
250+
251+
osmium::handler::CheckOrder handler{true};
252+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
253+
}
254+
255+
TEST_CASE("CheckOrder handler for history: Nodes after relations") {
256+
osmium::memory::Buffer buffer{1024};
257+
258+
REQUIRE(osmium::opl_parse("r50", buffer));
259+
SECTION("Positive ID") {
260+
REQUIRE(osmium::opl_parse("n30", buffer));
261+
}
262+
SECTION("Negative ID") {
263+
REQUIRE(osmium::opl_parse("n-30", buffer));
264+
}
265+
266+
osmium::handler::CheckOrder handler{true};
267+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
268+
}
269+
270+
TEST_CASE("CheckOrder handler for history: Ways after relations") {
271+
osmium::memory::Buffer buffer{1024};
272+
273+
REQUIRE(osmium::opl_parse("r50", buffer));
274+
SECTION("Positive ID") {
275+
REQUIRE(osmium::opl_parse("w30", buffer));
276+
}
277+
SECTION("Negative ID") {
278+
REQUIRE(osmium::opl_parse("w-30", buffer));
279+
}
280+
281+
osmium::handler::CheckOrder handler{true};
282+
REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
283+
}
284+

0 commit comments

Comments
 (0)