1 #include "catch.hpp"
2 
3 #include <osmium/builder/attr.hpp>
4 #include <osmium/builder/builder_helper.hpp>
5 #include <osmium/memory/buffer.hpp>
6 #include <osmium/osm/tag.hpp>
7 
8 #include <map>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 using namespace osmium::builder::attr; // NOLINT(google-build-using-namespace)
14 
15 TEST_CASE("create tag list") {
16     osmium::memory::Buffer buffer{10240};
17 
18     SECTION("with TagListBuilder from char*") {
19         {
20             osmium::builder::TagListBuilder builder(buffer);
21             builder.add_tag("highway", "primary");
22             builder.add_tag("name", "Main Street");
23         }
24         buffer.commit();
25     }
26 
27     SECTION("with TagListBuilder from pair<const char*, const char*>") {
28         {
29             osmium::builder::TagListBuilder builder(buffer);
30             builder.add_tag(std::pair<const char*, const char*>{"highway", "primary"});
31             builder.add_tag("name", "Main Street");
32         }
33         buffer.commit();
34     }
35 
36     SECTION("with TagListBuilder from pair<const char* const, const char*>") {
37         {
38             osmium::builder::TagListBuilder builder(buffer);
39             builder.add_tag(std::pair<const char* const, const char*>{"highway", "primary"});
40             builder.add_tag("name", "Main Street");
41         }
42         buffer.commit();
43     }
44 
45     SECTION("with TagListBuilder from pair<const char*, const char* const>") {
46         {
47             osmium::builder::TagListBuilder builder(buffer);
48             builder.add_tag(std::pair<const char*, const char* const>{"highway", "primary"});
49             builder.add_tag("name", "Main Street");
50         }
51         buffer.commit();
52     }
53 
54     SECTION("with TagListBuilder from pair<const char* const, const char* const>") {
55         {
56             osmium::builder::TagListBuilder builder(buffer);
57             builder.add_tag(std::pair<const char* const, const char* const>{"highway", "primary"});
58             builder.add_tag("name", "Main Street");
59         }
60         buffer.commit();
61     }
62 
63     SECTION("with TagListBuilder from char* with length") {
64         {
65             osmium::builder::TagListBuilder builder(buffer);
66             builder.add_tag("highway", strlen("highway"), "primary", strlen("primary"));
67             builder.add_tag("nameXX", 4, "Main Street", 11);
68         }
69         buffer.commit();
70     }
71 
72     SECTION("with TagListBuilder from std::string") {
73         {
74             osmium::builder::TagListBuilder builder(buffer);
75             builder.add_tag(std::string("highway"), std::string("primary"));
76             const std::string source = "name";
77             std::string gps = "Main Street";
78             builder.add_tag(source, gps);
79         }
80         buffer.commit();
81     }
82 
83     SECTION("with add_tag_list from pair<const char*, const char*>") {
84         osmium::builder::add_tag_list(buffer,
85             _tag(std::pair<const char*, const char*>{"highway", "primary"}),
86             _tag("name", "Main Street")
87         );
88     }
89 
90     SECTION("with add_tag_list from pair<const char* const, const char*>") {
91         osmium::builder::add_tag_list(buffer,
92             _tag(std::pair<const char* const, const char*>{"highway", "primary"}),
93             _tag("name", "Main Street")
94         );
95     }
96 
97     SECTION("with add_tag_list from pair<const char*, const char* const>") {
98         osmium::builder::add_tag_list(buffer,
99             _tag(std::pair<const char*, const char* const>{"highway", "primary"}),
100             _tag("name", "Main Street")
101         );
102     }
103 
104     SECTION("with add_tag_list from pair<const char* const, const char* const>") {
105         osmium::builder::add_tag_list(buffer,
106             _tag(std::pair<const char* const, const char* const>{"highway", "primary"}),
107             _tag("name", "Main Street")
108         );
109     }
110 
111     SECTION("with add_tag_list from vector of pairs (const/const)") {
112         std::vector<std::pair<const char* const, const char* const>> v{
113             { "highway", "primary" },
114             { "name", "Main Street" }
115         };
116         osmium::builder::add_tag_list(buffer, _tags(v));
117     }
118 
119     SECTION("with add_tag_list from vector of pairs (const/nc)") {
120         std::vector<std::pair<const char* const, const char*>> v{
121             { "highway", "primary" },
122             { "name", "Main Street" }
123         };
124         osmium::builder::add_tag_list(buffer, _tags(v));
125     }
126 
127     SECTION("with add_tag_list from vector of pairs (nc/const)") {
128         std::vector<std::pair<const char*, const char* const>> v{
129             { "highway", "primary" },
130             { "name", "Main Street" }
131         };
132         osmium::builder::add_tag_list(buffer, _tags(v));
133     }
134 
135     SECTION("with add_tag_list from vector of pairs (nc/nc)") {
136         std::vector<std::pair<const char*, const char*>> v{
137             { "highway", "primary" },
138             { "name", "Main Street" }
139         };
140         osmium::builder::add_tag_list(buffer, _tags(v));
141     }
142 
143     SECTION("with add_tag_list from initializer list") {
144         osmium::builder::add_tag_list(buffer, _tags({
145             { "highway", "primary" },
146             { "name", "Main Street" }
147         }));
148     }
149 
150     SECTION("with add_tag_list from _tag") {
151         osmium::builder::add_tag_list(buffer,
152             _tag("highway", "primary"),
153             _tag("name", "Main Street")
154         );
155     }
156 
157     SECTION("with add_tag_list from map") {
158         std::map<std::string, std::string> m{
159             { "highway", "primary" },
160             { "name", "Main Street" }
161         };
162         osmium::builder::add_tag_list(buffer, _tags(m));
163     }
164 
165     const osmium::TagList& tl = *buffer.select<osmium::TagList>().cbegin();
166     REQUIRE(osmium::item_type::tag_list == tl.type());
167     REQUIRE(2 == tl.size());
168 
169     REQUIRE(tl.has_key("highway"));
170     REQUIRE_FALSE(tl.has_key("unknown"));
171     REQUIRE(tl.has_tag("highway", "primary"));
172     REQUIRE_FALSE(tl.has_tag("highway", "false"));
173     REQUIRE_FALSE(tl.has_tag("foo", "bar"));
174 
175     auto it = tl.begin();
176     REQUIRE(std::string("highway")     == it->key());
177     REQUIRE(std::string("primary")     == it->value());
178     ++it;
179     REQUIRE(std::string("name")        == it->key());
180     REQUIRE(std::string("Main Street") == it->value());
181     ++it;
182     REQUIRE(it == tl.end());
183 
184     REQUIRE(std::string("primary") == tl.get_value_by_key("highway"));
185     REQUIRE(nullptr == tl.get_value_by_key("foo"));
186     REQUIRE(std::string("default") == tl.get_value_by_key("foo", "default"));
187 
188     REQUIRE(std::string("Main Street") == tl["name"]);
189 }
190 
191 TEST_CASE("empty keys and values are okay") {
192     osmium::memory::Buffer buffer{10240};
193 
194     const auto pos = osmium::builder::add_tag_list(buffer,
195         _tag("empty value", ""),
196         _tag("", "empty key")
197     );
198     const osmium::TagList& tl = buffer.get<osmium::TagList>(pos);
199 
200     REQUIRE(osmium::item_type::tag_list == tl.type());
201     REQUIRE(2 == tl.size());
202 
203     auto it = tl.begin();
204     REQUIRE(std::string("empty value") == it->key());
205     REQUIRE(std::string("")            == it->value());
206     ++it;
207     REQUIRE(std::string("")            == it->key());
208     REQUIRE(std::string("empty key")   == it->value());
209     ++it;
210     REQUIRE(it == tl.end());
211 
212     REQUIRE(std::string("") == tl.get_value_by_key("empty value"));
213     REQUIRE(std::string("empty key") == tl.get_value_by_key(""));
214 }
215 
216 TEST_CASE("tag key or value is too long") {
217     osmium::memory::Buffer buffer{10240};
218     osmium::builder::TagListBuilder builder{buffer};
219 
220     const char kv[2000] = "";
221     builder.add_tag(kv, 1, kv, 1000);
222     REQUIRE_THROWS(builder.add_tag(kv, 1500, kv, 1));
223     REQUIRE_THROWS(builder.add_tag(kv, 1, kv, 1500));
224 }
225 
226