Merge pull request #2038 from Project-OSRM/update/osmium_2.6.1

Update/osmium 2.6.1
This commit is contained in:
Patrick Niklaus 2016-03-01 14:37:11 -05:00
commit 82f7ab2ba5
111 changed files with 20416 additions and 176 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
OSMIUM_REPO=https://github.com/osmcode/libosmium.git
OSMIUM_TAG=v2.5.4
OSMIUM_TAG=v2.6.1
VARIANT_REPO=https://github.com/mapbox/variant.git
VARIANT_TAG=v1.0

View File

@ -13,6 +13,22 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
## [2.6.1] - 2016-02-22
### Added
- Add `WITH_PROFILING` option to CMake config. When enabled, this sets the
`-fno-omit-frame-pointer` compiler option.
### Changed
- Massive speed improvements when building multipolygons.
- Uses (and includes) new version 1.3.0 of protozero library.
- Removed dependency on Boost Iterator for PBF writer.
- Example program `osmium_area_test` now uses `cerr` instead of `cout` for
debug output.
## [2.6.0] - 2016-02-04
### Added
@ -260,7 +276,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
Doxygen (up to version 1.8.8). This version contains a workaround to fix
this.
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.6.0...HEAD
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.6.1...HEAD
[2.6.1]: https://github.com/osmcode/libosmium/compare/v2.6.0...v2.6.1
[2.6.0]: https://github.com/osmcode/libosmium/compare/v2.5.4...v2.6.0
[2.5.4]: https://github.com/osmcode/libosmium/compare/v2.5.3...v2.5.4
[2.5.3]: https://github.com/osmcode/libosmium/compare/v2.5.2...v2.5.3

View File

@ -25,7 +25,7 @@ project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 2)
set(LIBOSMIUM_VERSION_MINOR 6)
set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION_PATCH 1)
set(LIBOSMIUM_VERSION
"${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
@ -58,6 +58,8 @@ option(INSTALL_GDALCPP "also install gdalcpp headers" OFF)
option(INSTALL_PROTOZERO "also install protozero headers" OFF)
option(INSTALL_UTFCPP "also install utfcpp headers" OFF)
option(WITH_PROFILING "add flags needed for profiling" OFF)
#-----------------------------------------------------------------------------
#
@ -205,12 +207,17 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}"
CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds."
FORCE)
if(WITH_PROFILING)
add_definitions(-fno-omit-frame-pointer)
endif()
#-----------------------------------------------------------------------------
#
# Build Type
#
#-----------------------------------------------------------------------------
# In 'Dev' mode: compile with very strict warnings and turn them into errors.
if(CMAKE_BUILD_TYPE STREQUAL "Dev")
if(NOT MSVC)

View File

@ -99,13 +99,13 @@ int main(int argc, char* argv[]) {
osmium::area::Assembler::config_type assembler_config;
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
std::cout << "Pass 1...\n";
std::cerr << "Pass 1...\n";
osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation);
collector.read_relations(reader1);
reader1.close();
std::cout << "Pass 1 done\n";
std::cerr << "Pass 1 done\n";
std::cout << "Memory:\n";
std::cerr << "Memory:\n";
collector.used_memory();
index_pos_type index_pos;
@ -113,15 +113,15 @@ int main(int argc, char* argv[]) {
location_handler_type location_handler(index_pos, index_neg);
location_handler.ignore_errors(); // XXX
std::cout << "Pass 2...\n";
std::cerr << "Pass 2...\n";
osmium::io::Reader reader2(infile);
osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
osmium::apply(buffer, handler);
}));
reader2.close();
std::cout << "Pass 2 done\n";
std::cerr << "Pass 2 done\n";
std::cout << "Memory:\n";
std::cerr << "Memory:\n";
collector.used_memory();
std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();

View File

@ -232,7 +232,7 @@ namespace osmium {
if (!ring.closed()) {
open_rings = true;
if (m_config.problem_reporter) {
m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location());
m_config.problem_reporter->report_ring_not_closed(ring.get_node_ref_front().location(), ring.get_node_ref_back().location());
}
}
}
@ -248,14 +248,14 @@ namespace osmium {
* true.
*/
bool possibly_combine_rings_back(ProtoRing& ring) {
const osmium::NodeRef& nr = ring.get_segment_back().second();
const osmium::NodeRef& nr = ring.get_node_ref_back();
if (debug()) {
std::cerr << " possibly_combine_rings_back()\n";
}
for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
if (&*it != &ring && !it->closed()) {
if (has_same_location(nr, it->get_segment_front().first())) {
if (has_same_location(nr, it->get_node_ref_front())) {
if (debug()) {
std::cerr << " ring.last=it->first\n";
}
@ -263,7 +263,7 @@ namespace osmium {
m_rings.erase(it);
return true;
}
if (has_same_location(nr, it->get_segment_back().second())) {
if (has_same_location(nr, it->get_node_ref_back())) {
if (debug()) {
std::cerr << " ring.last=it->last\n";
}
@ -284,14 +284,14 @@ namespace osmium {
* true.
*/
bool possibly_combine_rings_front(ProtoRing& ring) {
const osmium::NodeRef& nr = ring.get_segment_front().first();
const osmium::NodeRef& nr = ring.get_node_ref_front();
if (debug()) {
std::cerr << " possibly_combine_rings_front()\n";
}
for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
if (&*it != &ring && !it->closed()) {
if (has_same_location(nr, it->get_segment_back().second())) {
if (has_same_location(nr, it->get_node_ref_back())) {
if (debug()) {
std::cerr << " ring.first=it->last\n";
}
@ -300,7 +300,7 @@ namespace osmium {
m_rings.erase(it);
return true;
}
if (has_same_location(nr, it->get_segment_front().first())) {
if (has_same_location(nr, it->get_node_ref_front())) {
if (debug()) {
std::cerr << " ring.first=it->first\n";
}
@ -368,7 +368,7 @@ namespace osmium {
}
osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size());
std::copy(ring.segments().begin(), ring.segments().end(), segments.begin());
std::copy(ring.segments().cbegin(), ring.segments().cend(), segments.begin());
std::sort(segments.begin(), segments.end());
const auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) {
return has_same_location(s1.first(), s2.first());
@ -433,14 +433,14 @@ namespace osmium {
}
{
osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder);
ring_builder.add_node_ref(ring->get_segment_front().first());
ring_builder.add_node_ref(ring->get_node_ref_front());
for (const auto& segment : ring->segments()) {
ring_builder.add_node_ref(segment.second());
}
}
for (ProtoRing* inner : ring->inner_rings()) {
osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder);
ring_builder.add_node_ref(inner->get_segment_front().first());
ring_builder.add_node_ref(inner->get_node_ref_front());
for (const auto& segment : inner->segments()) {
ring_builder.add_node_ref(segment.second());
}
@ -459,21 +459,21 @@ namespace osmium {
std::cerr << " => ring CLOSED\n";
}
} else {
if (has_same_location(ring.get_segment_back().second(), segment.first())) {
if (has_same_location(ring.get_node_ref_back(), segment.first())) {
combine_rings_back(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_back().second(), segment.second())) {
if (has_same_location(ring.get_node_ref_back(), segment.second())) {
segment.swap_locations();
combine_rings_back(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_front().first(), segment.first())) {
if (has_same_location(ring.get_node_ref_front(), segment.first())) {
segment.swap_locations();
combine_rings_front(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_front().first(), segment.second())) {
if (has_same_location(ring.get_node_ref_front(), segment.second())) {
combine_rings_front(segment, ring);
return true;
}
@ -696,7 +696,7 @@ namespace osmium {
}
// Now create the Area object and add the attributes and tags
// from the relation.
// from the way.
{
osmium::builder::AreaBuilder builder(out_buffer);
builder.initialize_from_object(way);

View File

@ -118,6 +118,10 @@ namespace osmium {
return m_segments.front();
}
const NodeRef& get_node_ref_front() const {
return get_segment_front().first();
}
const NodeRefSegment& get_segment_back() const {
return m_segments.back();
}
@ -126,6 +130,10 @@ namespace osmium {
return m_segments.back();
}
const NodeRef& get_node_ref_back() const {
return get_segment_back().second();
}
bool closed() const {
return m_segments.front().first().location() == m_segments.back().second().location();
}

View File

@ -58,7 +58,7 @@ namespace osmium {
*/
class SegmentList {
typedef std::vector<NodeRefSegment> slist_type;
using slist_type = std::vector<NodeRefSegment>;
slist_type m_segments;
@ -67,10 +67,11 @@ namespace osmium {
public:
explicit SegmentList(bool debug) noexcept :
m_segments(),
m_debug(debug) {
}
~SegmentList() = default;
~SegmentList() noexcept = default;
SegmentList(const SegmentList&) = delete;
SegmentList(SegmentList&&) = delete;
@ -88,6 +89,15 @@ namespace osmium {
}
typedef slist_type::const_iterator const_iterator;
typedef slist_type::iterator iterator;
iterator begin() noexcept {
return m_segments.begin();
}
iterator end() noexcept {
return m_segments.end();
}
const_iterator begin() const noexcept {
return m_segments.begin();
@ -98,8 +108,8 @@ namespace osmium {
}
/**
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
* Enable or disable debug output to stderr. This is used
* for debugging libosmium itself.
*/
void enable_debug_output(bool debug = true) noexcept {
m_debug = debug;
@ -148,9 +158,9 @@ namespace osmium {
/**
* Find duplicate segments (ie same start and end point) in the
* list and remove them. This will always remove pairs of the same
* segment. So if there are three, for instance, two will be
* removed and one will be left.
* list and remove them. This will always remove pairs of the
* same segment. So if there are three, for instance, two will
* be removed and one will be left.
*/
void erase_duplicate_segments() {
while (true) {
@ -168,7 +178,8 @@ namespace osmium {
/**
* Find intersection between segments.
*
* @param problem_reporter Any intersections found are reported to this object.
* @param problem_reporter Any intersections found are
* reported to this object.
* @returns true if there are intersections.
*/
bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {

View File

@ -44,10 +44,6 @@ DEALINGS IN THE SOFTWARE.
#include <time.h>
#include <utility>
// needed for older boost libraries
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <boost/iterator/transform_iterator.hpp>
#include <protozero/pbf_builder.hpp>
#include <osmium/handler.hpp>
@ -441,22 +437,19 @@ namespace osmium {
template <typename T>
void add_meta(const osmium::OSMObject& object, T& pbf_object) {
const osmium::TagList& tags = object.tags();
{
protozero::packed_field_uint32 field{pbf_object, protozero::pbf_tag_type(T::enum_type::packed_uint32_keys)};
for (const auto& tag : object.tags()) {
field.add_element(m_primitive_block.store_in_stringtable(tag.key()));
}
}
auto map_tag_key = [this](const osmium::Tag& tag) -> uint32_t {
return m_primitive_block.store_in_stringtable(tag.key());
};
auto map_tag_value = [this](const osmium::Tag& tag) -> uint32_t {
return m_primitive_block.store_in_stringtable(tag.value());
};
pbf_object.add_packed_uint32(T::enum_type::packed_uint32_keys,
boost::make_transform_iterator(tags.begin(), map_tag_key),
boost::make_transform_iterator(tags.end(), map_tag_key));
pbf_object.add_packed_uint32(T::enum_type::packed_uint32_vals,
boost::make_transform_iterator(tags.begin(), map_tag_value),
boost::make_transform_iterator(tags.end(), map_tag_value));
{
protozero::packed_field_uint32 field{pbf_object, protozero::pbf_tag_type(T::enum_type::packed_uint32_vals)};
for (const auto& tag : object.tags()) {
field.add_element(m_primitive_block.store_in_stringtable(tag.value()));
}
}
if (m_options.add_metadata) {
protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info);
@ -596,12 +589,12 @@ namespace osmium {
pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id());
add_meta(relation, pbf_relation);
auto map_member_role = [this](const osmium::RelationMember& member) -> uint32_t {
return m_primitive_block.store_in_stringtable(member.role());
};
pbf_relation.add_packed_int32(OSMFormat::Relation::packed_int32_roles_sid,
boost::make_transform_iterator(relation.members().begin(), map_member_role),
boost::make_transform_iterator(relation.members().end(), map_member_role));
{
protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_int32_roles_sid)};
for (const auto& member : relation.members()) {
field.add_element(m_primitive_block.store_in_stringtable(member.role()));
}
}
static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type {
return member->ref();
@ -612,12 +605,12 @@ namespace osmium {
it_type last { members.cend(), members.cend(), map_member_ref };
pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last);
static auto map_member_type = [](const osmium::RelationMember& member) noexcept -> int32_t {
return int32_t(osmium::item_type_to_nwr_index(member.type()));
};
pbf_relation.add_packed_int32(OSMFormat::Relation::packed_MemberType_types,
boost::make_transform_iterator(relation.members().begin(), map_member_type),
boost::make_transform_iterator(relation.members().end(), map_member_type));
{
protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_MemberType_types)};
for (const auto& member : relation.members()) {
field.add_element(int32_t(osmium::item_type_to_nwr_index(member.type())));
}
}
}
}; // class PBFOutputFormat

View File

@ -33,7 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <protozero/pbf_types.hpp>
#include <protozero/types.hpp>
namespace osmium {

View File

@ -49,6 +49,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/types.hpp>
#include <osmium/handler.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/util/iterator.hpp>
#include <osmium/visitor.hpp>
#include <osmium/relations/detail/relation_meta.hpp>
@ -61,6 +62,17 @@ namespace osmium {
*/
namespace relations {
namespace detail {
template <typename R>
inline typename std::iterator_traits<typename R::iterator>::difference_type count_not_removed(const R& range) {
return std::count_if(range.begin(), range.end(), [](MemberMeta& mm) {
return !mm.removed();
});
}
} // namespace detail
/**
* The Collector class collects members of a relation. This is a generic
* base class that can be used to assemble all kinds of relations. It has numerous
@ -175,7 +187,9 @@ namespace osmium {
* One vector each for nodes, ways, and relations containing all
* mappings from member ids to their relations.
*/
std::vector<MemberMeta> m_member_meta[3];
using mm_vector_type = std::vector<MemberMeta>;
using mm_iterator = mm_vector_type::iterator;
mm_vector_type m_member_meta[3];
int m_count_complete = 0;
@ -184,6 +198,11 @@ namespace osmium {
static constexpr size_t initial_buffer_size = 1024 * 1024;
iterator_range<mm_iterator> find_member_meta(osmium::item_type type, osmium::object_id_type id) {
auto& mmv = member_meta(type);
return iterator_range<mm_iterator>{std::equal_range(mmv.begin(), mmv.end(), MemberMeta(id))};
}
public:
/**
@ -367,10 +386,9 @@ namespace osmium {
* relation and false otherwise
*/
bool find_and_add_object(const osmium::OSMObject& object) {
auto& mmv = member_meta(object.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
auto range = find_member_meta(object.type(), object.id());
if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
if (detail::count_not_removed(range) == 0) {
// nothing found
return false;
}
@ -379,13 +397,12 @@ namespace osmium {
members_buffer().add_item(object);
const size_t member_offset = members_buffer().commit();
for (auto it = range.first; it != range.second; ++it) {
it->set_buffer_offset(member_offset);
for (auto& member_meta : range) {
member_meta.set_buffer_offset(member_offset);
}
}
for (auto it = range.first; it != range.second; ++it) {
MemberMeta& member_meta = *it;
for (auto& member_meta : range) {
if (member_meta.removed()) {
break;
}
@ -405,11 +422,6 @@ namespace osmium {
}
}
// Remove MemberMetas that were marked as removed.
mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
return mm.removed();
}), mmv.end());
return true;
}
@ -417,19 +429,18 @@ namespace osmium {
const osmium::Relation& relation = get_relation(relation_meta);
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
auto& mmv = member_meta(member.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(member.ref()));
assert(range.first != range.second);
auto range = find_member_meta(member.type(), member.ref());
assert(!range.empty());
// if this is the last time this object was needed
// then mark it as removed
if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
get_member(range.first->buffer_offset()).set_removed(true);
if (detail::count_not_removed(range) == 1) {
get_member(range.begin()->buffer_offset()).set_removed(true);
}
for (auto it = range.first; it != range.second; ++it) {
if (!it->removed() && relation.id() == get_relation(it->relation_pos()).id()) {
it->remove();
for (auto& member_meta : range) {
if (!member_meta.removed() && relation.id() == get_relation(member_meta.relation_pos()).id()) {
member_meta.remove();
break;
}
}
@ -446,24 +457,24 @@ namespace osmium {
const uint64_t relations_buffer_capacity = m_relations_buffer.capacity();
const uint64_t members_buffer_capacity = m_members_buffer.capacity();
std::cout << " nR = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n";
std::cout << " nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n";
std::cout << " nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n";
std::cout << " nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n";
std::cout << " nM = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n";
std::cerr << " nR = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n";
std::cerr << " nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n";
std::cerr << " nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n";
std::cerr << " nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n";
std::cerr << " nM = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n";
std::cout << " sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n";
std::cout << " sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n";
std::cerr << " sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n";
std::cerr << " sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n";
std::cout << " nR * sRM ............................... = " << std::setw(12) << relations << "\n";
std::cout << " nM * sMM ............................... = " << std::setw(12) << members << "\n";
std::cout << " relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n";
std::cout << " members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n";
std::cerr << " nR * sRM ............................... = " << std::setw(12) << relations << "\n";
std::cerr << " nM * sMM ............................... = " << std::setw(12) << members << "\n";
std::cerr << " relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n";
std::cerr << " members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n";
const uint64_t total = relations + members + relations_buffer_capacity + members_buffer_capacity;
std::cout << " total .................................. = " << std::setw(12) << total << "\n";
std::cout << " =======================================================\n";
std::cerr << " total .................................. = " << std::setw(12) << total << "\n";
std::cerr << " =======================================================\n";
return relations_buffer_capacity + members_buffer_capacity + relations + members;
}
@ -481,10 +492,9 @@ namespace osmium {
}
size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
const auto& mmv = member_meta(type);
const auto range = std::equal_range(mmv.cbegin(), mmv.cend(), MemberMeta(id));
assert(range.first != range.second);
return range.first->buffer_offset();
const auto range = find_member_meta(type, id);
assert(!range.empty());
return range.begin()->buffer_offset();
}
template <typename TIter>
@ -502,11 +512,10 @@ namespace osmium {
void moving_in_buffer(size_t old_offset, size_t new_offset) {
const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset);
auto& mmv = member_meta(object.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
for (auto it = range.first; it != range.second; ++it) {
assert(it->buffer_offset() == old_offset);
it->set_buffer_offset(new_offset);
auto range = find_member_meta(object.type(), object.id());
for (auto& member_meta : range) {
assert(member_meta.buffer_offset() == old_offset);
member_meta.set_buffer_offset(new_offset);
}
}

View File

@ -136,21 +136,6 @@ namespace osmium {
return out;
}
/**
* Count the number of MemberMeta objects in the iterator range
* that are not marked as removed.
*
* @tparam TIter Iterator that dereferences to a MemberMeta
* @param begin Begin of iterator range
* @param end End of iterator range
*/
template <typename TIter>
inline typename std::iterator_traits<TIter>::difference_type count_not_removed(TIter begin, TIter end) {
return std::count_if(begin, end, [](MemberMeta& mm) {
return !mm.removed();
});
}
} // namespace relations
} // namespace osmium

View File

@ -0,0 +1,74 @@
#ifndef OSMIUM_UTIL_ITERATOR_HPP
#define OSMIUM_UTIL_ITERATOR_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <utility>
namespace osmium {
template <typename It, typename P = std::pair<It, It>>
struct iterator_range : public P {
using iterator = It;
iterator_range(P&& p) :
P(std::forward<P>(p)) {
}
It begin() {
return this->first;
}
It end() {
return this->second;
}
It begin() const {
return this->first;
}
It end() const {
return this->second;
}
size_t empty() const {
return begin() == end();
}
};
} // namespace osmium
#endif // OSMIUM_UTIL_ITERATOR_HPP

View File

@ -45,9 +45,9 @@ namespace osmium {
int m_peak = 0;
#ifdef __linux__
int parse_number(const std::string& line) {
int f = line.find_first_of("0123456789");
int l = line.find_last_of("0123456789");
static int parse_number(const std::string& line) {
const auto f = line.find_first_of("0123456789");
const auto l = line.find_last_of("0123456789");
return std::atoi(line.substr(f, l-f+1).c_str());
}
#endif

View File

@ -40,7 +40,9 @@ documentation.
// in this case.
#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
# if !defined(__arm__) && !defined(_M_ARM)
# define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
# ifndef PROTOZERO_DO_NOT_USE_BARE_POINTER
# define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
# endif
# endif
#endif

View File

@ -29,7 +29,7 @@ namespace protozero {
*/
struct exception : std::exception {
/// Returns the explanatory string.
const char *what() const noexcept { return "pbf exception"; }
const char *what() const noexcept override { return "pbf exception"; }
};
/**
@ -38,7 +38,7 @@ struct exception : std::exception {
*/
struct varint_too_long_exception : exception {
/// Returns the explanatory string.
const char *what() const noexcept { return "varint too long exception"; }
const char *what() const noexcept override { return "varint too long exception"; }
};
/**
@ -47,7 +47,7 @@ struct varint_too_long_exception : exception {
*/
struct unknown_pbf_wire_type_exception : exception {
/// Returns the explanatory string.
const char *what() const noexcept { return "unknown pbf field type exception"; }
const char *what() const noexcept override { return "unknown pbf field type exception"; }
};
/**
@ -60,7 +60,7 @@ struct unknown_pbf_wire_type_exception : exception {
*/
struct end_of_buffer_exception : exception {
/// Returns the explanatory string.
const char *what() const noexcept { return "end of buffer exception"; }
const char *what() const noexcept override { return "end of buffer exception"; }
};
} // end namespace protozero

View File

@ -18,7 +18,7 @@ documentation.
#include <type_traits>
#include <protozero/pbf_types.hpp>
#include <protozero/types.hpp>
#include <protozero/pbf_writer.hpp>
namespace protozero {
@ -26,8 +26,10 @@ namespace protozero {
/**
* The pbf_builder is used to write PBF formatted messages into a buffer. It
* is based on the pbf_writer class and has all the same methods. The
* difference is that whereever the pbf_writer class takes an integer tag,
* this template class takes a tag of the template type T.
* difference is that while the pbf_writer class takes an integer tag,
* this template class takes a tag of the template type T. The idea is that
* T will be an enumeration value and this helps reduce the possibility of
* programming errors.
*
* Almost all methods in this class can throw an std::bad_alloc exception if
* the std::string used as a buffer wants to resize.
@ -77,7 +79,7 @@ public:
#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR
/// @endcond
inline void add_bytes(T tag, const char* value, size_t size) {
inline void add_bytes(T tag, const char* value, std::size_t size) {
pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
}
@ -85,7 +87,7 @@ public:
pbf_writer::add_bytes(pbf_tag_type(tag), value);
}
inline void add_string(T tag, const char* value, size_t size) {
inline void add_string(T tag, const char* value, std::size_t size) {
pbf_writer::add_string(pbf_tag_type(tag), value, size);
}
@ -97,7 +99,7 @@ public:
pbf_writer::add_string(pbf_tag_type(tag), value);
}
inline void add_message(T tag, const char* value, size_t size) {
inline void add_message(T tag, const char* value, std::size_t size) {
pbf_writer::add_message(pbf_tag_type(tag), value, size);
}

View File

@ -19,7 +19,7 @@ documentation.
#include <type_traits>
#include <protozero/pbf_reader.hpp>
#include <protozero/pbf_types.hpp>
#include <protozero/types.hpp>
namespace protozero {

View File

@ -25,7 +25,7 @@ documentation.
#include <protozero/config.hpp>
#include <protozero/exception.hpp>
#include <protozero/pbf_types.hpp>
#include <protozero/types.hpp>
#include <protozero/varint.hpp>
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
@ -94,11 +94,12 @@ class pbf_reader {
#ifdef PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
template <typename T>
inline std::pair<const T*, const T*> packed_fixed() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
auto len = get_len_and_skip();
protozero_assert(len % sizeof(T) == 0);
return std::make_pair(reinterpret_cast<const T*>(m_data-len), reinterpret_cast<const T*>(m_data));
using const_fixed_iterator = const T*;
template <typename T>
inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> create_fixed_iterator_pair(const char* first, const char* last) {
return std::make_pair(reinterpret_cast<const T*>(first),
reinterpret_cast<const T*>(last));
}
#else
@ -156,17 +157,22 @@ class pbf_reader {
}; // class const_fixed_iterator
template <typename T>
inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> create_fixed_iterator_pair(const char* first, const char* last) {
return std::make_pair(const_fixed_iterator<T>(first, last),
const_fixed_iterator<T>(last, last));
}
#endif
template <typename T>
inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> packed_fixed() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
auto len = get_len_and_skip();
protozero_assert(len % sizeof(T) == 0);
return std::make_pair(const_fixed_iterator<T>(m_data-len, m_data),
const_fixed_iterator<T>(m_data, m_data));
return create_fixed_iterator_pair<T>(m_data-len, m_data);
}
#endif
template <typename T> inline T get_varint();
template <typename T> inline T get_svarint();
@ -187,7 +193,7 @@ public:
*
* @post There is no current field.
*/
inline pbf_reader(const char *data, size_t length) noexcept;
inline pbf_reader(const char *data, std::size_t length) noexcept;
/**
* Construct a pbf_reader message from a data pointer and a length. The pointer
@ -198,7 +204,7 @@ public:
*
* @post There is no current field.
*/
inline pbf_reader(std::pair<const char *, size_t> data) noexcept;
inline pbf_reader(std::pair<const char *, std::size_t> data) noexcept;
/**
* Construct a pbf_reader message from a std::string. A pointer to the string
@ -247,8 +253,8 @@ public:
* buffer. Of course you have to know reasonably well what data to expect
* and how it is encoded for this number to have any meaning.
*/
size_t length() const noexcept {
return size_t(m_end - m_data);
std::size_t length() const noexcept {
return std::size_t(m_end - m_data);
}
/**
@ -832,14 +838,14 @@ public:
}; // class pbf_reader
pbf_reader::pbf_reader(const char *data, size_t length) noexcept
pbf_reader::pbf_reader(const char *data, std::size_t length) noexcept
: m_data(data),
m_end(data + length),
m_wire_type(pbf_wire_type::unknown),
m_tag(0) {
}
pbf_reader::pbf_reader(std::pair<const char *, size_t> data) noexcept
pbf_reader::pbf_reader(std::pair<const char *, std::size_t> data) noexcept
: m_data(data.first),
m_end(data.first + data.second),
m_wire_type(pbf_wire_type::unknown),
@ -935,7 +941,7 @@ void pbf_reader::skip() {
skip_bytes(4);
break;
default:
throw unknown_pbf_wire_type_exception();
protozero_assert(false && "can not be here because next() should have thrown already");
}
}

View File

@ -24,7 +24,7 @@ documentation.
#include <string>
#include <protozero/config.hpp>
#include <protozero/pbf_types.hpp>
#include <protozero/types.hpp>
#include <protozero/varint.hpp>
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
@ -33,6 +33,14 @@ documentation.
namespace protozero {
namespace detail {
template <typename T> class packed_field_varint;
template <typename T> class packed_field_svarint;
template <typename T> class packed_field_fixed;
} // end namespace detail
/**
* The pbf_writer is used to write PBF formatted messages into a buffer.
*
@ -41,9 +49,24 @@ namespace protozero {
*/
class pbf_writer {
// A pointer to a string buffer holding the data already written to the
// PBF message. For default constructed writers or writers that have been
// rolled back, this is a nullptr.
std::string* m_data;
// A pointer to a parent writer object if this is a submessage. If this
// is a top-level writer, it is a nullptr.
pbf_writer* m_parent_writer;
size_t m_pos = 0;
// This is usually 0. If there is an open submessage, this is set in the
// parent to the rollback position, ie. the last position before the
// submessage was started. This is the position where the header of the
// submessage starts.
std::size_t m_rollback_pos = 0;
// This is usually 0. If there is an open submessage, this is set in the
// parent to the position where the data of the submessage is written to.
std::size_t m_pos = 0;
inline void add_varint(uint64_t value) {
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
@ -94,7 +117,9 @@ class pbf_writer {
return;
}
add_length_varint(tag, sizeof(T) * pbf_length_type(std::distance(first, last)));
auto length = std::distance(first, last);
add_length_varint(tag, sizeof(T) * pbf_length_type(length));
reserve(sizeof(T) * std::size_t(length));
while (first != last) {
add_fixed<T>(*first++);
@ -132,16 +157,37 @@ class pbf_writer {
// and a varint needs 8 bit for every 7 bit.
static const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1;
inline void open_submessage(pbf_tag_type tag) {
// If m_rollpack_pos is set to this special value, it means that when
// the submessage is closed, nothing needs to be done, because the length
// of the submessage has already been written correctly.
static const std::size_t size_is_known = std::numeric_limits<std::size_t>::max();
inline void open_submessage(pbf_tag_type tag, std::size_t size) {
protozero_assert(m_pos == 0);
protozero_assert(m_data);
add_field(tag, pbf_wire_type::length_delimited);
m_data->append(size_t(reserve_bytes), '\0');
if (size == 0) {
m_rollback_pos = m_data->size();
add_field(tag, pbf_wire_type::length_delimited);
m_data->append(std::size_t(reserve_bytes), '\0');
} else {
m_rollback_pos = size_is_known;
add_length_varint(tag, pbf_length_type(size));
reserve(size);
}
m_pos = m_data->size();
}
inline void close_submessage() {
inline void rollback_submessage() {
protozero_assert(m_pos != 0);
protozero_assert(m_rollback_pos != size_is_known);
protozero_assert(m_data);
m_data->resize(m_rollback_pos);
m_pos = 0;
}
inline void commit_submessage() {
protozero_assert(m_pos != 0);
protozero_assert(m_rollback_pos != size_is_known);
protozero_assert(m_data);
auto length = pbf_length_type(m_data->size() - m_pos);
@ -152,6 +198,18 @@ class pbf_writer {
m_pos = 0;
}
inline void close_submessage() {
protozero_assert(m_data);
if (m_pos == 0 || m_rollback_pos == size_is_known) {
return;
}
if (m_data->size() - m_pos == 0) {
rollback_submessage();
} else {
commit_submessage();
}
}
inline void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
add_field(tag, pbf_wire_type::length_delimited);
add_varint(length);
@ -161,7 +219,8 @@ public:
/**
* Create a writer using the given string as a data store. The pbf_writer
* stores a reference to that string and adds all data to it.
* stores a reference to that string and adds all data to it. The string
* doesn't have to be empty. The pbf_writer will just append data.
*/
inline explicit pbf_writer(std::string& data) noexcept :
m_data(&data),
@ -185,12 +244,15 @@ public:
*
* @param parent_writer The pbf_writer
* @param tag Tag (field number) of the field that will be written
* @param size Optional size of the submessage in bytes (use 0 for unknown).
* Setting this allows some optimizations but is only possible in
* a few very specific cases.
*/
inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag) :
inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) :
m_data(parent_writer.m_data),
m_parent_writer(&parent_writer),
m_pos(0) {
m_parent_writer->open_submessage(tag);
m_parent_writer->open_submessage(tag, size);
}
/// A pbf_writer object can be copied
@ -211,6 +273,26 @@ public:
}
}
/**
* Reserve size bytes in the underlying message store in addition to
* whatever the message store already holds. So unlike
* the `std::string::reserve()` method this is not an absolute size,
* but additional memory that should be reserved.
*
* @param size Number of bytes to reserve in underlying message store.
*/
void reserve(std::size_t size) {
protozero_assert(m_data);
m_data->reserve(m_data->size() + size);
}
inline void rollback() {
protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent");
protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage");
m_parent_writer->rollback_submessage();
m_data = nullptr;
}
///@{
/**
* @name Scalar field writer functions
@ -372,7 +454,7 @@ public:
* @param value Pointer to value to be written
* @param size Number of bytes to be written
*/
inline void add_bytes(pbf_tag_type tag, const char* value, size_t size) {
inline void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) {
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
protozero_assert(m_data);
protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
@ -397,7 +479,7 @@ public:
* @param value Pointer to value to be written
* @param size Number of bytes to be written
*/
inline void add_string(pbf_tag_type tag, const char* value, size_t size) {
inline void add_string(pbf_tag_type tag, const char* value, std::size_t size) {
add_bytes(tag, value, size);
}
@ -429,7 +511,7 @@ public:
* @param value Pointer to message to be written
* @param size Length of the message
*/
inline void add_message(pbf_tag_type tag, const char* value, size_t size) {
inline void add_message(pbf_tag_type tag, const char* value, std::size_t size) {
add_bytes(tag, value, size);
}
@ -654,8 +736,102 @@ public:
///@}
template <typename T> friend class detail::packed_field_varint;
template <typename T> friend class detail::packed_field_svarint;
template <typename T> friend class detail::packed_field_fixed;
}; // class pbf_writer
namespace detail {
class packed_field {
protected:
pbf_writer m_writer;
public:
packed_field(pbf_writer& parent_writer, pbf_tag_type tag) :
m_writer(parent_writer, tag) {
}
packed_field(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) :
m_writer(parent_writer, tag, size) {
}
void rollback() {
m_writer.rollback();
}
}; // class packed_field
template <typename T>
class packed_field_fixed : public packed_field {
public:
packed_field_fixed(pbf_writer& parent_writer, pbf_tag_type tag) :
packed_field(parent_writer, tag) {
}
packed_field_fixed(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) :
packed_field(parent_writer, tag, size * sizeof(T)) {
}
void add_element(T value) {
m_writer.add_fixed<T>(value);
}
}; // class packed_field_fixed
template <typename T>
class packed_field_varint : public packed_field {
public:
packed_field_varint(pbf_writer& parent_writer, pbf_tag_type tag) :
packed_field(parent_writer, tag) {
}
void add_element(T value) {
m_writer.add_varint(uint64_t(value));
}
}; // class packed_field_varint
template <typename T>
class packed_field_svarint : public packed_field {
public:
packed_field_svarint(pbf_writer& parent_writer, pbf_tag_type tag) :
packed_field(parent_writer, tag) {
}
void add_element(T value) {
m_writer.add_varint(encode_zigzag64(value));
}
}; // class packed_field_svarint
} // end namespace detail
using packed_field_bool = detail::packed_field_varint<bool>;
using packed_field_enum = detail::packed_field_varint<int32_t>;
using packed_field_int32 = detail::packed_field_varint<int32_t>;
using packed_field_sint32 = detail::packed_field_svarint<int32_t>;
using packed_field_uint32 = detail::packed_field_varint<uint32_t>;
using packed_field_int64 = detail::packed_field_varint<int64_t>;
using packed_field_sint64 = detail::packed_field_svarint<int64_t>;
using packed_field_uint64 = detail::packed_field_varint<uint64_t>;
using packed_field_fixed32 = detail::packed_field_fixed<uint32_t>;
using packed_field_sfixed32 = detail::packed_field_fixed<int32_t>;
using packed_field_fixed64 = detail::packed_field_fixed<uint64_t>;
using packed_field_sfixed64 = detail::packed_field_fixed<int64_t>;
using packed_field_float = detail::packed_field_fixed<float>;
using packed_field_double = detail::packed_field_fixed<double>;
} // end namespace protozero
#endif // PROTOZERO_PBF_WRITER_HPP

View File

@ -1,5 +1,5 @@
#ifndef PROTOZERO_PBF_TYPES_HPP
#define PROTOZERO_PBF_TYPES_HPP
#ifndef PROTOZERO_TYPES_HPP
#define PROTOZERO_TYPES_HPP
/*****************************************************************************
@ -11,7 +11,7 @@ documentation.
*****************************************************************************/
/**
* @file pbf_types.hpp
* @file types.hpp
*
* @brief Contains the declaration of low-level types used in the pbf format.
*/
@ -46,4 +46,4 @@ namespace protozero {
} // end namespace protozero
#endif // PROTOZERO_PBF_TYPES_HPP
#endif // PROTOZERO_TYPES_HPP

View File

@ -25,13 +25,13 @@ namespace protozero {
/**
* The maximum length of a 64bit varint.
*/
const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
// from https://github.com/facebook/folly/blob/master/folly/Varint.h
/**
* Decode a 64bit varint.
*
* String exception guarantee: if there is an exception the data pointer will
* Strong exception guarantee: if there is an exception the data pointer will
* not be changed.
*
* @param[in,out] data Pointer to pointer to the input data. After the function

View File

@ -11,12 +11,12 @@ documentation.
*****************************************************************************/
#define PROTOZERO_VERSION_MAJOR 1
#define PROTOZERO_VERSION_MINOR 2
#define PROTOZERO_VERSION_PATCH 3
#define PROTOZERO_VERSION_MINOR 3
#define PROTOZERO_VERSION_PATCH 0
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
#define PROTOZERO_VERSION_STRING "1.2.3"
#define PROTOZERO_VERSION_STRING "1.3.0"
#endif // PROTOZERO_VERSION_HPP

View File

@ -0,0 +1,188 @@
#-----------------------------------------------------------------------------
#
# CMake Config
#
# Libosmium unit tests
#
#-----------------------------------------------------------------------------
message(STATUS "Configuring unit tests")
include(CMakeParseArguments)
include_directories(include)
add_library(testlib STATIC test_main.cpp)
set(ALL_TESTS "")
# Otherwise GCC throws a lot of warnings for REQUIRE(...) from Catch v.1.2.1
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-Wno-parentheses)
endif()
#-----------------------------------------------------------------------------
#
# Define function for adding tests
#
# add_unit_tests(group name [ENABLE_IF bool] [LIBS libs] [LABELS labels])
#
# group - test group (directory)
# name - name of test
# bool - boolean variable telling whether the test should be run (optional)
# libs - lib or libs that should be used when compiling test (optional)
# labels - additional labels this test should get (optional)
#
#-----------------------------------------------------------------------------
function(add_unit_test _tgroup _tname)
set(_testid "${_tgroup}_${_tname}")
set(_tpath "${_tgroup}/${_tname}")
set(ALL_TESTS "${ALL_TESTS};${_tpath}" PARENT_SCOPE)
cmake_parse_arguments(_param "" "ENABLE_IF" "LIBS;LABELS" ${ARGN})
if(Osmium_DEBUG)
message("${_testid} ENABLE_IF=[${_param_ENABLE_IF}] LIBS=[${_param_LIBS}] LABELS=[${_param_LABELS}]")
endif()
if((NOT(DEFINED _param_ENABLE_IF)) OR (_param_ENABLE_IF))
if(Osmium_DEBUG)
message("Adding test: ${_tpath}")
endif()
add_executable(${_testid} t/${_tpath}.cpp)
target_link_libraries(${_testid} testlib)
if(DEFINED _param_LIBS)
if(Osmium_DEBUG)
message(" Adding libs: ${_param_LIBS}")
endif()
target_link_libraries(${_testid} ${_param_LIBS})
endif()
add_test(NAME ${_testid}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${_testid}
)
set(_labels "unit;fast;${_tgroup}")
if(DEFINED _param_LABELS)
if(Osmium_DEBUG)
message(" Adding labels: ${_param_LABELS}")
endif()
set(_labels "${_labels};${_param_LABELS}")
endif()
set_tests_properties(${_testid} PROPERTIES
LABELS "${_labels}"
ENVIRONMENT "OSMIUM_TEST_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
)
else()
message("Skipped test ${_tpath} because a dependency was not found")
set(OSMIUM_SKIPPED_TESTS
"${OSMIUM_SKIPPED_TESTS} ${_tpath}"
CACHE STRING "Tests that were skipped because of missing dependecies")
endif()
endfunction()
#-----------------------------------------------------------------------------
#
# Add all tests.
#
#-----------------------------------------------------------------------------
add_unit_test(area test_area_id)
add_unit_test(area test_node_ref_segment)
add_unit_test(basic test_box)
add_unit_test(basic test_changeset)
add_unit_test(basic test_crc)
add_unit_test(basic test_entity_bits)
add_unit_test(basic test_location)
add_unit_test(basic test_node)
add_unit_test(basic test_node_ref)
add_unit_test(basic test_object_comparisons)
add_unit_test(basic test_relation)
add_unit_test(basic test_timestamp)
add_unit_test(basic test_types_from_string)
add_unit_test(basic test_way)
add_unit_test(buffer test_buffer_basics)
add_unit_test(buffer test_buffer_node)
add_unit_test(buffer test_buffer_purge)
add_unit_test(builder test_attr)
if(GEOS_FOUND AND PROJ_FOUND)
set(GEOS_AND_PROJ_FOUND TRUE)
else()
set(GEOS_AND_PROJ_FOUND FALSE)
endif()
add_unit_test(geom test_factory_with_projection
ENABLE_IF ${GEOS_AND_PROJ_FOUND}
LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
add_unit_test(geom test_crs ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_exception)
add_unit_test(geom test_geojson)
add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
add_unit_test(geom test_geos_wkb ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
add_unit_test(geom test_mercator)
add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
add_unit_test(geom test_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_tile)
add_unit_test(geom test_wkb)
add_unit_test(geom test_wkt)
add_unit_test(index test_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
add_unit_test(io test_file_formats)
add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}")
add_unit_test(io test_reader_with_mock_decompression ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(io test_reader_with_mock_parser ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(io test_output_utils)
add_unit_test(io test_output_iterator ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(io test_string_table)
add_unit_test(io test_writer ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(io test_writer_with_mock_compression ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(io test_writer_with_mock_encoder ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(tags test_filter)
add_unit_test(tags test_operators)
add_unit_test(tags test_tag_list)
add_unit_test(thread test_pool ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(util test_cast_with_assert)
add_unit_test(util test_delta)
add_unit_test(util test_double)
add_unit_test(util test_file)
add_unit_test(util test_memory)
add_unit_test(util test_memory_mapping)
add_unit_test(util test_minmax)
add_unit_test(util test_options)
add_unit_test(util test_string)
#-----------------------------------------------------------------------------
#
# Check that all tests available in test/t/*/test_*.cpp are run.
#
#-----------------------------------------------------------------------------
file(GLOB TESTS_IN_DIR RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/t" t/*/test_*.cpp)
foreach(file ${TESTS_IN_DIR})
string(REPLACE ".cpp" "" out1 ${file})
string(REPLACE "//" "/" tname ${out1})
list(FIND ALL_TESTS ${tname} found)
if(${found} EQUAL -1)
message(WARNING "Test '${tname}' not found in cmake config. It will not be run!")
endif()
endforeach()
#-----------------------------------------------------------------------------
message(STATUS "Configuring unit tests - done")
#-----------------------------------------------------------------------------

13
third_party/libosmium/test/README vendored Normal file
View File

@ -0,0 +1,13 @@
Osmium uses Catch (https://github.com/philsquared/Catch/) for its unit tests.
Only one header file is needed (catch.hpp) which can be downloaded from
http://builds.catch-lib.net/ and put into the include directory.
Osmium needs a few changes to catch.hpp, they were patched in. To be able to
compare with the original version, it is stored in include/catch_orig.hpp.
Changes are:
* Disable more warnings in GCC
* CATCH_CONFIG_CPP11_NULLPTR must be set for MSVC
* Problem with test running in loop: https://github.com/philsquared/Catch/issues/271

View File

@ -0,0 +1 @@
multipolygon.qgs~

View File

@ -0,0 +1,118 @@
#-----------------------------------------------------------------------------
#
# CMake Config
#
# Libosmium data tests
#
#-----------------------------------------------------------------------------
message(STATUS "Configuring data tests")
if(NOT GDAL_FOUND OR NOT EXPAT_FOUND)
message(STATUS "Sorry, building data tests needs GDAL and Expat")
message(STATUS "Configuring data tests - failed")
return()
endif()
message(STATUS "Looking for osm-testdata")
find_path(OSM_TESTDATA grid/data/all.osm HINT ../../../osm-testdata)
if(OSM_TESTDATA STREQUAL "OSM_TESTDATA-NOTFOUND")
message(STATUS "Looking for osm-testdata - not found (data tests disabled)")
message(STATUS "Configuring data tests - failed")
return()
endif()
message(STATUS "Looking for osm-testdata - found")
#-----------------------------------------------------------------------------
include_directories("include")
include_directories("../include")
#-----------------------------------------------------------------------------
#
# testcases
#
#-----------------------------------------------------------------------------
file(GLOB TESTCASE_CPPS testcases/*.cpp)
add_executable(testdata-testcases testdata-testcases.cpp ${TESTCASE_CPPS})
target_link_libraries(testdata-testcases
${OSMIUM_XML_LIBRARIES}
)
add_test(NAME testdata-testcases
COMMAND testdata-testcases
)
set_tests_properties(testdata-testcases PROPERTIES
ENVIRONMENT "TESTCASES_DIR=${OSM_TESTDATA}/grid/data"
LABELS "data;fast")
#-----------------------------------------------------------------------------
#
# xml
#
#-----------------------------------------------------------------------------
add_executable(testdata-xml testdata-xml.cpp)
target_link_libraries(testdata-xml
${OSMIUM_XML_LIBRARIES}
)
add_test(NAME testdata-xml
COMMAND testdata-xml
)
set_tests_properties(testdata-xml PROPERTIES
ENVIRONMENT "TESTDIR=${OSM_TESTDATA}/xml/data"
LABELS "data;fast")
#-----------------------------------------------------------------------------
#
# overview
#
#-----------------------------------------------------------------------------
add_executable(testdata-overview testdata-overview.cpp)
target_link_libraries(testdata-overview
${OSMIUM_XML_LIBRARIES}
${GDAL_LIBRARIES}
)
add_test(NAME testdata-overview
COMMAND testdata-overview ${OSM_TESTDATA}/grid/data/all.osm
)
set_tests_properties(testdata-overview PROPERTIES
LABELS "data;slow")
#-----------------------------------------------------------------------------
#
# multipolygon
#
#-----------------------------------------------------------------------------
find_program(RUBY ruby)
find_package(Gem COMPONENTS json)
find_program(SPATIALITE spatialite)
if(RUBY AND GEM_json_FOUND AND SPATIALITE)
add_executable(testdata-multipolygon testdata-multipolygon.cpp)
target_link_libraries(testdata-multipolygon
${OSMIUM_XML_LIBRARIES}
${GDAL_LIBRARIES}
)
add_test(NAME testdata-multipolygon
COMMAND ${CMAKE_COMMAND}
-D OSM_TESTDATA=${OSM_TESTDATA}
-D RUBY=${RUBY}
-P ${CMAKE_CURRENT_SOURCE_DIR}/run-testdata-multipolygon.cmake)
set_tests_properties(testdata-multipolygon PROPERTIES LABELS "data;slow")
else()
message(WARNING "Disabled testdata-multipolygon test because 'ruby' and/or 'json' ruby gem and/or 'spatialite' was not found")
endif()
#-----------------------------------------------------------------------------
message(STATUS "Configuring data tests - done")
#-----------------------------------------------------------------------------

View File

@ -0,0 +1,10 @@
# OSM Testdata
This directory contains software that can be used with the osm-testdata
repository at https://github.com/osmcode/osm-testdata . To use it, clone
the `osm-testdata` repository in the same directory where you cloned the
`libosmium` repository.
Tests will be built if the CMake option `BUILD_DATA_TESTS` is set and run as
part of the `ctest` run.

View File

@ -0,0 +1,92 @@
#ifndef CHECK_BASICS_HANDLER_HPP
#define CHECK_BASICS_HANDLER_HPP
#include <iostream>
#include <unordered_set>
#include <osmium/handler.hpp>
#include <osmium/osm.hpp>
/**
* Check some basics of the input data:
*
* 1. Correct number of nodes, ways, and relations
* 2. Correct ID space used by nodes, ways, and relations
* 3. No ID used more than once
*/
class CheckBasicsHandler : public osmium::handler::Handler {
// Lower bound for the id range allowed in this test.
int m_id_range;
// In the beginning these contains the number of nodes, ways, and relations
// supposedly in the data.osm file. They will be decremented on each object
// and have to be 0 at the end.
int m_num_nodes;
int m_num_ways;
int m_num_relations;
// All IDs encountered in the data.osm file will be stored in this set and
// checked for duplicates.
std::unordered_set<osmium::object_id_type> m_ids;
// Check id is in range [min, max] and that it isn't more than once in input.
void id_check(osmium::object_id_type id, osmium::object_id_type min, osmium::object_id_type max) {
if (id < m_id_range + min || id > m_id_range + max) {
std::cerr << " id " << id << " out of range for this test case\n";
exit(1);
}
auto r = m_ids.insert(id);
if (!r.second) {
std::cerr << " id " << id << " contained twice in data.osm\n";
exit(1);
}
}
public:
static const int ids_per_testcase = 1000;
CheckBasicsHandler(int testcase, int nodes, int ways, int relations) :
osmium::handler::Handler(),
m_id_range(testcase * ids_per_testcase),
m_num_nodes(nodes),
m_num_ways(ways),
m_num_relations(relations) {
}
~CheckBasicsHandler() {
if (m_num_nodes != 0) {
std::cerr << " wrong number of nodes in data.osm\n";
exit(1);
}
if (m_num_ways != 0) {
std::cerr << " wrong number of ways in data.osm\n";
exit(1);
}
if (m_num_relations != 0) {
std::cerr << " wrong number of relations in data.osm\n";
exit(1);
}
}
void node(const osmium::Node& node) {
id_check(node.id(), 0, 799);
--m_num_nodes;
}
void way(const osmium::Way& way) {
id_check(way.id(), 800, 899);
--m_num_ways;
}
void relations(const osmium::Relation& relation) {
id_check(relation.id(), 900, 999);
--m_num_relations;
}
}; // CheckBasicsHandler
#endif // CHECK_BASICS_HANDLER_HPP

View File

@ -0,0 +1,86 @@
#ifndef CHECK_WKT_HANDLER_HPP
#define CHECK_WKT_HANDLER_HPP
#include <cassert>
#include <fstream>
#include <map>
#include <sstream>
#include <string>
#include <osmium/handler.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/types.hpp>
class CheckWKTHandler : public osmium::handler::Handler {
std::map<osmium::object_id_type, std::string> m_geometries;
osmium::geom::WKTFactory<> m_factory;
void read_wkt_file(const std::string& filename) {
std::ifstream in(filename, std::ifstream::in);
if (in) {
osmium::object_id_type id;
std::string line;
while (std::getline(in, line)) {
size_t pos = line.find_first_of(' ');
if (pos == std::string::npos) {
std::cerr << filename << " not formatted correctly\n";
exit(1);
}
std::string id_str = line.substr(0, pos);
std::istringstream iss(id_str);
iss >> id;
if (m_geometries.find(id) != m_geometries.end()) {
std::cerr << filename + " contains id " << id << "twice\n";
exit(1);
}
m_geometries[id] = line.substr(pos+1);
}
}
}
public:
CheckWKTHandler(const std::string& dirname, int test_id) :
osmium::handler::Handler() {
std::string filename = dirname + "/" + std::to_string(test_id / 100) + "/" + std::to_string(test_id) + "/";
read_wkt_file(filename + "nodes.wkt");
read_wkt_file(filename + "ways.wkt");
}
~CheckWKTHandler() {
if (!m_geometries.empty()) {
for (const auto& geom : m_geometries) {
std::cerr << "geometry id " << geom.first << " not in data.osm.\n";
}
exit(1);
}
}
void node(const osmium::Node& node) {
const std::string wkt = m_geometries[node.id()];
assert(wkt != "" && "Missing geometry for node in nodes.wkt");
std::string this_wkt = m_factory.create_point(node.location());
assert(wkt == this_wkt && "wkt geometries don't match");
m_geometries.erase(node.id());
}
void way(const osmium::Way& way) {
const std::string wkt = m_geometries[way.id()];
assert(wkt != "" && "Missing geometry for way in ways.wkt");
std::string this_wkt = m_factory.create_linestring(way);
assert(wkt == this_wkt && "wkt geometries don't match");
m_geometries.erase(way.id());
}
}; // CheckWKTHandler
#endif // CHECK_WKT_HANDLER_HPP

View File

@ -0,0 +1,22 @@
#ifndef COMMON_HPP
#define COMMON_HPP
#include <osmium/index/map/dummy.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/geom/wkt.hpp>
#include <osmium/handler.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
#include "check_basics_handler.hpp"
#include "check_wkt_handler.hpp"
#include "testdata-testcases.hpp"
#endif // COMMON_HPP

View File

@ -0,0 +1,10 @@
#ifndef TESTDATA_TESTCASES_HPP
#define TESTDATA_TESTCASES_HPP
#include <catch.hpp>
#include <string>
extern std::string dirname;
#endif // TESTDATA_TESTCASES_HPP

View File

@ -0,0 +1,880 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis projectname="" version="2.2.0-Valmiera">
<title></title>
<relations/>
<mapcanvas>
<units>degrees</units>
<extent>
<xmin>0.77500024999999972</xmin>
<ymin>-0.84791712574962541</ymin>
<xmax>10.22498975000000065</xmax>
<ymax>3.94791712574962572</ymax>
</extent>
<projections>0</projections>
<destinationsrs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</destinationsrs>
<layer_coordinate_transform_info/>
</mapcanvas>
<legend updateDrawingOrder="true">
<legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="Error Points" showFeatureCount="0">
<filegroup open="true" hidden="false">
<legendlayerfile isInOverview="0" layerid="perrors20140228163658956" visible="1"/>
</filegroup>
</legendlayer>
<legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="Error Lines" showFeatureCount="0">
<filegroup open="true" hidden="false">
<legendlayerfile isInOverview="0" layerid="lerrors20140228172357933" visible="1"/>
</filegroup>
</legendlayer>
<legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="multipolygons" showFeatureCount="0">
<filegroup open="true" hidden="false">
<legendlayerfile isInOverview="0" layerid="multipolygons20140221151811742" visible="1"/>
</filegroup>
</legendlayer>
<legendgroup embedded="1" drawingOrder="-1" open="true" checked="Qt::Checked" name="Overview" project="../../../osm-testdata/grid/tests.qgs"/>
<legendgroup embedded="1" drawingOrder="-1" open="true" checked="Qt::Checked" name="Test Framework" project="../../../osm-testdata/grid/tests.qgs"/>
</legend>
<projectlayers layercount="9">
<maplayer minimumScale="-4.65661e-10" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Line" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
<id>lerrors20140228172357933</id>
<datasource>dbname='./multipolygon.db' table="lerrors" (GEOMETRY) sql=</datasource>
<title></title>
<abstract></abstract>
<keywordList>
<value></value>
</keywordList>
<layername>Error Lines</layername>
<srs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<provider encoding="System">spatialite</provider>
<previewExpression>COALESCE( "OGC_FID", '&lt;NULL>' )</previewExpression>
<vectorjoins/>
<renderer-v2 attr="problem_type" symbollevels="0" type="categorizedSymbol">
<categories>
<category symbol="0" value="intersection" label="intersection"/>
<category symbol="1" value="role_should_be_outer" label="role_should_be_outer"/>
<category symbol="2" value="role_should_be_inner" label="role_should_be_inner"/>
<category symbol="3" value="" label=""/>
</categories>
<symbols>
<symbol alpha="1" type="line" name="0">
<layer pass="0" class="SimpleLine" locked="0">
<prop k="capstyle" v="square"/>
<prop k="color" v="255,0,0,255"/>
<prop k="customdash" v="5;2"/>
<prop k="customdash_unit" v="MM"/>
<prop k="draw_inside_polygon" v="0"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0"/>
<prop k="offset_unit" v="MM"/>
<prop k="penstyle" v="solid"/>
<prop k="use_custom_dash" v="0"/>
<prop k="width" v="0.5"/>
<prop k="width_unit" v="MM"/>
</layer>
</symbol>
<symbol alpha="1" type="line" name="1">
<layer pass="0" class="SimpleLine" locked="0">
<prop k="capstyle" v="square"/>
<prop k="color" v="255,122,33,255"/>
<prop k="customdash" v="5;2"/>
<prop k="customdash_unit" v="MM"/>
<prop k="draw_inside_polygon" v="0"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0"/>
<prop k="offset_unit" v="MM"/>
<prop k="penstyle" v="solid"/>
<prop k="use_custom_dash" v="0"/>
<prop k="width" v="0.5"/>
<prop k="width_unit" v="MM"/>
</layer>
</symbol>
<symbol alpha="1" type="line" name="2">
<layer pass="0" class="SimpleLine" locked="0">
<prop k="capstyle" v="square"/>
<prop k="color" v="255,122,33,255"/>
<prop k="customdash" v="5;2"/>
<prop k="customdash_unit" v="MM"/>
<prop k="draw_inside_polygon" v="0"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0"/>
<prop k="offset_unit" v="MM"/>
<prop k="penstyle" v="dash"/>
<prop k="use_custom_dash" v="0"/>
<prop k="width" v="0.5"/>
<prop k="width_unit" v="MM"/>
</layer>
</symbol>
<symbol alpha="1" type="line" name="3">
<layer pass="0" class="SimpleLine" locked="0">
<prop k="capstyle" v="square"/>
<prop k="color" v="255,0,0,255"/>
<prop k="customdash" v="5;2"/>
<prop k="customdash_unit" v="MM"/>
<prop k="draw_inside_polygon" v="0"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0"/>
<prop k="offset_unit" v="MM"/>
<prop k="penstyle" v="solid"/>
<prop k="use_custom_dash" v="0"/>
<prop k="width" v="0.5"/>
<prop k="width_unit" v="MM"/>
</layer>
</symbol>
</symbols>
<source-symbol>
<symbol alpha="1" type="line" name="0">
<layer pass="0" class="SimpleLine" locked="0">
<prop k="capstyle" v="square"/>
<prop k="color" v="77,243,51,255"/>
<prop k="customdash" v="5;2"/>
<prop k="customdash_unit" v="MM"/>
<prop k="draw_inside_polygon" v="0"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0"/>
<prop k="offset_unit" v="MM"/>
<prop k="penstyle" v="solid"/>
<prop k="use_custom_dash" v="0"/>
<prop k="width" v="0.26"/>
<prop k="width_unit" v="MM"/>
</layer>
</symbol>
</source-symbol>
<rotation/>
<sizescale scalemethod="area"/>
</renderer-v2>
<customproperties>
<property key="labeling" value="pal"/>
<property key="labeling/addDirectionSymbol" value="false"/>
<property key="labeling/angleOffset" value="0"/>
<property key="labeling/blendMode" value="0"/>
<property key="labeling/bufferBlendMode" value="0"/>
<property key="labeling/bufferColorA" value="255"/>
<property key="labeling/bufferColorB" value="255"/>
<property key="labeling/bufferColorG" value="255"/>
<property key="labeling/bufferColorR" value="255"/>
<property key="labeling/bufferDraw" value="false"/>
<property key="labeling/bufferJoinStyle" value="64"/>
<property key="labeling/bufferNoFill" value="false"/>
<property key="labeling/bufferSize" value="1"/>
<property key="labeling/bufferSizeInMapUnits" value="false"/>
<property key="labeling/bufferTransp" value="0"/>
<property key="labeling/centroidWhole" value="false"/>
<property key="labeling/decimals" value="3"/>
<property key="labeling/displayAll" value="false"/>
<property key="labeling/dist" value="0"/>
<property key="labeling/distInMapUnits" value="false"/>
<property key="labeling/enabled" value="false"/>
<property key="labeling/fieldName" value=""/>
<property key="labeling/fontBold" value="false"/>
<property key="labeling/fontCapitals" value="0"/>
<property key="labeling/fontFamily" value="Sans"/>
<property key="labeling/fontItalic" value="false"/>
<property key="labeling/fontLetterSpacing" value="0"/>
<property key="labeling/fontLimitPixelSize" value="false"/>
<property key="labeling/fontMaxPixelSize" value="10000"/>
<property key="labeling/fontMinPixelSize" value="3"/>
<property key="labeling/fontSize" value="10"/>
<property key="labeling/fontSizeInMapUnits" value="false"/>
<property key="labeling/fontStrikeout" value="false"/>
<property key="labeling/fontUnderline" value="false"/>
<property key="labeling/fontWeight" value="50"/>
<property key="labeling/fontWordSpacing" value="0"/>
<property key="labeling/formatNumbers" value="false"/>
<property key="labeling/isExpression" value="false"/>
<property key="labeling/labelOffsetInMapUnits" value="true"/>
<property key="labeling/labelPerPart" value="false"/>
<property key="labeling/leftDirectionSymbol" value="&lt;"/>
<property key="labeling/limitNumLabels" value="false"/>
<property key="labeling/maxCurvedCharAngleIn" value="20"/>
<property key="labeling/maxCurvedCharAngleOut" value="-20"/>
<property key="labeling/maxNumLabels" value="2000"/>
<property key="labeling/mergeLines" value="false"/>
<property key="labeling/minFeatureSize" value="0"/>
<property key="labeling/multilineAlign" value="0"/>
<property key="labeling/multilineHeight" value="1"/>
<property key="labeling/namedStyle" value=""/>
<property key="labeling/obstacle" value="true"/>
<property key="labeling/placeDirectionSymbol" value="0"/>
<property key="labeling/placement" value="2"/>
<property key="labeling/placementFlags" value="10"/>
<property key="labeling/plussign" value="false"/>
<property key="labeling/preserveRotation" value="true"/>
<property key="labeling/previewBkgrdColor" value="#ffffff"/>
<property key="labeling/priority" value="5"/>
<property key="labeling/quadOffset" value="4"/>
<property key="labeling/reverseDirectionSymbol" value="false"/>
<property key="labeling/rightDirectionSymbol" value=">"/>
<property key="labeling/scaleMax" value="10000000"/>
<property key="labeling/scaleMin" value="1"/>
<property key="labeling/scaleVisibility" value="false"/>
<property key="labeling/shadowBlendMode" value="6"/>
<property key="labeling/shadowColorB" value="0"/>
<property key="labeling/shadowColorG" value="0"/>
<property key="labeling/shadowColorR" value="0"/>
<property key="labeling/shadowDraw" value="false"/>
<property key="labeling/shadowOffsetAngle" value="135"/>
<property key="labeling/shadowOffsetDist" value="1"/>
<property key="labeling/shadowOffsetGlobal" value="true"/>
<property key="labeling/shadowOffsetUnits" value="1"/>
<property key="labeling/shadowRadius" value="1.5"/>
<property key="labeling/shadowRadiusAlphaOnly" value="false"/>
<property key="labeling/shadowRadiusUnits" value="1"/>
<property key="labeling/shadowScale" value="100"/>
<property key="labeling/shadowTransparency" value="30"/>
<property key="labeling/shadowUnder" value="0"/>
<property key="labeling/shapeBlendMode" value="0"/>
<property key="labeling/shapeBorderColorA" value="255"/>
<property key="labeling/shapeBorderColorB" value="128"/>
<property key="labeling/shapeBorderColorG" value="128"/>
<property key="labeling/shapeBorderColorR" value="128"/>
<property key="labeling/shapeBorderWidth" value="0"/>
<property key="labeling/shapeBorderWidthUnits" value="1"/>
<property key="labeling/shapeDraw" value="false"/>
<property key="labeling/shapeFillColorA" value="255"/>
<property key="labeling/shapeFillColorB" value="255"/>
<property key="labeling/shapeFillColorG" value="255"/>
<property key="labeling/shapeFillColorR" value="255"/>
<property key="labeling/shapeJoinStyle" value="64"/>
<property key="labeling/shapeOffsetUnits" value="1"/>
<property key="labeling/shapeOffsetX" value="0"/>
<property key="labeling/shapeOffsetY" value="0"/>
<property key="labeling/shapeRadiiUnits" value="1"/>
<property key="labeling/shapeRadiiX" value="0"/>
<property key="labeling/shapeRadiiY" value="0"/>
<property key="labeling/shapeRotation" value="0"/>
<property key="labeling/shapeRotationType" value="0"/>
<property key="labeling/shapeSVGFile" value=""/>
<property key="labeling/shapeSizeType" value="0"/>
<property key="labeling/shapeSizeUnits" value="1"/>
<property key="labeling/shapeSizeX" value="0"/>
<property key="labeling/shapeSizeY" value="0"/>
<property key="labeling/shapeTransparency" value="0"/>
<property key="labeling/shapeType" value="0"/>
<property key="labeling/textColorA" value="255"/>
<property key="labeling/textColorB" value="0"/>
<property key="labeling/textColorG" value="0"/>
<property key="labeling/textColorR" value="0"/>
<property key="labeling/textTransp" value="0"/>
<property key="labeling/upsidedownLabels" value="0"/>
<property key="labeling/wrapChar" value=""/>
<property key="labeling/xOffset" value="0"/>
<property key="labeling/yOffset" value="0"/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerTransparency>0</layerTransparency>
<displayfield>OGC_FID</displayfield>
<label>0</label>
<labelattributes>
<label fieldname="" text="Label"/>
<family fieldname="" name="Sans"/>
<size fieldname="" units="pt" value="12"/>
<bold fieldname="" on="0"/>
<italic fieldname="" on="0"/>
<underline fieldname="" on="0"/>
<strikeout fieldname="" on="0"/>
<color fieldname="" red="0" blue="0" green="0"/>
<x fieldname=""/>
<y fieldname=""/>
<offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
<angle fieldname="" value="0" auto="0"/>
<alignment fieldname="" value="center"/>
<buffercolor fieldname="" red="255" blue="255" green="255"/>
<buffersize fieldname="" units="pt" value="1"/>
<bufferenabled fieldname="" on=""/>
<multilineenabled fieldname="" on=""/>
<selectedonly on=""/>
</labelattributes>
<edittypes>
<edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
<edittype labelontop="0" editable="1" type="0" name="id"/>
<edittype labelontop="0" editable="1" type="0" name="object_id"/>
<edittype labelontop="0" editable="1" type="0" name="problem_type"/>
<edittype labelontop="0" editable="1" type="0" name="type"/>
<edittype labelontop="0" editable="1" type="0" name="way_id"/>
</edittypes>
<editform>.</editform>
<editforminit></editforminit>
<featformsuppress>0</featformsuppress>
<annotationform>.</annotationform>
<editorlayout>generatedlayout</editorlayout>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<attributeactions/>
</maplayer>
<maplayer minimumScale="-4.65661e-10" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Polygon" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
<id>multipolygons20140221151811742</id>
<datasource>dbname='./multipolygon.db' table="multipolygons" (GEOMETRY) sql=</datasource>
<title></title>
<abstract></abstract>
<keywordList>
<value></value>
</keywordList>
<layername>multipolygons</layername>
<srs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<provider encoding="System">spatialite</provider>
<previewExpression></previewExpression>
<vectorjoins/>
<renderer-v2 symbollevels="0" type="singleSymbol">
<symbols>
<symbol alpha="0.494118" type="fill" name="0">
<layer pass="0" class="SimpleFill" locked="0">
<prop k="border_width_unit" v="MM"/>
<prop k="color" v="0,170,255,255"/>
<prop k="color_border" v="0,0,0,255"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="style" v="solid"/>
<prop k="style_border" v="solid"/>
<prop k="width_border" v="0.26"/>
</layer>
</symbol>
</symbols>
<rotation/>
<sizescale scalemethod="area"/>
</renderer-v2>
<customproperties>
<property key="labeling" value="pal"/>
<property key="labeling/addDirectionSymbol" value="false"/>
<property key="labeling/angleOffset" value="0"/>
<property key="labeling/blendMode" value="0"/>
<property key="labeling/bufferBlendMode" value="0"/>
<property key="labeling/bufferColorA" value="255"/>
<property key="labeling/bufferColorB" value="255"/>
<property key="labeling/bufferColorG" value="255"/>
<property key="labeling/bufferColorR" value="255"/>
<property key="labeling/bufferDraw" value="false"/>
<property key="labeling/bufferJoinStyle" value="64"/>
<property key="labeling/bufferNoFill" value="false"/>
<property key="labeling/bufferSize" value="1"/>
<property key="labeling/bufferSizeInMapUnits" value="false"/>
<property key="labeling/bufferTransp" value="0"/>
<property key="labeling/centroidWhole" value="false"/>
<property key="labeling/decimals" value="3"/>
<property key="labeling/displayAll" value="false"/>
<property key="labeling/dist" value="0"/>
<property key="labeling/distInMapUnits" value="false"/>
<property key="labeling/enabled" value="false"/>
<property key="labeling/fieldName" value=""/>
<property key="labeling/fontBold" value="false"/>
<property key="labeling/fontCapitals" value="0"/>
<property key="labeling/fontFamily" value="Sans"/>
<property key="labeling/fontItalic" value="false"/>
<property key="labeling/fontLetterSpacing" value="0"/>
<property key="labeling/fontLimitPixelSize" value="false"/>
<property key="labeling/fontMaxPixelSize" value="10000"/>
<property key="labeling/fontMinPixelSize" value="3"/>
<property key="labeling/fontSize" value="10"/>
<property key="labeling/fontSizeInMapUnits" value="false"/>
<property key="labeling/fontStrikeout" value="false"/>
<property key="labeling/fontUnderline" value="false"/>
<property key="labeling/fontWeight" value="50"/>
<property key="labeling/fontWordSpacing" value="0"/>
<property key="labeling/formatNumbers" value="false"/>
<property key="labeling/isExpression" value="false"/>
<property key="labeling/labelOffsetInMapUnits" value="true"/>
<property key="labeling/labelPerPart" value="false"/>
<property key="labeling/leftDirectionSymbol" value="&lt;"/>
<property key="labeling/limitNumLabels" value="false"/>
<property key="labeling/maxCurvedCharAngleIn" value="20"/>
<property key="labeling/maxCurvedCharAngleOut" value="-20"/>
<property key="labeling/maxNumLabels" value="2000"/>
<property key="labeling/mergeLines" value="false"/>
<property key="labeling/minFeatureSize" value="0"/>
<property key="labeling/multilineAlign" value="0"/>
<property key="labeling/multilineHeight" value="1"/>
<property key="labeling/namedStyle" value=""/>
<property key="labeling/obstacle" value="true"/>
<property key="labeling/placeDirectionSymbol" value="0"/>
<property key="labeling/placement" value="0"/>
<property key="labeling/placementFlags" value="0"/>
<property key="labeling/plussign" value="false"/>
<property key="labeling/preserveRotation" value="true"/>
<property key="labeling/previewBkgrdColor" value="#ffffff"/>
<property key="labeling/priority" value="5"/>
<property key="labeling/quadOffset" value="4"/>
<property key="labeling/reverseDirectionSymbol" value="false"/>
<property key="labeling/rightDirectionSymbol" value=">"/>
<property key="labeling/scaleMax" value="10000000"/>
<property key="labeling/scaleMin" value="1"/>
<property key="labeling/scaleVisibility" value="false"/>
<property key="labeling/shadowBlendMode" value="6"/>
<property key="labeling/shadowColorB" value="0"/>
<property key="labeling/shadowColorG" value="0"/>
<property key="labeling/shadowColorR" value="0"/>
<property key="labeling/shadowDraw" value="false"/>
<property key="labeling/shadowOffsetAngle" value="135"/>
<property key="labeling/shadowOffsetDist" value="1"/>
<property key="labeling/shadowOffsetGlobal" value="true"/>
<property key="labeling/shadowOffsetUnits" value="1"/>
<property key="labeling/shadowRadius" value="1.5"/>
<property key="labeling/shadowRadiusAlphaOnly" value="false"/>
<property key="labeling/shadowRadiusUnits" value="1"/>
<property key="labeling/shadowScale" value="100"/>
<property key="labeling/shadowTransparency" value="30"/>
<property key="labeling/shadowUnder" value="0"/>
<property key="labeling/shapeBlendMode" value="0"/>
<property key="labeling/shapeBorderColorA" value="255"/>
<property key="labeling/shapeBorderColorB" value="128"/>
<property key="labeling/shapeBorderColorG" value="128"/>
<property key="labeling/shapeBorderColorR" value="128"/>
<property key="labeling/shapeBorderWidth" value="0"/>
<property key="labeling/shapeBorderWidthUnits" value="1"/>
<property key="labeling/shapeDraw" value="false"/>
<property key="labeling/shapeFillColorA" value="255"/>
<property key="labeling/shapeFillColorB" value="255"/>
<property key="labeling/shapeFillColorG" value="255"/>
<property key="labeling/shapeFillColorR" value="255"/>
<property key="labeling/shapeJoinStyle" value="64"/>
<property key="labeling/shapeOffsetUnits" value="1"/>
<property key="labeling/shapeOffsetX" value="0"/>
<property key="labeling/shapeOffsetY" value="0"/>
<property key="labeling/shapeRadiiUnits" value="1"/>
<property key="labeling/shapeRadiiX" value="0"/>
<property key="labeling/shapeRadiiY" value="0"/>
<property key="labeling/shapeRotation" value="0"/>
<property key="labeling/shapeRotationType" value="0"/>
<property key="labeling/shapeSVGFile" value=""/>
<property key="labeling/shapeSizeType" value="0"/>
<property key="labeling/shapeSizeUnits" value="1"/>
<property key="labeling/shapeSizeX" value="0"/>
<property key="labeling/shapeSizeY" value="0"/>
<property key="labeling/shapeTransparency" value="0"/>
<property key="labeling/shapeType" value="0"/>
<property key="labeling/textColorA" value="255"/>
<property key="labeling/textColorB" value="0"/>
<property key="labeling/textColorG" value="0"/>
<property key="labeling/textColorR" value="0"/>
<property key="labeling/textTransp" value="0"/>
<property key="labeling/upsidedownLabels" value="0"/>
<property key="labeling/wrapChar" value=""/>
<property key="labeling/xOffset" value="0"/>
<property key="labeling/yOffset" value="0"/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerTransparency>0</layerTransparency>
<displayfield>OGC_FID</displayfield>
<label>0</label>
<labelattributes>
<label fieldname="" text="Label"/>
<family fieldname="" name="Sans"/>
<size fieldname="" units="pt" value="12"/>
<bold fieldname="" on="0"/>
<italic fieldname="" on="0"/>
<underline fieldname="" on="0"/>
<strikeout fieldname="" on="0"/>
<color fieldname="" red="0" blue="0" green="0"/>
<x fieldname=""/>
<y fieldname=""/>
<offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
<angle fieldname="" value="0" auto="0"/>
<alignment fieldname="" value="center"/>
<buffercolor fieldname="" red="255" blue="255" green="255"/>
<buffersize fieldname="" units="pt" value="1"/>
<bufferenabled fieldname="" on=""/>
<multilineenabled fieldname="" on=""/>
<selectedonly on=""/>
</labelattributes>
<edittypes>
<edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
<edittype labelontop="0" editable="1" type="0" name="id"/>
<edittype labelontop="0" editable="1" type="0" name="type"/>
</edittypes>
<editform>.</editform>
<editforminit></editforminit>
<featformsuppress>0</featformsuppress>
<annotationform>.</annotationform>
<editorlayout>generatedlayout</editorlayout>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<attributeactions/>
</maplayer>
<maplayer minimumScale="0" maximumScale="1e+08" simplifyDrawingHints="0" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Point" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
<id>perrors20140228163658956</id>
<datasource>dbname='./multipolygon.db' table="perrors" (GEOMETRY) sql=</datasource>
<title></title>
<abstract></abstract>
<keywordList>
<value></value>
</keywordList>
<layername>Error Points</layername>
<srs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<provider encoding="System">spatialite</provider>
<previewExpression>COALESCE( "OGC_FID", '&lt;NULL>' )</previewExpression>
<vectorjoins/>
<renderer-v2 attr="problem_type" symbollevels="0" type="categorizedSymbol">
<categories>
<category symbol="0" value="intersection" label="intersection"/>
<category symbol="1" value="ring_not_closed" label="ring_not_closed"/>
<category symbol="2" value="duplicate_node" label="duplicate_node"/>
</categories>
<symbols>
<symbol alpha="1" type="marker" name="0">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,0,0,255"/>
<prop k="color_border" v="255,255,255,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="name" v="diamond"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.4"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="2.8"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
<symbol alpha="1" type="marker" name="1">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,0,0,255"/>
<prop k="color_border" v="255,255,255,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="name" v="triangle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.4"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="2.8"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
<symbol alpha="1" type="marker" name="2">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,255,255,255"/>
<prop k="color_border" v="255,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.4"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="2.4"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,0,0,255"/>
<prop k="color_border" v="255,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.8"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="0.5"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
</symbols>
<source-symbol>
<symbol alpha="1" type="marker" name="0">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="139,168,110,255"/>
<prop k="color_border" v="0,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="2"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
</source-symbol>
<rotation/>
<sizescale scalemethod="area"/>
</renderer-v2>
<customproperties>
<property key="labeling" value="pal"/>
<property key="labeling/addDirectionSymbol" value="false"/>
<property key="labeling/angleOffset" value="0"/>
<property key="labeling/blendMode" value="0"/>
<property key="labeling/bufferBlendMode" value="0"/>
<property key="labeling/bufferColorA" value="255"/>
<property key="labeling/bufferColorB" value="255"/>
<property key="labeling/bufferColorG" value="255"/>
<property key="labeling/bufferColorR" value="255"/>
<property key="labeling/bufferDraw" value="false"/>
<property key="labeling/bufferJoinStyle" value="64"/>
<property key="labeling/bufferNoFill" value="false"/>
<property key="labeling/bufferSize" value="1"/>
<property key="labeling/bufferSizeInMapUnits" value="false"/>
<property key="labeling/bufferTransp" value="0"/>
<property key="labeling/centroidWhole" value="false"/>
<property key="labeling/decimals" value="3"/>
<property key="labeling/displayAll" value="false"/>
<property key="labeling/dist" value="0"/>
<property key="labeling/distInMapUnits" value="false"/>
<property key="labeling/enabled" value="false"/>
<property key="labeling/fieldName" value=""/>
<property key="labeling/fontBold" value="false"/>
<property key="labeling/fontCapitals" value="0"/>
<property key="labeling/fontFamily" value="Sans"/>
<property key="labeling/fontItalic" value="false"/>
<property key="labeling/fontLetterSpacing" value="0"/>
<property key="labeling/fontLimitPixelSize" value="false"/>
<property key="labeling/fontMaxPixelSize" value="10000"/>
<property key="labeling/fontMinPixelSize" value="3"/>
<property key="labeling/fontSize" value="10"/>
<property key="labeling/fontSizeInMapUnits" value="false"/>
<property key="labeling/fontStrikeout" value="false"/>
<property key="labeling/fontUnderline" value="false"/>
<property key="labeling/fontWeight" value="50"/>
<property key="labeling/fontWordSpacing" value="0"/>
<property key="labeling/formatNumbers" value="false"/>
<property key="labeling/isExpression" value="false"/>
<property key="labeling/labelOffsetInMapUnits" value="true"/>
<property key="labeling/labelPerPart" value="false"/>
<property key="labeling/leftDirectionSymbol" value="&lt;"/>
<property key="labeling/limitNumLabels" value="false"/>
<property key="labeling/maxCurvedCharAngleIn" value="20"/>
<property key="labeling/maxCurvedCharAngleOut" value="-20"/>
<property key="labeling/maxNumLabels" value="2000"/>
<property key="labeling/mergeLines" value="false"/>
<property key="labeling/minFeatureSize" value="0"/>
<property key="labeling/multilineAlign" value="0"/>
<property key="labeling/multilineHeight" value="1"/>
<property key="labeling/namedStyle" value=""/>
<property key="labeling/obstacle" value="true"/>
<property key="labeling/placeDirectionSymbol" value="0"/>
<property key="labeling/placement" value="0"/>
<property key="labeling/placementFlags" value="0"/>
<property key="labeling/plussign" value="false"/>
<property key="labeling/preserveRotation" value="true"/>
<property key="labeling/previewBkgrdColor" value="#ffffff"/>
<property key="labeling/priority" value="5"/>
<property key="labeling/quadOffset" value="4"/>
<property key="labeling/reverseDirectionSymbol" value="false"/>
<property key="labeling/rightDirectionSymbol" value=">"/>
<property key="labeling/scaleMax" value="10000000"/>
<property key="labeling/scaleMin" value="1"/>
<property key="labeling/scaleVisibility" value="false"/>
<property key="labeling/shadowBlendMode" value="6"/>
<property key="labeling/shadowColorB" value="0"/>
<property key="labeling/shadowColorG" value="0"/>
<property key="labeling/shadowColorR" value="0"/>
<property key="labeling/shadowDraw" value="false"/>
<property key="labeling/shadowOffsetAngle" value="135"/>
<property key="labeling/shadowOffsetDist" value="1"/>
<property key="labeling/shadowOffsetGlobal" value="true"/>
<property key="labeling/shadowOffsetUnits" value="1"/>
<property key="labeling/shadowRadius" value="1.5"/>
<property key="labeling/shadowRadiusAlphaOnly" value="false"/>
<property key="labeling/shadowRadiusUnits" value="1"/>
<property key="labeling/shadowScale" value="100"/>
<property key="labeling/shadowTransparency" value="30"/>
<property key="labeling/shadowUnder" value="0"/>
<property key="labeling/shapeBlendMode" value="0"/>
<property key="labeling/shapeBorderColorA" value="255"/>
<property key="labeling/shapeBorderColorB" value="128"/>
<property key="labeling/shapeBorderColorG" value="128"/>
<property key="labeling/shapeBorderColorR" value="128"/>
<property key="labeling/shapeBorderWidth" value="0"/>
<property key="labeling/shapeBorderWidthUnits" value="1"/>
<property key="labeling/shapeDraw" value="false"/>
<property key="labeling/shapeFillColorA" value="255"/>
<property key="labeling/shapeFillColorB" value="255"/>
<property key="labeling/shapeFillColorG" value="255"/>
<property key="labeling/shapeFillColorR" value="255"/>
<property key="labeling/shapeJoinStyle" value="64"/>
<property key="labeling/shapeOffsetUnits" value="1"/>
<property key="labeling/shapeOffsetX" value="0"/>
<property key="labeling/shapeOffsetY" value="0"/>
<property key="labeling/shapeRadiiUnits" value="1"/>
<property key="labeling/shapeRadiiX" value="0"/>
<property key="labeling/shapeRadiiY" value="0"/>
<property key="labeling/shapeRotation" value="0"/>
<property key="labeling/shapeRotationType" value="0"/>
<property key="labeling/shapeSVGFile" value=""/>
<property key="labeling/shapeSizeType" value="0"/>
<property key="labeling/shapeSizeUnits" value="1"/>
<property key="labeling/shapeSizeX" value="0"/>
<property key="labeling/shapeSizeY" value="0"/>
<property key="labeling/shapeTransparency" value="0"/>
<property key="labeling/shapeType" value="0"/>
<property key="labeling/textColorA" value="255"/>
<property key="labeling/textColorB" value="0"/>
<property key="labeling/textColorG" value="0"/>
<property key="labeling/textColorR" value="0"/>
<property key="labeling/textTransp" value="0"/>
<property key="labeling/upsidedownLabels" value="0"/>
<property key="labeling/wrapChar" value=""/>
<property key="labeling/xOffset" value="0"/>
<property key="labeling/yOffset" value="0"/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerTransparency>0</layerTransparency>
<displayfield>OGC_FID</displayfield>
<label>0</label>
<labelattributes>
<label fieldname="" text="Label"/>
<family fieldname="" name="Sans"/>
<size fieldname="" units="pt" value="12"/>
<bold fieldname="" on="0"/>
<italic fieldname="" on="0"/>
<underline fieldname="" on="0"/>
<strikeout fieldname="" on="0"/>
<color fieldname="" red="0" blue="0" green="0"/>
<x fieldname=""/>
<y fieldname=""/>
<offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
<angle fieldname="" value="0" auto="0"/>
<alignment fieldname="" value="center"/>
<buffercolor fieldname="" red="255" blue="255" green="255"/>
<buffersize fieldname="" units="pt" value="1"/>
<bufferenabled fieldname="" on=""/>
<multilineenabled fieldname="" on=""/>
<selectedonly on=""/>
</labelattributes>
<edittypes>
<edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
<edittype labelontop="0" editable="1" type="0" name="id"/>
<edittype labelontop="0" editable="1" type="0" name="node_id"/>
<edittype labelontop="0" editable="1" type="0" name="object_id"/>
<edittype labelontop="0" editable="1" type="0" name="problem_type"/>
<edittype labelontop="0" editable="1" type="0" name="type"/>
</edittypes>
<editform>.</editform>
<editforminit></editforminit>
<featformsuppress>0</featformsuppress>
<annotationform>.</annotationform>
<editorlayout>generatedlayout</editorlayout>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<attributeactions/>
</maplayer>
</projectlayers>
<properties>
<WMSContactPerson type="QString"></WMSContactPerson>
<WMSOnlineResource type="QString"></WMSOnlineResource>
<WMSContactOrganization type="QString"></WMSContactOrganization>
<WMSExtent type="QStringList">
<value>0.82500024999999999</value>
<value>-0.35415386986094277</value>
<value>8.17498974999999994</value>
<value>3.45415386986094308</value>
</WMSExtent>
<WMSKeywordList type="QStringList">
<value></value>
</WMSKeywordList>
<WFSUrl type="QString"></WFSUrl>
<Paths>
<Absolute type="bool">false</Absolute>
</Paths>
<WMSServiceTitle type="QString">mp test</WMSServiceTitle>
<WFSLayers type="QStringList"/>
<WMSContactMail type="QString"></WMSContactMail>
<PositionPrecision>
<DecimalPlaces type="int">2</DecimalPlaces>
<Automatic type="bool">true</Automatic>
<DegreeFormat type="QString">D</DegreeFormat>
</PositionPrecision>
<WCSUrl type="QString"></WCSUrl>
<WMSContactPhone type="QString"></WMSContactPhone>
<WMSServiceCapabilities type="bool">true</WMSServiceCapabilities>
<WMSServiceAbstract type="QString"></WMSServiceAbstract>
<WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
<Measure>
<Ellipsoid type="QString">NONE</Ellipsoid>
</Measure>
<WFSTLayers>
<Insert type="QStringList"/>
<Update type="QStringList"/>
<Delete type="QStringList"/>
</WFSTLayers>
<Gui>
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
</Gui>
<Identify>
<disabledLayers type="QStringList"/>
</Identify>
<Macros>
<pythonCode type="QString"></pythonCode>
</Macros>
<WMSAccessConstraints type="QString"></WMSAccessConstraints>
<WCSLayers type="QStringList"/>
<SpatialRefSys>
<ProjectCrs type="QString">EPSG:4326</ProjectCrs>
</SpatialRefSys>
<DefaultStyles>
<Fill type="QString"></Fill>
<Line type="QString"></Line>
<Marker type="QString"></Marker>
<RandomColors type="bool">true</RandomColors>
<AlphaInt type="int">255</AlphaInt>
<ColorRamp type="QString"></ColorRamp>
</DefaultStyles>
<WMSFees type="QString"></WMSFees>
<WMSUrl type="QString"></WMSUrl>
</properties>
</qgis>

View File

@ -0,0 +1,46 @@
#-----------------------------------------------------------------------------
#
# Helper script that runs the 'multipolygon' test.
#
#-----------------------------------------------------------------------------
# Remove files that might be left over from previous run
file(REMOVE multipolygon.db multipolygon-tests.json)
#-----------------------------------------------------------------------------
#
# Create multipolygons from test data.
#
#-----------------------------------------------------------------------------
execute_process(
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/testdata-multipolygon
${OSM_TESTDATA}/grid/data/all.osm
RESULT_VARIABLE _result
OUTPUT_FILE multipolygon.log
ERROR_FILE multipolygon.log
)
if(_result)
message(FATAL_ERROR "Error running testdata-multipolygon command")
endif()
#-----------------------------------------------------------------------------
#
# Compare created multipolygons with reference data.
#
#-----------------------------------------------------------------------------
execute_process(
COMMAND ${RUBY} ${OSM_TESTDATA}/bin/compare-areas.rb
${OSM_TESTDATA}/grid/data/tests.json
multipolygon-tests.json
RESULT_VARIABLE _result
)
if(_result)
message(FATAL_ERROR "Error running compare-areas command")
endif()
#-----------------------------------------------------------------------------

View File

@ -0,0 +1,41 @@
#include "common.hpp"
class TestHandler100 : public osmium::handler::Handler {
public:
TestHandler100() :
osmium::handler::Handler() {
}
void node(osmium::Node& node) {
if (node.id() == 100000) {
REQUIRE(node.version() == 1);
REQUIRE(node.timestamp() == osmium::Timestamp("2014-01-01T00:00:00Z"));
REQUIRE(node.uid() == 1);
REQUIRE(!strcmp(node.user(), "test"));
REQUIRE(node.changeset() == 1);
REQUIRE(node.location().lon() == 1.02);
REQUIRE(node.location().lat() == 1.02);
} else {
throw std::runtime_error("Unknown ID");
}
}
}; // class TestHandler100
TEST_CASE("100") {
SECTION("test 100") {
osmium::io::Reader reader(dirname + "/1/100/data.osm");
CheckBasicsHandler check_basics_handler(100, 1, 0, 0);
CheckWKTHandler check_wkt_handler(dirname, 100);
TestHandler100 test_handler;
osmium::apply(reader, check_basics_handler, check_wkt_handler, test_handler);
}
}

View File

@ -0,0 +1,43 @@
#include "common.hpp"
class TestHandler101 : public osmium::handler::Handler {
public:
TestHandler101() :
osmium::handler::Handler() {
}
void node(osmium::Node& node) {
if (node.id() == 101000) {
REQUIRE(node.version() == 1);
REQUIRE(node.location().lon() == 1.12);
REQUIRE(node.location().lat() == 1.02);
} else if (node.id() == 101001) {
REQUIRE(node.version() == 1);
REQUIRE(node.location().lon() == 1.12);
REQUIRE(node.location().lat() == 1.03);
} else if (node.id() == 101002) {
} else if (node.id() == 101003) {
} else {
throw std::runtime_error("Unknown ID");
}
}
}; // class TestHandler101
TEST_CASE("101") {
SECTION("test 101") {
osmium::io::Reader reader(dirname + "/1/101/data.osm");
CheckBasicsHandler check_basics_handler(101, 4, 0, 0);
CheckWKTHandler check_wkt_handler(dirname, 101);
TestHandler101 test_handler;
osmium::apply(reader, check_basics_handler, check_wkt_handler, test_handler);
}
}

View File

@ -0,0 +1,58 @@
#include "common.hpp"
class TestHandler110 : public osmium::handler::Handler {
public:
TestHandler110() :
osmium::handler::Handler() {
}
void node(const osmium::Node& node) {
if (node.id() == 110000) {
REQUIRE(node.location().lon() == 1.02);
REQUIRE(node.location().lat() == 1.12);
} else if (node.id() == 110001) {
REQUIRE(node.location().lon() == 1.07);
REQUIRE(node.location().lat() == 1.13);
} else {
throw std::runtime_error("Unknown ID");
}
}
void way(const osmium::Way& way) {
if (way.id() == 110800) {
REQUIRE(way.version() == 1);
REQUIRE(way.nodes().size() == 2);
REQUIRE(!way.is_closed());
const char *test_id = way.tags().get_value_by_key("test:id");
REQUIRE(test_id);
REQUIRE(!strcmp(test_id, "110"));
} else {
throw std::runtime_error("Unknown ID");
}
}
}; // class TestHandler110
TEST_CASE("110") {
SECTION("test 110") {
osmium::io::Reader reader(dirname + "/1/110/data.osm");
index_pos_type index_pos;
index_neg_type index_neg;
location_handler_type location_handler(index_pos, index_neg);
location_handler.ignore_errors();
CheckBasicsHandler check_basics_handler(110, 2, 1, 0);
CheckWKTHandler check_wkt_handler(dirname, 110);
TestHandler110 test_handler;
osmium::apply(reader, location_handler, check_basics_handler, check_wkt_handler, test_handler);
}
}

View File

@ -0,0 +1,182 @@
#include <iostream>
#include <fstream>
#include <map>
#include <gdalcpp.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp>
#include <osmium/area/problem_reporter_ogr.hpp>
#include <osmium/geom/ogr.hpp>
#include <osmium/geom/wkt.hpp>
#include <osmium/handler.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
struct less_charptr {
bool operator()(const char* a, const char* b) const {
return std::strcmp(a, b) < 0;
}
}; // less_charptr
typedef std::map<const char*, const char*, less_charptr> tagmap_type;
inline tagmap_type create_map(const osmium::TagList& taglist) {
tagmap_type map;
for (auto& tag : taglist) {
map[tag.key()] = tag.value();
}
return map;
}
class TestHandler : public osmium::handler::Handler {
gdalcpp::Layer m_layer_point;
gdalcpp::Layer m_layer_lines;
gdalcpp::Layer m_layer_mpoly;
osmium::geom::OGRFactory<> m_ogr_factory;
osmium::geom::WKTFactory<> m_wkt_factory;
std::ofstream m_out;
bool m_first_out {true};
public:
explicit TestHandler(gdalcpp::Dataset& dataset) :
m_layer_point(dataset, "points", wkbPoint),
m_layer_lines(dataset, "lines", wkbLineString),
m_layer_mpoly(dataset, "multipolygons", wkbMultiPolygon),
m_out("multipolygon-tests.json") {
m_layer_point.add_field("id", OFTReal, 10);
m_layer_point.add_field("type", OFTString, 30);
m_layer_lines.add_field("id", OFTReal, 10);
m_layer_lines.add_field("type", OFTString, 30);
m_layer_mpoly.add_field("id", OFTReal, 10);
m_layer_mpoly.add_field("from_type", OFTString, 1);
}
~TestHandler() {
m_out << "\n]\n";
}
void node(const osmium::Node& node) {
gdalcpp::Feature feature(m_layer_point, m_ogr_factory.create_point(node));
feature.set_field("id", static_cast<double>(node.id()));
feature.set_field("type", node.tags().get_value_by_key("type"));
feature.add_to_layer();
}
void way(const osmium::Way& way) {
try {
gdalcpp::Feature feature(m_layer_lines, m_ogr_factory.create_linestring(way));
feature.set_field("id", static_cast<double>(way.id()));
feature.set_field("type", way.tags().get_value_by_key("type"));
feature.add_to_layer();
} catch (osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
}
}
void area(const osmium::Area& area) {
if (m_first_out) {
m_out << "[\n";
m_first_out = false;
} else {
m_out << ",\n";
}
m_out << "{\n \"test_id\": " << (area.orig_id() / 1000) << ",\n \"area_id\": " << area.id() << ",\n \"from_id\": " << area.orig_id() << ",\n \"from_type\": \"" << (area.from_way() ? "way" : "relation") << "\",\n \"wkt\": \"";
try {
std::string wkt = m_wkt_factory.create_multipolygon(area);
m_out << wkt << "\",\n \"tags\": {";
auto tagmap = create_map(area.tags());
bool first = true;
for (auto& tag : tagmap) {
if (first) {
first = false;
} else {
m_out << ", ";
}
m_out << '"' << tag.first << "\": \"" << tag.second << '"';
}
m_out << "}\n}";
} catch (osmium::geometry_error&) {
m_out << "INVALID\"\n}";
}
try {
gdalcpp::Feature feature(m_layer_mpoly, m_ogr_factory.create_multipolygon(area));
feature.set_field("id", static_cast<double>(area.orig_id()));
std::string from_type;
if (area.from_way()) {
from_type = "w";
} else {
from_type = "r";
}
feature.set_field("from_type", from_type.c_str());
feature.add_to_layer();
} catch (osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
}
}
}; // class TestHandler
/* ================================================== */
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " INFILE\n";
exit(1);
}
std::string output_format("SQLite");
std::string input_filename(argv[1]);
std::string output_filename("multipolygon.db");
CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
gdalcpp::Dataset dataset{output_format, output_filename, gdalcpp::SRS{}, { "SPATIALITE=TRUE" }};
osmium::area::ProblemReporterOGR problem_reporter(dataset);
osmium::area::Assembler::config_type assembler_config(&problem_reporter);
assembler_config.enable_debug_output();
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
std::cerr << "Pass 1...\n";
osmium::io::Reader reader1(input_filename);
collector.read_relations(reader1);
reader1.close();
std::cerr << "Pass 1 done\n";
index_type index;
location_handler_type location_handler(index);
location_handler.ignore_errors();
TestHandler test_handler(dataset);
std::cerr << "Pass 2...\n";
osmium::io::Reader reader2(input_filename);
osmium::apply(reader2, location_handler, test_handler, collector.handler([&test_handler](const osmium::memory::Buffer& area_buffer) {
osmium::apply(area_buffer, test_handler);
}));
reader2.close();
std::cerr << "Pass 2 done\n";
}

View File

@ -0,0 +1,101 @@
/* The code in this file is released into the Public Domain. */
#include <iostream>
#include <gdalcpp.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/geom/ogr.hpp>
#include <osmium/handler.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
class TestOverviewHandler : public osmium::handler::Handler {
gdalcpp::Layer m_layer_nodes;
gdalcpp::Layer m_layer_labels;
gdalcpp::Layer m_layer_ways;
osmium::geom::OGRFactory<> m_factory;
public:
explicit TestOverviewHandler(gdalcpp::Dataset& dataset) :
m_layer_nodes(dataset, "nodes", wkbPoint),
m_layer_labels(dataset, "labels", wkbPoint),
m_layer_ways(dataset, "ways", wkbLineString) {
m_layer_nodes.add_field("id", OFTReal, 10);
m_layer_labels.add_field("id", OFTReal, 10);
m_layer_labels.add_field("label", OFTString, 30);
m_layer_ways.add_field("id", OFTReal, 10);
m_layer_ways.add_field("test", OFTInteger, 3);
}
void node(const osmium::Node& node) {
const char* label = node.tags().get_value_by_key("label");
if (label) {
gdalcpp::Feature feature(m_layer_labels, m_factory.create_point(node));
feature.set_field("id", static_cast<double>(node.id()));
feature.set_field("label", label);
feature.add_to_layer();
} else {
gdalcpp::Feature feature(m_layer_nodes, m_factory.create_point(node));
feature.set_field("id", static_cast<double>(node.id()));
feature.add_to_layer();
}
}
void way(const osmium::Way& way) {
try {
gdalcpp::Feature feature(m_layer_ways, m_factory.create_linestring(way));
feature.set_field("id", static_cast<double>(way.id()));
const char* test = way.tags().get_value_by_key("test");
if (test) {
feature.set_field("test", test);
}
feature.add_to_layer();
} catch (osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
}
}
};
/* ================================================== */
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " INFILE\n";
exit(1);
}
std::string output_format("SQLite");
std::string input_filename(argv[1]);
std::string output_filename("testdata-overview.db");
::unlink(output_filename.c_str());
CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
gdalcpp::Dataset dataset(output_format, output_filename, gdalcpp::SRS{}, { "SPATIALITE=TRUE" });
osmium::io::Reader reader(input_filename);
index_type index;
location_handler_type location_handler(index);
location_handler.ignore_errors();
TestOverviewHandler handler(dataset);
osmium::apply(reader, location_handler, handler);
reader.close();
}

View File

@ -0,0 +1,25 @@
#include <iostream>
#include <string>
#define CATCH_CONFIG_RUNNER
#include "testdata-testcases.hpp"
std::string dirname;
int main(int argc, char* argv[]) {
const char* testcases_dir = getenv("TESTCASES_DIR");
if (testcases_dir) {
dirname = testcases_dir;
std::cerr << "Running tests from '" << dirname << "' (from TESTCASES_DIR environment variable)\n";
} else {
std::cerr << "Please set TESTCASES_DIR environment variable.\n";
exit(1);
}
int result = Catch::Session().run(argc, argv);
return result;
}

View File

@ -0,0 +1,561 @@
/* The code in this file is released into the Public Domain. */
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <string>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/io/gzip_compression.hpp>
#include <osmium/visitor.hpp>
std::string S_(const char* s) {
return std::string(s);
}
std::string filename(const char* test_id, const char* suffix = "osm") {
const char* testdir = getenv("TESTDIR");
if (!testdir) {
std::cerr << "You have to set TESTDIR environment variable before running testdata-xml\n";
exit(2);
}
std::string f;
f += testdir;
f += "/";
f += test_id;
f += "/data.";
f += suffix;
return f;
}
struct header_buffer_type {
osmium::io::Header header;
osmium::memory::Buffer buffer;
};
// =============================================
// The following helper functions are used to call different parts of the
// Osmium internals used to read and parse XML files. This way those parts
// can be tested individually. These function can not be used in normal
// operations, because they make certain assumptions, for instance that
// file contents fit into small buffers.
std::string read_file(const char* test_id) {
int fd = osmium::io::detail::open_for_reading(filename(test_id));
assert(fd >= 0);
std::string input(10000, '\0');
auto n = ::read(fd, reinterpret_cast<unsigned char*>(const_cast<char*>(input.data())), 10000);
assert(n >= 0);
input.resize(static_cast<std::string::size_type>(n));
close(fd);
return input;
}
std::string read_gz_file(const char* test_id, const char* suffix) {
int fd = osmium::io::detail::open_for_reading(filename(test_id, suffix));
assert(fd >= 0);
osmium::io::GzipDecompressor gzip_decompressor(fd);
std::string input = gzip_decompressor.read();
gzip_decompressor.close();
return input;
}
header_buffer_type parse_xml(std::string input) {
osmium::io::detail::future_string_queue_type input_queue;
osmium::io::detail::future_buffer_queue_type output_queue;
std::promise<osmium::io::Header> header_promise;
std::future<osmium::io::Header> header_future = header_promise.get_future();
osmium::io::detail::add_to_queue(input_queue, std::move(input));
osmium::io::detail::add_to_queue(input_queue, std::string{});
osmium::io::detail::XMLParser parser(input_queue, output_queue, header_promise, osmium::osm_entity_bits::all);
parser.parse();
header_buffer_type result;
result.header = header_future.get();
std::future<osmium::memory::Buffer> future_buffer;
output_queue.wait_and_pop(future_buffer);
result.buffer = future_buffer.get();
if (result.buffer) {
std::future<osmium::memory::Buffer> future_buffer2;
output_queue.wait_and_pop(future_buffer2);
assert(!future_buffer2.get());
}
return result;
}
header_buffer_type read_xml(const char* test_id) {
std::string input = read_file(test_id);
return parse_xml(input);
}
// =============================================
TEST_CASE("Reading OSM XML 100") {
SECTION("Direct") {
header_buffer_type r = read_xml("100-correct_but_no_data");
REQUIRE(r.header.get("generator") == "testdata");
REQUIRE(0 == r.buffer.committed());
REQUIRE(! r.buffer);
}
SECTION("Using Reader") {
osmium::io::Reader reader(filename("100-correct_but_no_data"));
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
REQUIRE(0 == buffer.committed());
REQUIRE(! buffer);
reader.close();
}
SECTION("Using Reader asking for header only") {
osmium::io::Reader reader(filename("100-correct_but_no_data"), osmium::osm_entity_bits::nothing);
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
reader.close();
}
}
// =============================================
TEST_CASE("Reading OSM XML 101") {
SECTION("Direct") {
REQUIRE_THROWS_AS(read_xml("101-missing_version"), osmium::format_version_error);
try {
read_xml("101-missing_version");
} catch (osmium::format_version_error& e) {
REQUIRE(e.version.empty());
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("101-missing_version"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 102") {
SECTION("Direct") {
REQUIRE_THROWS_AS(read_xml("102-wrong_version"), osmium::format_version_error);
try {
read_xml("102-wrong_version");
} catch (osmium::format_version_error& e) {
REQUIRE(e.version == "0.1");
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("102-wrong_version"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 103") {
SECTION("Direct") {
REQUIRE_THROWS_AS(read_xml("103-old_version"), osmium::format_version_error);
try {
read_xml("103-old_version");
} catch (osmium::format_version_error& e) {
REQUIRE(e.version == "0.5");
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("103-old_version"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 104") {
SECTION("Direct") {
REQUIRE_THROWS_AS(read_xml("104-empty_file"), osmium::xml_error);
try {
read_xml("104-empty_file");
} catch (osmium::xml_error& e) {
REQUIRE(e.line == 1);
REQUIRE(e.column == 0);
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("104-empty_file"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 105") {
SECTION("Direct") {
REQUIRE_THROWS_AS(read_xml("105-incomplete_xml_file"), osmium::xml_error);
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("105-incomplete_xml_file"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 120") {
SECTION("Direct") {
std::string data = read_gz_file("120-correct_gzip_file_without_data", "osm.gz");
REQUIRE(data.size() == 102);
header_buffer_type r = parse_xml(data);
REQUIRE(r.header.get("generator") == "testdata");
REQUIRE(0 == r.buffer.committed());
REQUIRE(! r.buffer);
}
SECTION("Using Reader") {
osmium::io::Reader reader(filename("120-correct_gzip_file_without_data", "osm.gz"));
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
REQUIRE(0 == buffer.committed());
REQUIRE(! buffer);
reader.close();
}
}
// =============================================
TEST_CASE("Reading OSM XML 121") {
SECTION("Direct") {
REQUIRE_THROWS_AS( {
read_gz_file("121-truncated_gzip_file", "osm.gz");
}, osmium::gzip_error);
}
SECTION("Using Reader") {
// can throw osmium::gzip_error or osmium::xml_error
REQUIRE_THROWS({
osmium::io::Reader reader(filename("121-truncated_gzip_file", "osm.gz"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
});
}
}
// =============================================
TEST_CASE("Reading OSM XML 122") {
SECTION("Direct") {
REQUIRE_THROWS_AS( {
read_xml("122-no_osm_element");
}, osmium::xml_error);
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("122-no_osm_element"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 140") {
SECTION("Using Reader") {
osmium::io::Reader reader(filename("140-unicode"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
int count = 0;
for (auto it = buffer.begin<osmium::Node>(); it != buffer.end<osmium::Node>(); ++it) {
++count;
REQUIRE(it->id() == count);
const osmium::TagList& t = it->tags();
const char* uc = t["unicode_char"];
auto len = atoi(t["unicode_utf8_length"]);
REQUIRE(len == strlen(uc));
REQUIRE(S_(uc) == t["unicode_xml"]);
// workaround for missing support for u8 string literals on Windows
#if !defined(_MSC_VER)
switch (count) {
case 1:
REQUIRE(S_(uc) == u8"a");
break;
case 2:
REQUIRE(S_(uc) == u8"\u00e4");
break;
case 3:
REQUIRE(S_(uc) == u8"\u30dc");
break;
case 4:
REQUIRE(S_(uc) == u8"\U0001d11e");
break;
case 5:
REQUIRE(S_(uc) == u8"\U0001f6eb");
break;
default:
REQUIRE(false); // should not be here
}
#endif
}
REQUIRE(count == 5);
}
}
// =============================================
TEST_CASE("Reading OSM XML 141") {
SECTION("Using Reader") {
osmium::io::Reader reader(filename("141-entities"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
REQUIRE(buffer.committed() > 0);
REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
const osmium::Node& node = buffer.get<osmium::Node>(0);
const osmium::TagList& tags = node.tags();
REQUIRE(S_(tags["less-than"]) == "<");
REQUIRE(S_(tags["greater-than"]) == ">");
REQUIRE(S_(tags["apostrophe"]) == "'");
REQUIRE(S_(tags["ampersand"]) == "&");
REQUIRE(S_(tags["quote"]) == "\"");
}
}
// =============================================
TEST_CASE("Reading OSM XML 142") {
SECTION("Using Reader to read nodes") {
osmium::io::Reader reader(filename("142-whitespace"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
int count = 0;
for (auto it = buffer.begin<osmium::Node>(); it != buffer.end<osmium::Node>(); ++it) {
++count;
REQUIRE(it->id() == count);
REQUIRE(it->tags().size() == 1);
const osmium::Tag& tag = *(it->tags().begin());
switch (count) {
case 1:
REQUIRE(S_(it->user()) == "user name");
REQUIRE(S_(tag.key()) == "key with space");
REQUIRE(S_(tag.value()) == "value with space");
break;
case 2:
REQUIRE(S_(it->user()) == "line\nfeed");
REQUIRE(S_(tag.key()) == "key with\nlinefeed");
REQUIRE(S_(tag.value()) == "value with\nlinefeed");
break;
case 3:
REQUIRE(S_(it->user()) == "carriage\rreturn");
REQUIRE(S_(tag.key()) == "key with\rcarriage\rreturn");
REQUIRE(S_(tag.value()) == "value with\rcarriage\rreturn");
break;
case 4:
REQUIRE(S_(it->user()) == "tab\tulator");
REQUIRE(S_(tag.key()) == "key with\ttab");
REQUIRE(S_(tag.value()) == "value with\ttab");
break;
case 5:
REQUIRE(S_(it->user()) == "unencoded linefeed");
REQUIRE(S_(tag.key()) == "key with unencoded linefeed");
REQUIRE(S_(tag.value()) == "value with unencoded linefeed");
break;
default:
REQUIRE(false); // should not be here
}
}
REQUIRE(count == 5);
}
SECTION("Using Reader to read relation") {
osmium::io::Reader reader(filename("142-whitespace"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
auto it = buffer.begin<osmium::Relation>();
REQUIRE(it != buffer.end<osmium::Relation>());
REQUIRE(it->id() == 21);
const auto& members = it->members();
REQUIRE(members.size() == 5);
int count = 0;
for (const auto& member : members) {
++count;
switch (count) {
case 1:
REQUIRE(S_(member.role()) == "role with whitespace");
break;
case 2:
REQUIRE(S_(member.role()) == "role with\nlinefeed");
break;
case 3:
REQUIRE(S_(member.role()) == "role with\rcarriage\rreturn");
break;
case 4:
REQUIRE(S_(member.role()) == "role with\ttab");
break;
case 5:
REQUIRE(S_(member.role()) == "role with unencoded linefeed");
break;
default:
REQUIRE(false); // should not be here
}
}
REQUIRE(count == 5);
}
}
// =============================================
TEST_CASE("Reading OSM XML 200") {
SECTION("Direct") {
header_buffer_type r = read_xml("200-nodes");
REQUIRE(r.header.get("generator") == "testdata");
REQUIRE(r.buffer.committed() > 0);
REQUIRE(r.buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
REQUIRE(r.buffer.get<osmium::Node>(0).id() == 36966060);
REQUIRE(std::distance(r.buffer.begin(), r.buffer.end()) == 3);
}
SECTION("Using Reader") {
osmium::io::Reader reader(filename("200-nodes"));
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
REQUIRE(buffer.committed() > 0);
REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
REQUIRE(buffer.get<osmium::Node>(0).id() == 36966060);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
reader.close();
}
SECTION("Using Reader asking for nodes") {
osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::node);
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
REQUIRE(buffer.committed() > 0);
REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
REQUIRE(buffer.get<osmium::Node>(0).id() == 36966060);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
reader.close();
}
SECTION("Using Reader asking for header only") {
osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::nothing);
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
REQUIRE_THROWS({
reader.read();
});
reader.close();
}
SECTION("Using Reader asking for ways") {
osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::way);
osmium::io::Header header = reader.header();
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
REQUIRE(0 == buffer.committed());
REQUIRE(! buffer);
reader.close();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
#include <cstdlib>
#include <string>
inline std::string with_data_dir(const char* filename) {
const char* data_dir = getenv("OSMIUM_TEST_DATA_DIR");
std::string result;
if (data_dir) {
result = data_dir;
result += '/';
}
result += filename;
return result;
}

View File

@ -0,0 +1,42 @@
/*
* mkstemp.c
*
* Provides a trivial replacement for the POSIX `mkstemp()' function,
* suitable for use in MinGW (Win32) applications.
*
* This file is part of the MinGW32 package set.
*
* Contributed by Keith Marshall <keithmarshall@users.sourceforge.net>
* Patched to VS2013 by alex85k
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef WIN_MKSTEMP_H
#define WIN_MKSTEMP_H
#include <stdio.h>
#include <fcntl.h>
#include <share.h>
inline int mkstemp( char *templ )
{
int maxtry = 26, rtn = -1;
while( maxtry-- && (rtn < 0) )
{
char *r = _mktemp( templ );
if( r == NULL )
return -1;
rtn = sopen( r, O_RDWR | O_CREAT | O_EXCL | O_BINARY, SH_DENYRW, 0600 );
}
return rtn;
}
#endif

View File

@ -0,0 +1,25 @@
#include "catch.hpp"
#include <osmium/osm/area.hpp>
TEST_CASE("area_id") {
SECTION("object_id_to_area_id_conversion") {
REQUIRE( 46 == osmium::object_id_to_area_id( 23, osmium::item_type::way));
REQUIRE( 47 == osmium::object_id_to_area_id( 23, osmium::item_type::relation));
REQUIRE( 0 == osmium::object_id_to_area_id( 0, osmium::item_type::way));
REQUIRE( 1 == osmium::object_id_to_area_id( 0, osmium::item_type::relation));
REQUIRE(-24 == osmium::object_id_to_area_id(-12, osmium::item_type::way));
REQUIRE(-25 == osmium::object_id_to_area_id(-12, osmium::item_type::relation));
}
SECTION("area_id_to_object_id_conversion") {
REQUIRE( 23 == osmium::area_id_to_object_id( 46));
REQUIRE( 23 == osmium::area_id_to_object_id( 47));
REQUIRE( 0 == osmium::area_id_to_object_id( 0));
REQUIRE( 0 == osmium::area_id_to_object_id( 1));
REQUIRE(-12 == osmium::area_id_to_object_id(-24));
REQUIRE(-12 == osmium::area_id_to_object_id(-25));
}
}

View File

@ -0,0 +1,129 @@
#include "catch.hpp"
#include <osmium/area/detail/node_ref_segment.hpp>
using osmium::area::detail::NodeRefSegment;
TEST_CASE("NodeRefSegmentClass") {
SECTION("instantiation_with_default_parameters") {
NodeRefSegment s;
REQUIRE(s.first().ref() == 0);
REQUIRE(s.first().location() == osmium::Location());
REQUIRE(s.second().ref() == 0);
REQUIRE(s.second().location() == osmium::Location());
}
SECTION("instantiation") {
osmium::NodeRef nr1(1, { 1.2, 3.4 });
osmium::NodeRef nr2(2, { 1.4, 3.1 });
osmium::NodeRef nr3(3, { 1.2, 3.6 });
osmium::NodeRef nr4(4, { 1.2, 3.7 });
NodeRefSegment s1(nr1, nr2, nullptr, nullptr);
REQUIRE(s1.first().ref() == 1);
REQUIRE(s1.second().ref() == 2);
NodeRefSegment s2(nr2, nr3, nullptr, nullptr);
REQUIRE(s2.first().ref() == 3);
REQUIRE(s2.second().ref() == 2);
NodeRefSegment s3(nr3, nr4, nullptr, nullptr);
REQUIRE(s3.first().ref() == 3);
REQUIRE(s3.second().ref() == 4);
}
SECTION("intersection") {
NodeRefSegment s1({ 1, {0.0, 0.0}}, { 2, {2.0, 2.0}}, nullptr, nullptr);
NodeRefSegment s2({ 3, {0.0, 2.0}}, { 4, {2.0, 0.0}}, nullptr, nullptr);
NodeRefSegment s3({ 5, {2.0, 0.0}}, { 6, {4.0, 2.0}}, nullptr, nullptr);
NodeRefSegment s4({ 7, {1.0, 0.0}}, { 8, {3.0, 2.0}}, nullptr, nullptr);
NodeRefSegment s5({ 9, {0.0, 4.0}}, {10, {4.0, 0.0}}, nullptr, nullptr);
NodeRefSegment s6({11, {0.0, 0.0}}, {12, {1.0, 1.0}}, nullptr, nullptr);
NodeRefSegment s7({13, {1.0, 1.0}}, {14, {3.0, 3.0}}, nullptr, nullptr);
REQUIRE(calculate_intersection(s1, s2) == osmium::Location(1.0, 1.0));
REQUIRE(calculate_intersection(s1, s3) == osmium::Location());
REQUIRE(calculate_intersection(s2, s3) == osmium::Location());
REQUIRE(calculate_intersection(s1, s4) == osmium::Location());
REQUIRE(calculate_intersection(s1, s5) == osmium::Location(2.0, 2.0));
REQUIRE(calculate_intersection(s1, s1) == osmium::Location());
REQUIRE(calculate_intersection(s1, s6) == osmium::Location());
REQUIRE(calculate_intersection(s1, s7) == osmium::Location());
}
SECTION("intersection of very long segments") {
NodeRefSegment s1({ 1, {90.0, 90.0}}, { 2, {-90.0, -90.0}}, nullptr, nullptr);
NodeRefSegment s2({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
REQUIRE(calculate_intersection(s1, s2) == osmium::Location(0.0, 0.0));
NodeRefSegment s3({ 1, {-90.0, -90.0}}, { 2, {90.0, 90.0}}, nullptr, nullptr);
NodeRefSegment s4({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
REQUIRE(calculate_intersection(s3, s4) == osmium::Location(0.0, 0.0));
NodeRefSegment s5({ 1, {-90.0000001, -90.0}}, { 2, {90.0, 90.0}}, nullptr, nullptr);
NodeRefSegment s6({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
REQUIRE(calculate_intersection(s5, s6) == osmium::Location(0.0, 0.0));
}
SECTION("to_left_of") {
osmium::Location loc { 2.0, 2.0 };
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {4.0, 0.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {3.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {4.0, 3.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {2.0, 0.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {3.0, 1.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {3.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {2.0, 0.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {2.0, 0.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {2.0, 2.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 1.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {0.0, 1.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {1.0, 3.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {2.0, 0.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {3.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {1.0, 2.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {1.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 2.0}}, nullptr, nullptr).to_left_of(loc));
REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {0.0, 1.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
REQUIRE(NodeRefSegment({0, {2.0, 2.0}}, {1, {4.0, 0.0}}, nullptr, nullptr).to_left_of(loc) == false);
}
SECTION("ordering") {
osmium::NodeRef node_ref1(1, { 1.0, 3.0 });
osmium::NodeRef node_ref2(2, { 1.4, 2.9 });
osmium::NodeRef node_ref3(3, { 1.2, 3.0 });
osmium::NodeRef node_ref4(4, { 1.2, 3.3 });
REQUIRE(node_ref1 < node_ref2);
REQUIRE(node_ref2 < node_ref3);
REQUIRE(node_ref1 < node_ref3);
REQUIRE(node_ref1 >= node_ref1);
REQUIRE( osmium::location_less()(node_ref1, node_ref2));
REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
REQUIRE( osmium::location_less()(node_ref1, node_ref3));
REQUIRE( osmium::location_less()(node_ref3, node_ref4));
REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
}
}

View File

@ -0,0 +1,134 @@
#include "catch.hpp"
#include <sstream>
#include <boost/crc.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/crc.hpp>
#include <osmium/geom/relations.hpp>
TEST_CASE("Starting with default constructed box") {
osmium::Box b;
SECTION("default constructor creates invalid box") {
REQUIRE(!b);
REQUIRE(!b.bottom_left());
REQUIRE(!b.top_right());
REQUIRE_THROWS_AS(b.size(), osmium::invalid_location);
}
SECTION("extend with undefined") {
REQUIRE(!b);
b.extend(osmium::Location{});
REQUIRE(!b);
REQUIRE(!b.bottom_left());
REQUIRE(!b.top_right());
}
SECTION("extend with invalid") {
REQUIRE(!b);
b.extend(osmium::Location{200.0, 100.0});
REQUIRE(!b);
REQUIRE(!b.bottom_left());
REQUIRE(!b.top_right());
}
SECTION("extend with valid") {
osmium::Location loc1 { 1.2, 3.4 };
b.extend(loc1);
REQUIRE(!!b);
REQUIRE(!!b.bottom_left());
REQUIRE(!!b.top_right());
REQUIRE(b.contains(loc1));
osmium::Location loc2 { 3.4, 4.5 };
osmium::Location loc3 { 5.6, 7.8 };
b.extend(loc2);
b.extend(loc3);
REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
// extend with undefined doesn't change anything
b.extend(osmium::Location());
REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
REQUIRE(b.contains(loc1));
REQUIRE(b.contains(loc2));
REQUIRE(b.contains(loc3));
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(b);
REQUIRE(crc32().checksum() == 0xd381a838);
}
SECTION("output defined") {
b.extend(osmium::Location(1.2, 3.4));
b.extend(osmium::Location(5.6, 7.8));
std::stringstream out;
out << b;
REQUIRE(out.str() == "(1.2,3.4,5.6,7.8)");
REQUIRE(b.size() == Approx(19.36).epsilon(0.000001));
}
SECTION("output undefined") {
std::stringstream out;
out << b;
REQUIRE(out.str() == "(undefined)");
}
SECTION("output undefined bottom left") {
b.top_right() = osmium::Location(1.2, 3.4);
std::stringstream out;
out << b;
REQUIRE(out.str() == "(undefined)");
}
SECTION("output undefined top right") {
b.bottom_left() = osmium::Location(1.2, 3.4);
std::stringstream out;
out << b;
REQUIRE(out.str() == "(undefined)");
}
}
TEST_CASE("Create box from locations") {
osmium::Box b{osmium::Location{1.23, 2.34}, osmium::Location{3.45, 4.56}};
REQUIRE(!!b);
REQUIRE(b.bottom_left() == (osmium::Location{1.23, 2.34}));
REQUIRE(b.top_right() == (osmium::Location{3.45, 4.56}));
}
TEST_CASE("Create box from doubles") {
osmium::Box b{1.23, 2.34, 3.45, 4.56};
REQUIRE(!!b);
REQUIRE(b.bottom_left() == (osmium::Location{1.23, 2.34}));
REQUIRE(b.top_right() == (osmium::Location{3.45, 4.56}));
}
TEST_CASE("Relationship between boxes") {
osmium::Box outer;
outer.extend(osmium::Location(1, 1));
outer.extend(osmium::Location(10, 10));
osmium::Box inner;
inner.extend(osmium::Location(2, 2));
inner.extend(osmium::Location(4, 4));
osmium::Box overlap;
overlap.extend(osmium::Location(3, 3));
overlap.extend(osmium::Location(5, 5));
REQUIRE( osmium::geom::contains(inner, outer));
REQUIRE(!osmium::geom::contains(outer, inner));
REQUIRE(!osmium::geom::contains(overlap, inner));
REQUIRE(!osmium::geom::contains(inner, overlap));
}

View File

@ -0,0 +1,145 @@
#include "catch.hpp"
#include <boost/crc.hpp>
#include <osmium/builder/attr.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/crc.hpp>
using namespace osmium::builder::attr;
TEST_CASE("Build changeset") {
osmium::memory::Buffer buffer(10 * 1000);
osmium::builder::add_changeset(buffer,
_cid(42),
_created_at(time_t(100)),
_closed_at(time_t(200)),
_num_changes(7),
_num_comments(3),
_uid(9),
_user("user"),
_tag("comment", "foo")
);
const osmium::Changeset& cs1 = buffer.get<osmium::Changeset>(0);
REQUIRE(42 == cs1.id());
REQUIRE(9 == cs1.uid());
REQUIRE(7 == cs1.num_changes());
REQUIRE(3 == cs1.num_comments());
REQUIRE(true == cs1.closed());
REQUIRE(osmium::Timestamp(100) == cs1.created_at());
REQUIRE(osmium::Timestamp(200) == cs1.closed_at());
REQUIRE(1 == cs1.tags().size());
REQUIRE(std::string("user") == cs1.user());
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(cs1);
REQUIRE(crc32().checksum() == 0x502e8c0e);
auto pos = osmium::builder::add_changeset(buffer,
_cid(43),
_created_at(time_t(120)),
_num_changes(21),
_num_comments(0),
_uid(9),
_user("user"),
_tag("comment", "foo"),
_tag("foo", "bar"),
_comment({time_t(300), 10, "user2", "foo"}),
_comments({{time_t(400), 9, "user", "bar"}})
);
const osmium::Changeset& cs2 = buffer.get<osmium::Changeset>(pos);
REQUIRE(43 == cs2.id());
REQUIRE(9 == cs2.uid());
REQUIRE(21 == cs2.num_changes());
REQUIRE(0 == cs2.num_comments());
REQUIRE(false == cs2.closed());
REQUIRE(osmium::Timestamp(120) == cs2.created_at());
REQUIRE(osmium::Timestamp() == cs2.closed_at());
REQUIRE(2 == cs2.tags().size());
REQUIRE(std::string("user") == cs2.user());
REQUIRE(cs1 != cs2);
REQUIRE(cs1 < cs2);
REQUIRE(cs1 <= cs2);
REQUIRE(false == (cs1 > cs2));
REQUIRE(false == (cs1 >= cs2));
auto cit = cs2.discussion().begin();
REQUIRE(cit != cs2.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(300));
REQUIRE(cit->uid() == 10);
REQUIRE(std::string("user2") == cit->user());
REQUIRE(std::string("foo") == cit->text());
REQUIRE(++cit != cs2.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(400));
REQUIRE(cit->uid() == 9);
REQUIRE(std::string("user") == cit->user());
REQUIRE(std::string("bar") == cit->text());
REQUIRE(++cit == cs2.discussion().end());
}
TEST_CASE("Create changeset without helper") {
osmium::memory::Buffer buffer(10 * 1000);
osmium::builder::ChangesetBuilder builder(buffer);
osmium::Changeset& cs1 = builder.object();
cs1.set_id(42)
.set_created_at(100)
.set_closed_at(200)
.set_num_changes(7)
.set_num_comments(2)
.set_uid(9);
builder.add_user("user");
{
osmium::builder::TagListBuilder tl_builder(buffer, &builder);
tl_builder.add_tag("key1", "val1");
tl_builder.add_tag("key2", "val2");
}
{
osmium::builder::ChangesetDiscussionBuilder disc_builder(buffer, &builder);
disc_builder.add_comment(osmium::Timestamp(300), 10, "user2");
disc_builder.add_comment_text("foo");
disc_builder.add_comment(osmium::Timestamp(400), 9, "user");
disc_builder.add_comment_text("bar");
}
buffer.commit();
REQUIRE(42 == cs1.id());
REQUIRE(9 == cs1.uid());
REQUIRE(7 == cs1.num_changes());
REQUIRE(2 == cs1.num_comments());
REQUIRE(true == cs1.closed());
REQUIRE(osmium::Timestamp(100) == cs1.created_at());
REQUIRE(osmium::Timestamp(200) == cs1.closed_at());
REQUIRE(2 == cs1.tags().size());
REQUIRE(std::string("user") == cs1.user());
auto cit = cs1.discussion().begin();
REQUIRE(cit != cs1.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(300));
REQUIRE(cit->uid() == 10);
REQUIRE(std::string("user2") == cit->user());
REQUIRE(std::string("foo") == cit->text());
REQUIRE(++cit != cs1.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(400));
REQUIRE(cit->uid() == 9);
REQUIRE(std::string("user") == cit->user());
REQUIRE(std::string("bar") == cit->text());
REQUIRE(++cit == cs1.discussion().end());
}

View File

@ -0,0 +1,68 @@
#include "catch.hpp"
#include <boost/crc.hpp>
#include <osmium/osm/crc.hpp>
TEST_CASE("CRC of basic datatypes") {
osmium::CRC<boost::crc_32_type> crc32;
SECTION("Bool") {
crc32.update_bool(true);
crc32.update_bool(false);
REQUIRE(crc32().checksum() == 0x58c223be);
}
SECTION("Char") {
crc32.update_int8('x');
crc32.update_int8('y');
REQUIRE(crc32().checksum() == 0x8fe62899);
}
SECTION("Int16") {
crc32.update_int16(0x0123U);
crc32.update_int16(0x1234U);
REQUIRE(crc32().checksum() == 0xda923744);
}
SECTION("Int32") {
crc32.update_int32(0x01234567UL);
crc32.update_int32(0x12345678UL);
REQUIRE(crc32().checksum() == 0x9b4e2af3);
}
SECTION("Int64") {
crc32.update_int64(0x0123456789abcdefULL);
crc32.update_int64(0x123456789abcdef0ULL);
REQUIRE(crc32().checksum() == 0x6d8b7267);
}
SECTION("String") {
const char* str = "foobar";
crc32.update_string(str);
REQUIRE(crc32().checksum() == 0x9ef61f95);
}
SECTION("Timestamp") {
osmium::Timestamp t("2015-07-12T13:10:46Z");
crc32.update(t);
REQUIRE(crc32().checksum() == 0x58a29d7);
}
SECTION("Location") {
osmium::Location loc { 3.46, 2.001 };
crc32.update(loc);
REQUIRE(crc32().checksum() == 0xddee042c);
}
}

View File

@ -0,0 +1,31 @@
#include "catch.hpp"
#include <osmium/osm/entity_bits.hpp>
TEST_CASE("entity_bits") {
SECTION("can_be_set_and_checked") {
osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
REQUIRE(entities == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
entities |= osmium::osm_entity_bits::relation;
REQUIRE((entities & osmium::osm_entity_bits::object));
entities |= osmium::osm_entity_bits::area;
REQUIRE(entities == osmium::osm_entity_bits::object);
REQUIRE(! (entities & osmium::osm_entity_bits::changeset));
entities &= osmium::osm_entity_bits::node;
REQUIRE((entities & osmium::osm_entity_bits::node));
REQUIRE(! (entities & osmium::osm_entity_bits::way));
REQUIRE(entities == osmium::osm_entity_bits::node);
REQUIRE(osmium::osm_entity_bits::node == osmium::osm_entity_bits::from_item_type(osmium::item_type::node));
REQUIRE(osmium::osm_entity_bits::way == osmium::osm_entity_bits::from_item_type(osmium::item_type::way));
REQUIRE(osmium::osm_entity_bits::relation == osmium::osm_entity_bits::from_item_type(osmium::item_type::relation));
REQUIRE(osmium::osm_entity_bits::changeset == osmium::osm_entity_bits::from_item_type(osmium::item_type::changeset));
REQUIRE(osmium::osm_entity_bits::area == osmium::osm_entity_bits::from_item_type(osmium::item_type::area));
}
}

View File

@ -0,0 +1,154 @@
#include "catch.hpp"
#include <sstream>
#include <type_traits>
#include <osmium/osm/location.hpp>
TEST_CASE("Location") {
// fails on MSVC and doesn't really matter
// static_assert(std::is_literal_type<osmium::Location>::value, "osmium::Location not literal type");
SECTION("instantiation_with_default_parameters") {
osmium::Location loc;
REQUIRE(!loc);
REQUIRE_THROWS_AS(loc.lon(), osmium::invalid_location);
REQUIRE_THROWS_AS(loc.lat(), osmium::invalid_location);
}
SECTION("instantiation_with_double_parameters") {
osmium::Location loc1(1.2, 4.5);
REQUIRE(!!loc1);
REQUIRE(12000000 == loc1.x());
REQUIRE(45000000 == loc1.y());
REQUIRE(1.2 == loc1.lon());
REQUIRE(4.5 == loc1.lat());
osmium::Location loc2(loc1);
REQUIRE(4.5 == loc2.lat());
osmium::Location loc3 = loc1;
REQUIRE(4.5 == loc3.lat());
}
SECTION("instantiation_with_double_parameters_constructor_with_universal_initializer") {
osmium::Location loc { 2.2, 3.3 };
REQUIRE(2.2 == loc.lon());
REQUIRE(3.3 == loc.lat());
}
SECTION("instantiation_with_double_parameters_constructor_with_initializer_list") {
osmium::Location loc({ 4.4, 5.5 });
REQUIRE(4.4 == loc.lon());
REQUIRE(5.5 == loc.lat());
}
SECTION("instantiation_with_double_parameters_operator_equal") {
osmium::Location loc = { 5.5, 6.6 };
REQUIRE(5.5 == loc.lon());
REQUIRE(6.6 == loc.lat());
}
SECTION("equality") {
osmium::Location loc1(1.2, 4.5);
osmium::Location loc2(1.2, 4.5);
osmium::Location loc3(1.5, 1.5);
REQUIRE(loc1 == loc2);
REQUIRE(loc1 != loc3);
}
SECTION("order") {
REQUIRE(osmium::Location(-1.2, 10.0) < osmium::Location(1.2, 10.0));
REQUIRE(osmium::Location(1.2, 10.0) > osmium::Location(-1.2, 10.0));
REQUIRE(osmium::Location(10.2, 20.0) < osmium::Location(11.2, 20.2));
REQUIRE(osmium::Location(10.2, 20.2) < osmium::Location(11.2, 20.0));
REQUIRE(osmium::Location(11.2, 20.2) > osmium::Location(10.2, 20.0));
}
SECTION("validity") {
REQUIRE(osmium::Location(0.0, 0.0).valid());
REQUIRE(osmium::Location(1.2, 4.5).valid());
REQUIRE(osmium::Location(-1.2, 4.5).valid());
REQUIRE(osmium::Location(-180.0, -90.0).valid());
REQUIRE(osmium::Location(180.0, -90.0).valid());
REQUIRE(osmium::Location(-180.0, 90.0).valid());
REQUIRE(osmium::Location(180.0, 90.0).valid());
REQUIRE(!osmium::Location(200.0, 4.5).valid());
REQUIRE(!osmium::Location(-1.2, -100.0).valid());
REQUIRE(!osmium::Location(-180.0, 90.005).valid());
}
SECTION("output_to_iterator_comma_separator") {
char buffer[100];
osmium::Location loc(-3.2, 47.3);
*loc.as_string(buffer, ',') = 0;
REQUIRE(std::string("-3.2,47.3") == buffer);
}
SECTION("output_to_iterator_space_separator") {
char buffer[100];
osmium::Location loc(0.0, 7.0);
*loc.as_string(buffer, ' ') = 0;
REQUIRE(std::string("0 7") == buffer);
}
SECTION("output_to_iterator_check_precision") {
char buffer[100];
osmium::Location loc(-179.9999999, -90.0);
*loc.as_string(buffer, ' ') = 0;
REQUIRE(std::string("-179.9999999 -90") == buffer);
}
SECTION("output_to_iterator_undefined_location") {
char buffer[100];
osmium::Location loc;
REQUIRE_THROWS_AS(loc.as_string(buffer, ','), osmium::invalid_location);
}
SECTION("output_to_string_comman_separator") {
std::string s;
osmium::Location loc(-3.2, 47.3);
loc.as_string(std::back_inserter(s), ',');
REQUIRE(s == "-3.2,47.3");
}
SECTION("output_to_string_space_separator") {
std::string s;
osmium::Location loc(0.0, 7.0);
loc.as_string(std::back_inserter(s), ' ');
REQUIRE(s == "0 7");
}
SECTION("output_to_string_check_precision") {
std::string s;
osmium::Location loc(-179.9999999, -90.0);
loc.as_string(std::back_inserter(s), ' ');
REQUIRE(s == "-179.9999999 -90");
}
SECTION("output_to_string_undefined_location") {
std::string s;
osmium::Location loc;
REQUIRE_THROWS_AS(loc.as_string(std::back_inserter(s), ','), osmium::invalid_location);
}
SECTION("output_defined") {
osmium::Location p(-3.2, 47.3);
std::stringstream out;
out << p;
REQUIRE(out.str() == "(-3.2,47.3)");
}
SECTION("output_undefined") {
osmium::Location p;
std::stringstream out;
out << p;
REQUIRE(out.str() == "(undefined,undefined)");
}
}

View File

@ -0,0 +1,124 @@
#include "catch.hpp"
#include <boost/crc.hpp>
#include <osmium/builder/attr.hpp>
#include <osmium/osm/crc.hpp>
#include <osmium/osm/node.hpp>
using namespace osmium::builder::attr;
TEST_CASE("Build node") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_node(buffer,
_id(17),
_version(3),
_visible(true),
_cid(333),
_uid(21),
_timestamp(time_t(123)),
_user("foo"),
_tag("amenity", "pub"),
_tag("name", "OSM BAR"),
_location(3.5, 4.7)
);
osmium::Node& node = buffer.get<osmium::Node>(0);
REQUIRE(osmium::item_type::node == node.type());
REQUIRE(node.type_is_in(osmium::osm_entity_bits::node));
REQUIRE(node.type_is_in(osmium::osm_entity_bits::nwr));
REQUIRE(17l == node.id());
REQUIRE(17ul == node.positive_id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
REQUIRE(false == node.deleted());
REQUIRE(333 == node.changeset());
REQUIRE(21 == node.uid());
REQUIRE(std::string("foo") == node.user());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
REQUIRE(2 == node.tags().size());
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(node);
REQUIRE(crc32().checksum() == 0x7dc553f9);
node.set_visible(false);
REQUIRE(false == node.visible());
REQUIRE(true == node.deleted());
}
TEST_CASE("default values for node attributes") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_node(buffer, _id(0));
const osmium::Node& node = buffer.get<osmium::Node>(0);
REQUIRE(0l == node.id());
REQUIRE(0ul == node.positive_id());
REQUIRE(0 == node.version());
REQUIRE(true == node.visible());
REQUIRE(0 == node.changeset());
REQUIRE(0 == node.uid());
REQUIRE(std::string("") == node.user());
REQUIRE(0 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location() == node.location());
REQUIRE(0 == node.tags().size());
}
TEST_CASE("set node attributes from strings") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_node(buffer, _id(0));
osmium::Node& node = buffer.get<osmium::Node>(0);
node.set_id("-17")
.set_version("3")
.set_visible(true)
.set_changeset("333")
.set_uid("21");
REQUIRE(-17l == node.id());
REQUIRE(17ul == node.positive_id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
REQUIRE(333 == node.changeset());
REQUIRE(21 == node.uid());
}
TEST_CASE("set large id") {
osmium::memory::Buffer buffer(10000);
int64_t id = 3000000000l;
osmium::builder::add_node(buffer, _id(id));
osmium::Node& node = buffer.get<osmium::Node>(0);
REQUIRE(id == node.id());
REQUIRE(static_cast<osmium::unsigned_object_id_type>(id) == node.positive_id());
node.set_id(-id);
REQUIRE(-id == node.id());
REQUIRE(static_cast<osmium::unsigned_object_id_type>(id) == node.positive_id());
}
TEST_CASE("set tags on node") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_node(buffer,
_user("foo"),
_tag("amenity", "pub"),
_tag("name", "OSM BAR")
);
const osmium::Node& node = buffer.get<osmium::Node>(0);
REQUIRE(nullptr == node.tags().get_value_by_key("fail"));
REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity"));
REQUIRE(std::string("pub") == node.get_value_by_key("amenity"));
REQUIRE(std::string("default") == node.tags().get_value_by_key("fail", "default"));
REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity", "default"));
REQUIRE(std::string("pub") == node.get_value_by_key("amenity", "default"));
}

View File

@ -0,0 +1,109 @@
#include "catch.hpp"
#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
TEST_CASE("NodeRef") {
SECTION("instantiation_with_default_parameters") {
osmium::NodeRef node_ref;
REQUIRE(node_ref.ref() == 0);
// REQUIRE(!node_ref.has_location());
}
SECTION("instantiation_with_id") {
osmium::NodeRef node_ref(7);
REQUIRE(node_ref.ref() == 7);
}
SECTION("equality") {
osmium::NodeRef node_ref1(7, { 1.2, 3.4 });
osmium::NodeRef node_ref2(7, { 1.4, 3.1 });
osmium::NodeRef node_ref3(9, { 1.2, 3.4 });
REQUIRE(node_ref1 == node_ref2);
REQUIRE(node_ref1 != node_ref3);
REQUIRE(!osmium::location_equal()(node_ref1, node_ref2));
REQUIRE(!osmium::location_equal()(node_ref2, node_ref3));
REQUIRE(osmium::location_equal()(node_ref1, node_ref3));
}
SECTION("set_location") {
osmium::NodeRef node_ref(7);
REQUIRE(!node_ref.location().valid());
REQUIRE(node_ref.location() == osmium::Location());
node_ref.set_location(osmium::Location(13.5, -7.2));
REQUIRE(node_ref.location().lon() == 13.5);
REQUIRE(node_ref.location().valid());
}
SECTION("ordering") {
osmium::NodeRef node_ref1(1, { 1.0, 3.0 });
osmium::NodeRef node_ref2(2, { 1.4, 2.9 });
osmium::NodeRef node_ref3(3, { 1.2, 3.0 });
osmium::NodeRef node_ref4(4, { 1.2, 3.3 });
REQUIRE(node_ref1 < node_ref2);
REQUIRE(node_ref2 < node_ref3);
REQUIRE(node_ref1 < node_ref3);
REQUIRE(node_ref1 >= node_ref1);
REQUIRE(osmium::location_less()(node_ref1, node_ref2));
REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
REQUIRE(osmium::location_less()(node_ref1, node_ref3));
REQUIRE(osmium::location_less()(node_ref3, node_ref4));
REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
}
}
TEST_CASE("WayNodeList") {
osmium::memory::Buffer buffer(1024);
SECTION("Empty list") {
{
osmium::builder::WayNodeListBuilder builder(buffer);
}
REQUIRE(buffer.commit() == 0);
REQUIRE(buffer.committed( )> 0);
const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0);
REQUIRE(nrl.empty());
REQUIRE(nrl.size() == 0);
}
SECTION("Small area") {
osmium::builder::add_way_node_list(buffer, osmium::builder::attr::_nodes({
{ 1, {0, 0}},
{ 2, {0, 1}},
{ 3, {1, 1}},
{ 4, {1, 0}},
{ 1, {0, 0}},
}));
const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0);
REQUIRE_FALSE(nrl.empty());
REQUIRE(nrl.size() == 5);
REQUIRE(nrl.is_closed());
REQUIRE(nrl.ends_have_same_id());
REQUIRE(nrl.ends_have_same_location());
}
SECTION("Not an area") {
osmium::builder::add_way_node_list(buffer, osmium::builder::attr::_nodes({
{ 1, {0, 0}},
{ 2, {1, 0}},
{ 1, {0, 0}},
}));
const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0);
REQUIRE_FALSE(nrl.empty());
REQUIRE(nrl.size() == 3);
REQUIRE(nrl.is_closed());
REQUIRE(nrl.ends_have_same_id());
REQUIRE(nrl.ends_have_same_location());
}
}

View File

@ -0,0 +1,76 @@
#include "catch.hpp"
#include <osmium/builder/attr.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/object_comparisons.hpp>
TEST_CASE("Object_Comparisons") {
using namespace osmium::builder::attr;
SECTION("order") {
osmium::memory::Buffer buffer(10 * 1000);
osmium::builder::add_node(buffer, _id(10), _version(1));
osmium::builder::add_node(buffer, _id(15), _version(2));
auto it = buffer.begin();
osmium::Node& node1 = static_cast<osmium::Node&>(*it);
osmium::Node& node2 = static_cast<osmium::Node&>(*(++it));
REQUIRE(node1 < node2);
REQUIRE_FALSE(node1 > node2);
node1.set_id(20);
node1.set_version(1);
node2.set_id(20);
node2.set_version(2);
REQUIRE(node1 < node2);
REQUIRE_FALSE(node1 > node2);
node1.set_id(-10);
node1.set_version(2);
node2.set_id(-15);
node2.set_version(1);
REQUIRE(node1 < node2);
REQUIRE_FALSE(node1 > node2);
}
SECTION("order_types") {
osmium::memory::Buffer buffer(10 * 1000);
osmium::builder::add_node(buffer, _id(3), _version(3));
osmium::builder::add_node(buffer, _id(3), _version(4));
osmium::builder::add_node(buffer, _id(3), _version(4));
osmium::builder::add_way(buffer, _id(2), _version(2));
osmium::builder::add_relation(buffer, _id(1), _version(1));
auto it = buffer.begin();
const osmium::Node& node1 = static_cast<const osmium::Node&>(*it);
const osmium::Node& node2 = static_cast<const osmium::Node&>(*(++it));
const osmium::Node& node3 = static_cast<const osmium::Node&>(*(++it));
const osmium::Way& way = static_cast<const osmium::Way&>(*(++it));
const osmium::Relation& relation = static_cast<const osmium::Relation&>(*(++it));
REQUIRE(node1 < node2);
REQUIRE(node2 < way);
REQUIRE_FALSE(node2 > way);
REQUIRE(way < relation);
REQUIRE(node1 < relation);
REQUIRE(osmium::object_order_type_id_version()(node1, node2));
REQUIRE(osmium::object_order_type_id_reverse_version()(node2, node1));
REQUIRE(osmium::object_order_type_id_version()(node1, way));
REQUIRE(osmium::object_order_type_id_reverse_version()(node1, way));
REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, node2));
REQUIRE(osmium::object_equal_type_id_version()(node2, node3));
REQUIRE(osmium::object_equal_type_id()(node1, node2));
REQUIRE(osmium::object_equal_type_id()(node2, node3));
REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, way));
REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, relation));
REQUIRE_FALSE(osmium::object_equal_type_id()(node1, relation));
}
}

View File

@ -0,0 +1,75 @@
#include "catch.hpp"
#include <boost/crc.hpp>
#include <osmium/builder/attr.hpp>
#include <osmium/osm/crc.hpp>
#include <osmium/osm/relation.hpp>
using namespace osmium::builder::attr;
TEST_CASE("Build relation") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_relation(buffer,
_id(17),
_version(3),
_visible(),
_cid(333),
_uid(21),
_timestamp(time_t(123)),
_user("foo"),
_tag("type", "multipolygon"),
_tag("name", "Sherwood Forest"),
_member(osmium::item_type::way, 1, "inner"),
_member(osmium::item_type::way, 2, ""),
_member(osmium::item_type::way, 3, "outer")
);
const osmium::Relation& relation = buffer.get<osmium::Relation>(0);
REQUIRE(17 == relation.id());
REQUIRE(3 == relation.version());
REQUIRE(true == relation.visible());
REQUIRE(333 == relation.changeset());
REQUIRE(21 == relation.uid());
REQUIRE(std::string("foo") == relation.user());
REQUIRE(123 == uint32_t(relation.timestamp()));
REQUIRE(2 == relation.tags().size());
REQUIRE(3 == relation.members().size());
int n=1;
for (auto& member : relation.members()) {
REQUIRE(osmium::item_type::way == member.type());
REQUIRE(n == member.ref());
switch (n) {
case 1:
REQUIRE(std::string("inner") == member.role());
break;
case 2:
REQUIRE(std::string("") == member.role());
break;
case 3:
REQUIRE(std::string("outer") == member.role());
break;
default:
REQUIRE(false);
}
++n;
}
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(relation);
REQUIRE(crc32().checksum() == 0x2c2352e);
}
TEST_CASE("Member role too long") {
osmium::memory::Buffer buffer(10000);
osmium::builder::RelationMemberListBuilder builder(buffer);
const char role[2000] = "";
builder.add_member(osmium::item_type::node, 1, role, 1024);
REQUIRE_THROWS(builder.add_member(osmium::item_type::node, 1, role, 1025));
}

View File

@ -0,0 +1,77 @@
#include "catch.hpp"
#include <sstream>
#include <osmium/osm/timestamp.hpp>
TEST_CASE("Timestamp") {
SECTION("can be default initialized to invalid value") {
osmium::Timestamp t;
REQUIRE(0 == uint32_t(t));
REQUIRE("" == t.to_iso());
REQUIRE_FALSE(t.valid());
}
SECTION("invalid value is zero") {
osmium::Timestamp t(static_cast<time_t>(0));
REQUIRE(0 == uint32_t(t));
REQUIRE("" == t.to_iso());
REQUIRE_FALSE(t.valid());
}
SECTION("can be initialized from time_t") {
osmium::Timestamp t(static_cast<time_t>(1));
REQUIRE(1 == uint32_t(t));
REQUIRE("1970-01-01T00:00:01Z" == t.to_iso());
REQUIRE(t.valid());
}
SECTION("can be initialized from const char*") {
osmium::Timestamp t("2000-01-01T00:00:00Z");
REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
REQUIRE(t.valid());
}
SECTION("can be initialized from string") {
std::string s = "2000-01-01T00:00:00Z";
osmium::Timestamp t(s);
REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
REQUIRE(t.valid());
}
SECTION("throws if initialized from bad string") {
REQUIRE_THROWS_AS(osmium::Timestamp("x"), std::invalid_argument);
}
SECTION("can be explicitly cast to time_t") {
osmium::Timestamp t(4242);
time_t x = t.seconds_since_epoch();
REQUIRE(x == 4242);
}
SECTION("uint32_t can be initialized from Timestamp") {
osmium::Timestamp t(4242);
uint32_t x { t };
REQUIRE(x == 4242);
}
SECTION("can be compared") {
osmium::Timestamp t1(10);
osmium::Timestamp t2(50);
REQUIRE(t1 < t2);
REQUIRE(t1 > osmium::start_of_time());
REQUIRE(t2 > osmium::start_of_time());
REQUIRE(t1 < osmium::end_of_time());
REQUIRE(t2 < osmium::end_of_time());
}
SECTION("can be written to stream") {
std::stringstream ss;
osmium::Timestamp t(1);
ss << t;
REQUIRE("1970-01-01T00:00:01Z" == ss.str());
}
}

View File

@ -0,0 +1,90 @@
#include "catch.hpp"
#include <osmium/osm/types.hpp>
#include <osmium/osm/types_from_string.hpp>
TEST_CASE("set ID from string") {
REQUIRE(osmium::string_to_object_id("0") == 0);
REQUIRE(osmium::string_to_object_id("17") == 17);
REQUIRE(osmium::string_to_object_id("-17") == -17);
REQUIRE(osmium::string_to_object_id("01") == 1);
REQUIRE_THROWS_AS(osmium::string_to_object_id(""), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id(" "), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id(" 22"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("x"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("0x1"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("12a"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("12345678901234567890"), std::range_error);
}
TEST_CASE("set type and ID from string") {
auto n17 = osmium::string_to_object_id("n17", osmium::osm_entity_bits::nwr);
REQUIRE(n17.first == osmium::item_type::node);
REQUIRE(n17.second == 17);
auto w42 = osmium::string_to_object_id("w42", osmium::osm_entity_bits::nwr);
REQUIRE(w42.first == osmium::item_type::way);
REQUIRE(w42.second == 42);
auto r_2 = osmium::string_to_object_id("r-2", osmium::osm_entity_bits::nwr);
REQUIRE(r_2.first == osmium::item_type::relation);
REQUIRE(r_2.second == -2);
auto x3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr);
REQUIRE(x3.first == osmium::item_type::undefined);
REQUIRE(x3.second == 3);
REQUIRE_THROWS_AS(osmium::string_to_object_id("", osmium::osm_entity_bits::nwr), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("n", osmium::osm_entity_bits::nwr), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("x3", osmium::osm_entity_bits::nwr), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("nx3", osmium::osm_entity_bits::nwr), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("n3", osmium::osm_entity_bits::way), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_id("n3a", osmium::osm_entity_bits::nwr), std::range_error);
}
TEST_CASE("set object version from string") {
REQUIRE(osmium::string_to_object_version("0") == 0);
REQUIRE(osmium::string_to_object_version("1") == 1);
REQUIRE_THROWS_AS(osmium::string_to_object_version("-1"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_version(""), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_version(" "), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_version(" 22"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_object_version("x"), std::range_error);
}
TEST_CASE("set changeset id from string") {
REQUIRE(osmium::string_to_changeset_id("0") == 0);
REQUIRE(osmium::string_to_changeset_id("1") == 1);
REQUIRE_THROWS_AS(osmium::string_to_changeset_id("-1"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_changeset_id(""), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" "), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" 22"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_changeset_id("x"), std::range_error);
}
TEST_CASE("set user id from string") {
REQUIRE(osmium::string_to_user_id("0") == 0);
REQUIRE(osmium::string_to_user_id("1") == 1);
REQUIRE(osmium::string_to_user_id("-1") == -1);
REQUIRE_THROWS_AS(osmium::string_to_user_id("-2"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_user_id(""), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_user_id(" "), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_user_id(" 22"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_user_id("x"), std::range_error);
}
TEST_CASE("set num changes from string") {
REQUIRE(osmium::string_to_num_changes("0") == 0);
REQUIRE(osmium::string_to_num_changes("1") == 1);
REQUIRE_THROWS_AS(osmium::string_to_num_changes("-1"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_num_changes(""), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_num_changes(" "), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_num_changes(" 22"), std::range_error);
REQUIRE_THROWS_AS(osmium::string_to_num_changes("x"), std::range_error);
}

View File

@ -0,0 +1,95 @@
#include "catch.hpp"
#include <boost/crc.hpp>
#include <osmium/builder/attr.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm/crc.hpp>
#include <osmium/osm/way.hpp>
using namespace osmium::builder::attr;
TEST_CASE("Build way") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_way(buffer,
_id(17),
_version(3),
_visible(true),
_cid(333),
_uid(21),
_timestamp(time_t(123)),
_user("foo"),
_tag("highway", "residential"),
_tag("name", "High Street"),
_nodes({1, 3, 2})
);
const osmium::Way& way = buffer.get<osmium::Way>(0);
REQUIRE(osmium::item_type::way == way.type());
REQUIRE(way.type_is_in(osmium::osm_entity_bits::way));
REQUIRE(way.type_is_in(osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
REQUIRE(17 == way.id());
REQUIRE(3 == way.version());
REQUIRE(true == way.visible());
REQUIRE(333 == way.changeset());
REQUIRE(21 == way.uid());
REQUIRE(std::string("foo") == way.user());
REQUIRE(123 == uint32_t(way.timestamp()));
REQUIRE(2 == way.tags().size());
REQUIRE(3 == way.nodes().size());
REQUIRE(1 == way.nodes()[0].ref());
REQUIRE(3 == way.nodes()[1].ref());
REQUIRE(2 == way.nodes()[2].ref());
REQUIRE(! way.is_closed());
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(way);
REQUIRE(crc32().checksum() == 0x7676d0c2);
}
TEST_CASE("build closed way") {
osmium::memory::Buffer buffer(10000);
osmium::builder::add_way(buffer,
_tag("highway", "residential"),
_tag("name", "High Street"),
_nodes({1, 3, 1})
);
const osmium::Way& way = buffer.get<osmium::Way>(0);
REQUIRE(way.is_closed());
}
TEST_CASE("build way with helpers") {
osmium::memory::Buffer buffer(10000);
{
osmium::builder::WayBuilder builder(buffer);
builder.add_user("username");
builder.add_tags({
{"amenity", "restaurant"},
{"name", "Zum goldenen Schwanen"}
});
builder.add_node_refs({
{22, {3.5, 4.7}},
{67, {4.1, 2.2}}
});
}
buffer.commit();
const osmium::Way& way = buffer.get<osmium::Way>(0);
REQUIRE(std::string("username") == way.user());
REQUIRE(2 == way.tags().size());
REQUIRE(std::string("amenity") == way.tags().begin()->key());
REQUIRE(std::string("Zum goldenen Schwanen") == way.tags()["name"]);
REQUIRE(2 == way.nodes().size());
REQUIRE(22 == way.nodes()[0].ref());
REQUIRE(4.1 == way.nodes()[1].location().lon());
}

View File

@ -0,0 +1,34 @@
#include "catch.hpp"
#include <osmium/memory/buffer.hpp>
TEST_CASE("Buffer basics") {
osmium::memory::Buffer invalid_buffer1;
osmium::memory::Buffer invalid_buffer2;
osmium::memory::Buffer empty_buffer1(1024);
osmium::memory::Buffer empty_buffer2(2048);
REQUIRE(!invalid_buffer1);
REQUIRE(!invalid_buffer2);
REQUIRE(empty_buffer1);
REQUIRE(empty_buffer2);
REQUIRE(invalid_buffer1 == invalid_buffer2);
REQUIRE(invalid_buffer1 != empty_buffer1);
REQUIRE(empty_buffer1 != empty_buffer2);
REQUIRE(invalid_buffer1.capacity() == 0);
REQUIRE(invalid_buffer1.written() == 0);
REQUIRE(invalid_buffer1.committed() == 0);
REQUIRE(empty_buffer1.capacity() == 1024);
REQUIRE(empty_buffer1.written() == 0);
REQUIRE(empty_buffer1.committed() == 0);
REQUIRE(empty_buffer2.capacity() == 2048);
REQUIRE(empty_buffer2.written() == 0);
REQUIRE(empty_buffer2.committed() == 0);
}

View File

@ -0,0 +1,199 @@
#include "catch.hpp"
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm/node.hpp>
void check_node_1(osmium::Node& node) {
REQUIRE(1 == node.id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
REQUIRE(333 == node.changeset());
REQUIRE(21 == node.uid());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
REQUIRE(std::string("testuser") == node.user());
for (osmium::memory::Item& item : node) {
REQUIRE(osmium::item_type::tag_list == item.type());
}
REQUIRE(node.tags().begin() == node.tags().end());
REQUIRE(node.tags().empty());
REQUIRE(0 == std::distance(node.tags().begin(), node.tags().end()));
}
void check_node_2(osmium::Node& node) {
REQUIRE(2 == node.id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
REQUIRE(333 == node.changeset());
REQUIRE(21 == node.uid());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
REQUIRE(std::string("testuser") == node.user());
for (osmium::memory::Item& item : node) {
REQUIRE(osmium::item_type::tag_list == item.type());
}
REQUIRE(!node.tags().empty());
REQUIRE(2 == std::distance(node.tags().begin(), node.tags().end()));
int n = 0;
for (const osmium::Tag& tag : node.tags()) {
switch (n) {
case 0:
REQUIRE(std::string("amenity") == tag.key());
REQUIRE(std::string("bank") == tag.value());
break;
case 1:
REQUIRE(std::string("name") == tag.key());
REQUIRE(std::string("OSM Savings") == tag.value());
break;
}
++n;
}
REQUIRE(2 == n);
}
TEST_CASE("Node in Buffer") {
constexpr size_t buffer_size = 10000;
unsigned char data[buffer_size];
osmium::memory::Buffer buffer(data, buffer_size, 0);
SECTION("Add node to buffer") {
{
// add node 1
osmium::builder::NodeBuilder node_builder(buffer);
osmium::Node& node = node_builder.object();
REQUIRE(osmium::item_type::node == node.type());
node.set_id(1);
node.set_version(3);
node.set_visible(true);
node.set_changeset(333);
node.set_uid(21);
node.set_timestamp(123);
node.set_location(osmium::Location(3.5, 4.7));
node_builder.add_user("testuser");
buffer.commit();
}
{
// add node 2
osmium::builder::NodeBuilder node_builder(buffer);
osmium::Node& node = node_builder.object();
REQUIRE(osmium::item_type::node == node.type());
node.set_id(2);
node.set_version(3);
node.set_visible(true);
node.set_changeset(333);
node.set_uid(21);
node.set_timestamp(123);
node.set_location(osmium::Location(3.5, 4.7));
node_builder.add_user("testuser");
{
osmium::builder::TagListBuilder tag_builder(buffer, &node_builder);
tag_builder.add_tag("amenity", "bank");
tag_builder.add_tag("name", "OSM Savings");
}
buffer.commit();
}
REQUIRE(2 == std::distance(buffer.begin(), buffer.end()));
int item_no = 0;
for (osmium::memory::Item& item : buffer) {
REQUIRE(osmium::item_type::node == item.type());
osmium::Node& node = static_cast<osmium::Node&>(item);
switch (item_no) {
case 0:
check_node_1(node);
break;
case 1:
check_node_2(node);
break;
default:
break;
}
++item_no;
}
}
SECTION("Add buffer to another one") {
{
// add node 1
osmium::builder::NodeBuilder node_builder(buffer);
osmium::Node& node = node_builder.object();
REQUIRE(osmium::item_type::node == node.type());
node.set_id(1);
node.set_version(3);
node.set_visible(true);
node.set_changeset(333);
node.set_uid(21);
node.set_timestamp(123);
node.set_location(osmium::Location(3.5, 4.7));
node_builder.add_user("testuser");
buffer.commit();
}
osmium::memory::Buffer buffer2(buffer_size, osmium::memory::Buffer::auto_grow::yes);
buffer2.add_buffer(buffer);
buffer2.commit();
REQUIRE(buffer.committed() == buffer2.committed());
const osmium::Node& node = buffer2.get<osmium::Node>(0);
REQUIRE(node.id() == 1);
REQUIRE(123 == uint32_t(node.timestamp()));
}
SECTION("Use back_inserter on buffer") {
{
// add node 1
osmium::builder::NodeBuilder node_builder(buffer);
osmium::Node& node = node_builder.object();
REQUIRE(osmium::item_type::node == node.type());
node.set_id(1);
node.set_version(3);
node.set_visible(true);
node.set_changeset(333);
node.set_uid(21);
node.set_timestamp(123);
node.set_location(osmium::Location(3.5, 4.7));
node_builder.add_user("testuser");
buffer.commit();
}
osmium::memory::Buffer buffer2(buffer_size, osmium::memory::Buffer::auto_grow::yes);
std::copy(buffer.begin(), buffer.end(), std::back_inserter(buffer2));
REQUIRE(buffer.committed() == buffer2.committed());
const osmium::Node& node = buffer2.get<osmium::Node>(0);
REQUIRE(node.id() == 1);
REQUIRE(123 == uint32_t(node.timestamp()));
}
}

View File

@ -0,0 +1,186 @@
#include "catch.hpp"
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm/node.hpp>
struct CallbackClass {
int count = 0;
void moving_in_buffer(size_t old_offset, size_t new_offset) {
REQUIRE(old_offset > new_offset);
++count;
}
}; // struct CallbackClass
TEST_CASE("Purge data from buffer") {
constexpr size_t buffer_size = 10000;
SECTION("purge empty buffer") {
osmium::memory::Buffer buffer(buffer_size);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 0);
REQUIRE(buffer.committed() == 0);
}
SECTION("purge buffer with one object but nothing to delete") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
size_t committed = buffer.committed();
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 0);
REQUIRE(committed == buffer.committed());
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
}
SECTION("purge buffer with one object which gets deleted") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
node_builder.object().set_removed(true);
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 0);
REQUIRE(buffer.committed() == 0);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
}
SECTION("purge buffer with two objects, first gets deleted") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
node_builder.object().set_removed(true);
}
buffer.commit();
size_t size1 = buffer.committed();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
}
buffer.commit();
size_t size2 = buffer.committed() - size1;
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 1);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
REQUIRE(buffer.committed() == size2);
}
SECTION("purge buffer with two objects, second gets deleted") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser_longer_name");
}
buffer.commit();
size_t size1 = buffer.committed();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
node_builder.object().set_removed(true);
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 0);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
REQUIRE(buffer.committed() == size1);
}
SECTION("purge buffer with three objects, middle one gets deleted") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser_longer_name");
}
buffer.commit();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
node_builder.object().set_removed(true);
}
buffer.commit();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("sn");
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 1);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
}
SECTION("purge buffer with three objects, all get deleted") {
osmium::memory::Buffer buffer(buffer_size);
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser_longer_name");
node_builder.object().set_removed(true);
}
buffer.commit();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("testuser");
node_builder.object().set_removed(true);
}
buffer.commit();
{
osmium::builder::NodeBuilder node_builder(buffer);
node_builder.add_user("sn");
node_builder.object().set_removed(true);
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
CallbackClass callback;
buffer.purge_removed(&callback);
REQUIRE(callback.count == 0);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
}
}

View File

@ -0,0 +1,567 @@
#include "catch.hpp"
#include <cstdint>
#include <initializer_list>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/types.hpp>
TEST_CASE("create node using builders") {
using namespace osmium::builder::attr;
osmium::memory::Buffer buffer(1024*10);
SECTION("add node with only id") {
const auto pos = osmium::builder::add_node(buffer, _id(22));
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 22);
REQUIRE(node.version() == 0);
REQUIRE(node.timestamp() == osmium::Timestamp{});
REQUIRE(node.changeset() == 0);
REQUIRE(node.uid() == 0);
REQUIRE(std::string(node.user()) == "");
REQUIRE(node.location() == osmium::Location{});
REQUIRE(node.tags().size() == 0);
}
SECTION("add node with complete info but no tags") {
const auto loc = osmium::Location(3.14, 1.59);
const auto pos = osmium::builder::add_node(buffer,
_id(1),
_version(17),
_timestamp(osmium::Timestamp("2015-01-01T10:20:30Z")),
_cid(21),
_uid(222),
_location(loc),
_user("foo")
);
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 1);
REQUIRE(node.version() == 17);
REQUIRE(node.timestamp() == osmium::Timestamp{"2015-01-01T10:20:30Z"});
REQUIRE(node.changeset() == 21);
REQUIRE(node.uid() == 222);
REQUIRE(std::string(node.user()) == "foo");
REQUIRE(node.location() == loc);
REQUIRE(node.tags().size() == 0);
REQUIRE(std::distance(node.cbegin(), node.cend()) == 0);
}
SECTION("visible/deleted flag") {
osmium::builder::add_node(buffer, _id(1), _deleted());
osmium::builder::add_node(buffer, _id(2), _deleted(true));
osmium::builder::add_node(buffer, _id(3), _deleted(false));
osmium::builder::add_node(buffer, _id(4), _visible());
osmium::builder::add_node(buffer, _id(5), _visible(true));
osmium::builder::add_node(buffer, _id(6), _visible(false));
auto it = buffer.cbegin<osmium::Node>();
REQUIRE_FALSE(it++->visible());
REQUIRE_FALSE(it++->visible());
REQUIRE(it++->visible());
REQUIRE(it++->visible());
REQUIRE(it++->visible());
REQUIRE_FALSE(it++->visible());
REQUIRE(it == buffer.cend<osmium::Node>());
}
SECTION("order of attributes doesn't matter") {
const auto loc = osmium::Location(3.14, 1.59);
const auto pos = osmium::builder::add_node(buffer,
_timestamp("2015-01-01T10:20:30Z"),
_version(17),
_cid(21),
_uid(222),
_user(std::string("foo")),
_id(1),
_location(3.14, 1.59)
);
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 1);
REQUIRE(node.version() == 17);
REQUIRE(node.timestamp() == osmium::Timestamp{"2015-01-01T10:20:30Z"});
REQUIRE(node.changeset() == 21);
REQUIRE(node.uid() == 222);
REQUIRE(std::string(node.user()) == "foo");
REQUIRE(node.location() == loc);
REQUIRE(node.tags().size() == 0);
}
SECTION("add tags using _tag") {
std::pair<const char*, const char*> t1 = {"name", "Node Inn"};
std::pair<std::string, std::string> t2 = {"phone", "+1-123-555-4567"};
const auto pos = osmium::builder::add_node(buffer,
_id(2),
_tag("amenity", "restaurant"),
_tag(t1),
_tag(t2),
_tag(std::string{"cuisine"}, std::string{"italian"})
);
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 2);
REQUIRE(node.tags().size() == 4);
REQUIRE(std::distance(node.cbegin(), node.cend()) == 1);
auto it = node.tags().cbegin();
REQUIRE(std::string(it->key()) == "amenity");
REQUIRE(std::string(it->value()) == "restaurant");
++it;
REQUIRE(std::string(it->key()) == "name");
REQUIRE(std::string(it->value()) == "Node Inn");
++it;
REQUIRE(std::string(it->key()) == "phone");
REQUIRE(std::string(it->value()) == "+1-123-555-4567");
++it;
REQUIRE(std::string(it->key()) == "cuisine");
REQUIRE(std::string(it->value()) == "italian");
++it;
REQUIRE(it == node.tags().cend());
}
SECTION("add tags using _tags from initializer list") {
const auto pos = osmium::builder::add_node(buffer,
_id(3),
_tags({{"amenity", "post_box"}})
);
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 3);
REQUIRE(node.tags().size() == 1);
auto it = node.tags().cbegin();
REQUIRE(std::string(it->key()) == "amenity");
REQUIRE(std::string(it->value()) == "post_box");
++it;
REQUIRE(it == node.tags().cend());
REQUIRE(std::distance(node.cbegin(), node.cend()) == 1);
}
SECTION("add tags using _tags from TagList") {
const auto pos1 = osmium::builder::add_node(buffer,
_id(3),
_tag("a", "d"),
_tag("b", "e"),
_tag("c", "f")
);
const auto& node1 = buffer.get<osmium::Node>(pos1);
const auto pos2 = osmium::builder::add_node(buffer,
_id(4),
_tags(node1.tags())
);
const auto& node2 = buffer.get<osmium::Node>(pos2);
REQUIRE(node2.id() == 4);
REQUIRE(node2.tags().size() == 3);
auto it = node2.tags().cbegin();
REQUIRE(std::string(it++->key()) == "a");
REQUIRE(std::string(it++->key()) == "b");
REQUIRE(std::string(it++->key()) == "c");
REQUIRE(it == node2.tags().cend());
REQUIRE(std::distance(node2.cbegin(), node2.cend()) == 1);
}
SECTION("add tags using mixed tag sources") {
const std::vector<pair_of_cstrings> tags = {
{"t5", "t5"},
{"t6", "t6"}
};
const auto pos = osmium::builder::add_node(buffer,
_id(4),
_tag("t1", "t1"),
_tags({{"t2", "t2"}, {"t3", "t3"}}),
_tag("t4", "t4"),
_tags(tags)
);
const auto& node = buffer.get<osmium::Node>(pos);
REQUIRE(node.id() == 4);
REQUIRE(node.tags().size() == 6);
auto it = node.tags().cbegin();
REQUIRE(std::string(it->key()) == "t1");
++it;
REQUIRE(std::string(it->key()) == "t2");
++it;
REQUIRE(std::string(it->key()) == "t3");
++it;
REQUIRE(std::string(it->key()) == "t4");
++it;
REQUIRE(std::string(it->key()) == "t5");
++it;
REQUIRE(std::string(it->key()) == "t6");
++it;
REQUIRE(it == node.tags().cend());
REQUIRE(std::distance(node.cbegin(), node.cend()) == 1);
}
}
TEST_CASE("create way using builders") {
using namespace osmium::builder::attr;
osmium::memory::Buffer buffer(1024*10);
SECTION("add way without nodes") {
const auto pos = osmium::builder::add_way(buffer,
_id(999),
_cid(21),
_uid(222),
_user("foo")
);
const auto& way = buffer.get<osmium::Way>(pos);
REQUIRE(way.id() == 999);
REQUIRE(way.version() == 0);
REQUIRE(way.timestamp() == osmium::Timestamp{});
REQUIRE(way.changeset() == 21);
REQUIRE(way.uid() == 222);
REQUIRE(std::string(way.user()) == "foo");
REQUIRE(way.tags().size() == 0);
REQUIRE(way.nodes().size() == 0);
REQUIRE(std::distance(way.cbegin(), way.cend()) == 0);
}
}
TEST_CASE("create way with nodes") {
std::vector<osmium::NodeRef> nrvec = {
{ 1, osmium::Location{1.1, 0.1} },
{ 2, osmium::Location{2.2, 0.2} },
{ 4, osmium::Location{4.4, 0.4} },
{ 8, osmium::Location{8.8, 0.8} }
};
using namespace osmium::builder::attr;
osmium::memory::Buffer wbuffer(1024*10);
osmium::builder::add_way(wbuffer,
_id(1),
_nodes({1, 2, 4, 8})
);
const osmium::NodeRefList& nodes = wbuffer.get<osmium::Way>(0).nodes();
osmium::memory::Buffer buffer(1024*10);
SECTION("add nodes using an OSM object id or NodeRef") {
osmium::builder::add_way(buffer,
_id(1),
_node(1),
_node(2),
_node(osmium::NodeRef{4}),
_node(8)
);
}
SECTION("add nodes using iterator list with object ids") {
osmium::builder::add_way(buffer,
_id(1),
_nodes({1, 2, 4, 8})
);
}
SECTION("add way with nodes in initializer_list of NodeRefs") {
osmium::builder::add_way(buffer,
_id(1),
_nodes({
{ 1, {1.1, 0.1} },
{ 2, {2.2, 0.2} },
{ 4, {4.4, 0.4} },
{ 8, {8.8, 0.8} }
})
);
}
SECTION("add nodes using WayNodeList") {
osmium::builder::add_way(buffer,
_id(1),
_nodes(nodes)
);
}
SECTION("add nodes using vector of OSM object ids") {
const std::vector<osmium::object_id_type> some_nodes = {
1, 2, 4, 8
};
osmium::builder::add_way(buffer,
_id(1),
_nodes(some_nodes)
);
}
SECTION("add nodes using vector of NodeRefs") {
osmium::builder::add_way(buffer,
_id(1),
_nodes(nrvec)
);
}
SECTION("add nodes using different means together") {
osmium::builder::add_way(buffer,
_id(1),
_node(1),
_nodes({2, 4}),
_node(8)
);
}
SECTION("add nodes using different means together") {
osmium::builder::add_way(buffer,
_id(1),
_nodes(nodes.begin(), nodes.begin() + 1),
_nodes({2, 4, 8})
);
}
const auto& way = buffer.get<osmium::Way>(0);
REQUIRE(way.id() == 1);
REQUIRE(way.nodes().size() == 4);
REQUIRE(std::distance(way.cbegin(), way.cend()) == 1);
auto it = way.nodes().cbegin();
REQUIRE(it->ref() == 1);
if (it->location().valid()) {
REQUIRE(*it == nrvec[0]);
}
it++;
REQUIRE(it->ref() == 2);
if (it->location().valid()) {
REQUIRE(*it == nrvec[1]);
}
it++;
REQUIRE(it->ref() == 4);
if (it->location().valid()) {
REQUIRE(*it == nrvec[2]);
}
it++;
REQUIRE(it->ref() == 8);
if (it->location().valid()) {
REQUIRE(*it == nrvec[3]);
}
it++;
REQUIRE(it == way.nodes().cend());
}
TEST_CASE("create relation using builders") {
using namespace osmium::builder::attr;
osmium::memory::Buffer buffer(1024*10);
SECTION("create relation") {
osmium::builder::attr::member_type m{osmium::item_type::way, 113, "inner"};
osmium::builder::add_relation(buffer,
_id(123),
_member(osmium::item_type::node, 123, ""),
_member(osmium::item_type::node, 132),
_member(osmium::item_type::way, 111, "outer"),
_member(osmium::builder::attr::member_type{osmium::item_type::way, 112, "inner"}),
_member(m)
);
const auto& relation = buffer.get<osmium::Relation>(0);
REQUIRE(relation.id() == 123);
REQUIRE(relation.members().size() == 5);
REQUIRE(std::distance(relation.cbegin(), relation.cend()) == 1);
auto it = relation.members().begin();
REQUIRE(it->type() == osmium::item_type::node);
REQUIRE(it->ref() == 123);
REQUIRE(std::string(it->role()) == "");
++it;
REQUIRE(it->type() == osmium::item_type::node);
REQUIRE(it->ref() == 132);
REQUIRE(std::string(it->role()) == "");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 111);
REQUIRE(std::string(it->role()) == "outer");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 112);
REQUIRE(std::string(it->role()) == "inner");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 113);
REQUIRE(std::string(it->role()) == "inner");
++it;
REQUIRE(it == relation.members().end());
}
SECTION("create relation member from existing relation member") {
osmium::builder::add_relation(buffer,
_id(123),
_member(osmium::item_type::way, 111, "outer"),
_member(osmium::item_type::way, 112, "inner")
);
const auto& relation1 = buffer.get<osmium::Relation>(0);
const auto pos = osmium::builder::add_relation(buffer,
_id(124),
_member(*relation1.members().begin()),
_members(std::next(relation1.members().begin()), relation1.members().end())
);
const auto& relation = buffer.get<osmium::Relation>(pos);
REQUIRE(relation.id() == 124);
REQUIRE(relation.members().size() == 2);
auto it = relation.members().begin();
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 111);
REQUIRE(std::string(it->role()) == "outer");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 112);
REQUIRE(std::string(it->role()) == "inner");
++it;
REQUIRE(it == relation.members().end());
}
SECTION("create relation with members from initializer list") {
const auto pos = osmium::builder::add_relation(buffer,
_id(123),
_members({
{osmium::item_type::node, 123, ""},
{osmium::item_type::way, 111, "outer"}
})
);
const auto& relation = buffer.get<osmium::Relation>(pos);
REQUIRE(relation.id() == 123);
REQUIRE(relation.members().size() == 2);
REQUIRE(std::distance(relation.cbegin(), relation.cend()) == 1);
auto it = relation.members().begin();
REQUIRE(it->type() == osmium::item_type::node);
REQUIRE(it->ref() == 123);
REQUIRE(std::string(it->role()) == "");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 111);
REQUIRE(std::string(it->role()) == "outer");
++it;
REQUIRE(it == relation.members().end());
}
SECTION("create relation with members from iterators and some tags") {
const std::vector<member_type> members = {
{osmium::item_type::node, 123},
{osmium::item_type::way, 111, "outer"}
};
SECTION("using iterators") {
osmium::builder::add_relation(buffer,
_id(123),
_members(members.begin(), members.end()),
_tag("a", "x"),
_tag("b", "y")
);
}
SECTION("using container") {
osmium::builder::add_relation(buffer,
_id(123),
_members(members),
_tag("a", "x"),
_tag("b", "y")
);
}
const auto& relation = buffer.get<osmium::Relation>(0);
REQUIRE(relation.id() == 123);
REQUIRE(relation.members().size() == 2);
REQUIRE(relation.tags().size() == 2);
REQUIRE(std::distance(relation.cbegin(), relation.cend()) == 2);
auto it = relation.members().begin();
REQUIRE(it->type() == osmium::item_type::node);
REQUIRE(it->ref() == 123);
REQUIRE(std::string(it->role()) == "");
++it;
REQUIRE(it->type() == osmium::item_type::way);
REQUIRE(it->ref() == 111);
REQUIRE(std::string(it->role()) == "outer");
++it;
REQUIRE(it == relation.members().end());
}
}
TEST_CASE("create area using builders") {
using namespace osmium::builder::attr;
osmium::memory::Buffer buffer(1024*10);
SECTION("add area without rings") {
const auto pos = osmium::builder::add_area(buffer,
_id(999),
_cid(21),
_uid(222),
_user("foo"),
_tag("landuse", "residential")
);
const auto& area = buffer.get<osmium::Area>(pos);
REQUIRE(area.id() == 999);
REQUIRE(area.version() == 0);
REQUIRE(area.timestamp() == osmium::Timestamp{});
REQUIRE(area.changeset() == 21);
REQUIRE(area.uid() == 222);
REQUIRE(std::string(area.user()) == "foo");
REQUIRE(area.tags().size() == 1);
REQUIRE(std::distance(area.cbegin(), area.cend()) == 1);
}
}

View File

@ -0,0 +1,81 @@
#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/area.hpp>
using namespace osmium::builder::attr;
inline const osmium::Area& create_test_area_1outer_0inner(osmium::memory::Buffer& buffer) {
osmium::builder::add_area(buffer,
_user("foo"),
_tag("building", "true"),
_outer_ring({
{1, {3.2, 4.2}},
{2, {3.5, 4.7}},
{3, {3.6, 4.9}},
{1, {3.2, 4.2}}
})
);
return buffer.get<osmium::Area>(0);
}
inline const osmium::Area& create_test_area_1outer_1inner(osmium::memory::Buffer& buffer) {
osmium::builder::add_area(buffer,
_user("foo"),
_tag("building", "true"),
_outer_ring({
{1, {0.1, 0.1}},
{2, {9.1, 0.1}},
{3, {9.1, 9.1}},
{4, {0.1, 9.1}},
{1, {0.1, 0.1}}
}),
_inner_ring({
{5, {1.0, 1.0}},
{6, {8.0, 1.0}},
{7, {8.0, 8.0}},
{8, {1.0, 8.0}},
{5, {1.0, 1.0}}
})
);
return buffer.get<osmium::Area>(0);
}
inline const osmium::Area& create_test_area_2outer_2inner(osmium::memory::Buffer& buffer) {
osmium::builder::add_area(buffer,
_user("foo"),
_tag("building", "true"),
_outer_ring({
{1, {0.1, 0.1}},
{2, {9.1, 0.1}},
{3, {9.1, 9.1}},
{4, {0.1, 9.1}},
{1, {0.1, 0.1}}
}),
_inner_ring({
{5, {1.0, 1.0}},
{6, {4.0, 1.0}},
{7, {4.0, 4.0}},
{8, {1.0, 4.0}},
{5, {1.0, 1.0}}
}),
_inner_ring({
{10, {5.0, 5.0}},
{11, {5.0, 7.0}},
{12, {7.0, 7.0}},
{10, {5.0, 5.0}}
}),
_outer_ring({
{100, {10.0, 10.0}},
{101, {11.0, 10.0}},
{102, {11.0, 11.0}},
{103, {10.0, 11.0}},
{100, {10.0, 10.0}}
})
);
return buffer.get<osmium::Area>(0);
}

View File

@ -0,0 +1,15 @@
#ifndef TEST_GEOM_HELPER_HPP
#define TEST_GEOM_HELPER_HPP
#include <string>
#include <geos/io/WKBWriter.h>
inline std::string geos_to_wkb(const geos::geom::Geometry* geometry) {
std::stringstream ss;
geos::io::WKBWriter wkb_writer;
wkb_writer.writeHEX(*geometry, ss);
return ss.str();
}
#endif // TEST_GEOM_HELPER_HPP

View File

@ -0,0 +1,18 @@
#include "catch.hpp"
#include <random>
#include <osmium/geom/projection.hpp>
TEST_CASE("CRS") {
osmium::geom::CRS wgs84{4326};
osmium::geom::CRS mercator{3857};
osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)};
auto ct = osmium::geom::transform(wgs84, mercator, c);
auto c2 = osmium::geom::transform(mercator, wgs84, ct);
REQUIRE(c.x == Approx(c2.x));
REQUIRE(c.y == Approx(c2.y));
}

View File

@ -0,0 +1,16 @@
#include "catch.hpp"
#include <string>
#include <osmium/geom/factory.hpp>
TEST_CASE("Geometry exception") {
SECTION("geometry_error") {
osmium::geometry_error e("some error message", "node", 17);
REQUIRE(e.id() == 17);
REQUIRE(std::string(e.what()) == "some error message (node_id=17)");
}
}

View File

@ -0,0 +1,41 @@
#include "catch.hpp"
#include <osmium/geom/geos.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp>
#include <osmium/geom/wkb.hpp>
#include <osmium/geom/wkt.hpp>
#include "helper.hpp"
TEST_CASE("Projection") {
SECTION("point_mercator") {
osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2);
std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
}
SECTION("point_epsg_3857") {
osmium::geom::WKTFactory<osmium::geom::Projection> factory(osmium::geom::Projection(3857), 2);
std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
}
SECTION("wkb_with_parameter") {
osmium::geom::WKBFactory<osmium::geom::Projection> wkb_factory(osmium::geom::Projection(3857), osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<osmium::geom::Projection> geos_factory(osmium::geom::Projection(3857));
std::string wkb = wkb_factory.create_point(osmium::Location(3.2, 4.2));
std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
}
SECTION("cleanup") {
// trying to make valgrind happy, but there is still a memory leak in proj library
pj_deallocate_grids();
}
}

View File

@ -0,0 +1,166 @@
#include "catch.hpp"
#include <osmium/geom/geojson.hpp>
#include "area_helper.hpp"
#include "wnl_helper.hpp"
TEST_CASE("GeoJSON_Geometry") {
SECTION("point") {
osmium::geom::GeoJSONFactory<> factory;
std::string json {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
}
SECTION("empty_point") {
osmium::geom::GeoJSONFactory<> factory;
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
SECTION("linestring") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::string json {factory.create_linestring(wnl)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.6,4.9]]}"} == json);
}
{
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.2,4.2]]}"} == json);
}
{
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.5,4.7],[3.6,4.9]]}"} == json);
}
{
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.5,4.7],[3.2,4.2]]}"} == json);
}
}
SECTION("empty_linestring") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
auto& wnl = create_test_wnl_empty(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
}
SECTION("linestring_with_two_same_locations") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
auto& wnl = create_test_wnl_same_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
{
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
}
{
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
}
}
SECTION("linestring_with_undefined_location") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
auto& wnl = create_test_wnl_undefined_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
}
SECTION("area_1outer_0inner") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
REQUIRE(!area.is_multipolygon());
REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
{
std::string json {factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[3.2,4.2],[3.5,4.7],[3.6,4.9],[3.2,4.2]]]]}"} == json);
}
}
SECTION("area_1outer_1inner") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
REQUIRE(!area.is_multipolygon());
REQUIRE(std::distance(area.cbegin(), area.cend()) == 3);
REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
REQUIRE(std::distance(area.cbegin<osmium::InnerRing>(), area.cend<osmium::InnerRing>()) == area.num_rings().second);
{
std::string json {factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[8,1],[8,8],[1,8],[1,1]]]]}"} == json);
}
}
SECTION("area_2outer_2inner") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
REQUIRE(area.is_multipolygon());
REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
REQUIRE(std::distance(area.cbegin<osmium::InnerRing>(), area.cend<osmium::InnerRing>()) == area.num_rings().second);
int outer_ring=0;
int inner_ring=0;
for (auto it_outer = area.cbegin<osmium::OuterRing>(); it_outer != area.cend<osmium::OuterRing>(); ++it_outer) {
if (outer_ring == 0) {
REQUIRE(it_outer->front().ref() == 1);
} else if (outer_ring == 1) {
REQUIRE(it_outer->front().ref() == 100);
} else {
REQUIRE(false);
}
for (auto it_inner = area.inner_ring_cbegin(it_outer); it_inner != area.inner_ring_cend(it_outer); ++it_inner) {
if (outer_ring == 0 && inner_ring == 0) {
REQUIRE(it_inner->front().ref() == 5);
} else if (outer_ring == 0 && inner_ring == 1) {
REQUIRE(it_inner->front().ref() == 10);
} else {
REQUIRE(false);
}
++inner_ring;
}
inner_ring = 0;
++outer_ring;
}
{
std::string json {factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[4,1],[4,4],[1,4],[1,1]],[[5,5],[5,7],[7,7],[5,5]]],[[[10,10],[11,10],[11,11],[10,11],[10,10]]]]}"} == json);
}
}
}

View File

@ -0,0 +1,141 @@
#include "catch.hpp"
#include <osmium/geom/geos.hpp>
#include "area_helper.hpp"
#include "wnl_helper.hpp"
TEST_CASE("GEOS geometry factory - create point") {
osmium::geom::GEOSFactory<> factory;
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
REQUIRE(-1 == point->getSRID());
}
TEST_CASE("GEOS geometry factory - create point with non-default srid") {
osmium::geom::GEOSFactory<> factory(4326);
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
REQUIRE(4326 == point->getSRID());
}
TEST_CASE("GEOS geometry factory - create point with externally created GEOS factory") {
geos::geom::GeometryFactory geos_factory;
osmium::geom::GEOSFactory<> factory(geos_factory);
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
REQUIRE(0 == point->getSRID());
}
TEST_CASE("GEOS geometry factory - can not create from invalid location") {
osmium::geom::GEOSFactory<> factory;
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
TEST_CASE("GEOS geometry factory - create linestring") {
osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
SECTION("from way node list") {
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl)};
REQUIRE(3 == linestring->getNumPoints());
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.2 == p0->getX());
std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
REQUIRE(3.6 == p2->getX());
}
SECTION("without duplicates and backwards") {
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(3 == linestring->getNumPoints());
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.6 == p0->getX());
std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
REQUIRE(3.2 == p2->getX());
}
SECTION("with duplicates") {
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(4 == linestring->getNumPoints());
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.2 == p0->getX());
}
SECTION("with duplicates and backwards") {
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(4 == linestring->getNumPoints());
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.6 == p0->getX());
}
}
TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings") {
osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
REQUIRE(0 == p0->getNumInteriorRing());
const geos::geom::LineString* l0e = p0->getExteriorRing();
REQUIRE(4 == l0e->getNumPoints());
std::unique_ptr<geos::geom::Point> l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
REQUIRE(3.5 == l0e_p0->getX());
}
TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring") {
osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
REQUIRE(1 == p0->getNumInteriorRing());
const geos::geom::LineString* l0e = p0->getExteriorRing();
REQUIRE(5 == l0e->getNumPoints());
const geos::geom::LineString* l0i0 = p0->getInteriorRingN(0);
REQUIRE(5 == l0i0->getNumPoints());
}
TEST_CASE("GEOS geometry factory - create area with two outer and two inner rings") {
osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(2 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
REQUIRE(2 == p0->getNumInteriorRing());
const geos::geom::LineString* l0e = p0->getExteriorRing();
REQUIRE(5 == l0e->getNumPoints());
const geos::geom::Polygon* p1 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(1));
REQUIRE(0 == p1->getNumInteriorRing());
const geos::geom::LineString* l1e = p1->getExteriorRing();
REQUIRE(5 == l1e->getNumPoints());
}

View File

@ -0,0 +1,92 @@
#include "catch.hpp"
#include <osmium/geom/geos.hpp>
#include <osmium/geom/wkb.hpp>
#include "helper.hpp"
#include "area_helper.hpp"
#include "wnl_helper.hpp"
TEST_CASE("WKB_Geometry_with_GEOS") {
SECTION("point") {
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<> geos_factory;
std::string wkb {wkb_factory.create_point(osmium::Location(3.2, 4.2))};
std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
}
SECTION("linestring") {
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<> geos_factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::string wkb = wkb_factory.create_linestring(wnl);
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
{
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
{
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
{
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
}
SECTION("area_1outer_0inner") {
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<> geos_factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
std::string wkb = wkb_factory.create_multipolygon(area);
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
SECTION("area_1outer_1inner") {
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<> geos_factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
std::string wkb = wkb_factory.create_multipolygon(area);
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
SECTION("area_2outer_2inner") {
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::geom::GEOSFactory<> geos_factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
std::string wkb = wkb_factory.create_multipolygon(area);
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
REQUIRE(geos_to_wkb(geos.get()) == wkb);
}
}

View File

@ -0,0 +1,37 @@
#include "catch.hpp"
#include <osmium/geom/mercator_projection.hpp>
TEST_CASE("Mercator") {
SECTION("mercator_projection") {
osmium::geom::MercatorProjection projection;
REQUIRE(3857 == projection.epsg());
REQUIRE("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" == projection.proj_string());
}
SECTION("low_level_mercator_functions") {
osmium::geom::Coordinates c1(17.839, -3.249);
osmium::geom::Coordinates r1 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c1));
REQUIRE(r1.x == Approx(c1.x).epsilon(0.000001));
REQUIRE(r1.y == Approx(c1.y).epsilon(0.000001));
osmium::geom::Coordinates c2(-89.2, 15.915);
osmium::geom::Coordinates r2 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c2));
REQUIRE(r2.x == Approx(c2.x).epsilon(0.000001));
REQUIRE(r2.y == Approx(c2.y).epsilon(0.000001));
osmium::geom::Coordinates c3(180.0, 85.0);
osmium::geom::Coordinates r3 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c3));
REQUIRE(r3.x == Approx(c3.x).epsilon(0.000001));
REQUIRE(r3.y == Approx(c3.y).epsilon(0.000001));
}
SECTION("mercator_bounds") {
osmium::Location mmax(180.0, osmium::geom::MERCATOR_MAX_LAT);
osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(mmax);
REQUIRE(c.x == Approx(c.y).epsilon(0.001));
REQUIRE(osmium::geom::detail::y_to_lat(osmium::geom::detail::lon_to_x(180.0)) == Approx(osmium::geom::MERCATOR_MAX_LAT).epsilon(0.0000001));
}
}

View File

@ -0,0 +1,121 @@
#include "catch.hpp"
#include <osmium/geom/ogr.hpp>
#include "area_helper.hpp"
#include "wnl_helper.hpp"
TEST_CASE("OGR_Geometry") {
SECTION("point") {
osmium::geom::OGRFactory<> factory;
std::unique_ptr<OGRPoint> point {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
}
SECTION("empty_point") {
osmium::geom::OGRFactory<> factory;
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
SECTION("linestring") {
osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl)};
REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0));
REQUIRE(3.6 == linestring->getX(2));
}
{
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0));
REQUIRE(3.2 == linestring->getX(2));
}
{
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0));
}
{
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0));
}
}
SECTION("area_1outer_0inner") {
osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
REQUIRE(0 == p0->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(4 == l0e->getNumPoints());
REQUIRE(3.5 == l0e->getX(1));
}
SECTION("area_1outer_1inner") {
osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
REQUIRE(1 == p0->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(5 == l0e->getNumPoints());
const OGRLineString* l0i0 = p0->getInteriorRing(0);
REQUIRE(5 == l0i0->getNumPoints());
}
SECTION("area_2outer_2inner") {
osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(2 == mp->getNumGeometries());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
REQUIRE(2 == p0->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(5 == l0e->getNumPoints());
const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
REQUIRE(0 == p1->getNumInteriorRings());
const OGRLineString* l1e = p1->getExteriorRing();
REQUIRE(5 == l1e->getNumPoints());
}
}

View File

@ -0,0 +1,149 @@
#include "catch.hpp"
#include <random>
#include <osmium/geom/factory.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp>
TEST_CASE("Projection") {
SECTION("identity_projection") {
osmium::geom::IdentityProjection projection;
REQUIRE(4326 == projection.epsg());
REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string());
}
SECTION("project_location_4326") {
osmium::geom::Projection projection(4326);
REQUIRE(4326 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string());
const osmium::Location loc(1.0, 2.0);
const osmium::geom::Coordinates c {1.0, 2.0};
REQUIRE(c == projection(loc));
}
SECTION("project_location_4326_string") {
osmium::geom::Projection projection("+init=epsg:4326");
REQUIRE(-1 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string());
const osmium::Location loc(1.0, 2.0);
const osmium::geom::Coordinates c {1.0, 2.0};
REQUIRE(c == projection(loc));
}
SECTION("unknown_projection_string") {
REQUIRE_THROWS_AS(osmium::geom::Projection projection("abc"), osmium::projection_error);
}
SECTION("unknown_epsg_code") {
REQUIRE_THROWS_AS(osmium::geom::Projection projection(9999999), osmium::projection_error);
}
SECTION("project_location_3857") {
osmium::geom::Projection projection(3857);
REQUIRE(3857 == projection.epsg());
REQUIRE("+init=epsg:3857" == projection.proj_string());
{
const osmium::Location loc(0.0, 0.0);
const osmium::geom::Coordinates c {0.0, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(180.0, 0.0);
const osmium::geom::Coordinates c {20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(180.0, 0.0);
const osmium::geom::Coordinates c {20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(0.0, 85.0511288);
const osmium::geom::Coordinates c {0.0, 20037508.34};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
}
SECTION("project_location_mercator") {
osmium::geom::MercatorProjection projection;
{
const osmium::Location loc(0.0, 0.0);
const osmium::geom::Coordinates c {0.0, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(180.0, 0.0);
const osmium::geom::Coordinates c {20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(180.0, 0.0);
const osmium::geom::Coordinates c {20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
{
const osmium::Location loc(0.0, 85.0511288);
const osmium::geom::Coordinates c {0.0, 20037508.34};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
}
SECTION("compare_mercators") {
osmium::geom::MercatorProjection projection_merc;
osmium::geom::Projection projection_3857(3857);
REQUIRE(3857 == projection_3857.epsg());
REQUIRE("+init=epsg:3857" == projection_3857.proj_string());
{
const osmium::Location loc(4.2, 27.3);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
{
const osmium::Location loc(160.789, -42.42);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
{
const osmium::Location loc(-0.001, 0.001);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
{
const osmium::Location loc(-85.2, -85.2);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
}
SECTION("compare_mercators") {
osmium::geom::MercatorProjection projection_merc;
osmium::geom::Projection projection_3857(3857);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis_x(-180.0, 180.0);
std::uniform_real_distribution<> dis_y(-90.0, 90.0);
for (int n = 0; n < 100000; ++n) {
const osmium::Location loc(dis_x(gen), dis_y(gen));
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
}
}

View File

@ -0,0 +1,93 @@
#include "catch.hpp"
#include <sstream>
#include <osmium/geom/tile.hpp>
#include "helper.hpp"
#include "test_tile_data.hpp"
TEST_CASE("Tile") {
SECTION("x0.0 y0.0 zoom 0") {
osmium::Location l(0.0, 0.0);
osmium::geom::Tile t(0, l);
REQUIRE(t.x == 0);
REQUIRE(t.y == 0);
REQUIRE(t.z == 0);
}
SECTION("x180.0 y90.0 zoom 0") {
osmium::Location l(180.0, 90.0);
osmium::geom::Tile t(0, l);
REQUIRE(t.x == 0);
REQUIRE(t.y == 0);
REQUIRE(t.z == 0);
}
SECTION("x180.0 y90.0 zoom 4") {
osmium::Location l(180.0, 90.0);
osmium::geom::Tile t(4, l);
REQUIRE(t.x == (1 << 4) - 1);
REQUIRE(t.y == 0);
REQUIRE(t.z == 4);
}
SECTION("x0.0 y0.0 zoom 4") {
osmium::Location l(0.0, 0.0);
osmium::geom::Tile t(4, l);
auto n = 1 << (4-1);
REQUIRE(t.x == n);
REQUIRE(t.y == n);
REQUIRE(t.z == 4);
}
SECTION("equality") {
osmium::geom::Tile a(4, 3, 4);
osmium::geom::Tile b(4, 3, 4);
osmium::geom::Tile c(4, 4, 3);
REQUIRE(a == b);
REQUIRE(a != c);
REQUIRE(b != c);
}
SECTION("order") {
osmium::geom::Tile a(2, 3, 4);
osmium::geom::Tile b(4, 3, 4);
osmium::geom::Tile c(4, 4, 3);
osmium::geom::Tile d(4, 4, 2);
REQUIRE(a < b);
REQUIRE(a < c);
REQUIRE(b < c);
REQUIRE(d < c);
}
SECTION("tilelist") {
std::istringstream input_data(s);
while (input_data) {
double lon, lat;
uint32_t x, y, zoom;
input_data >> lon;
input_data >> lat;
input_data >> x;
input_data >> y;
input_data >> zoom;
osmium::Location l(lon, lat);
osmium::geom::Tile t(zoom, l);
REQUIRE(t.x == x);
REQUIRE(t.y == y);
}
}
}

View File

@ -0,0 +1,477 @@
#include <string>
static std::string s = R"(127.4864358 16.8380041 223904 118630 18
163.1103174 39.4760232 121 48 7
-4.1372725 -22.5105386 31 36 6
98.7193066 -36.2312406 1 1 1
63.5773661 -13.47636 21 17 5
-88.4518148 37.9805485 260 395 10
-14.5903133 -28.2989812 3763 4767 13
-13.4971239 -34.4080035 14 19 5
-169.156223 -64.0900356 3 93 7
27.1473191 -4.1993125 4713 4191 13
-160.9733129 54.3684314 13 81 8
129.0194139 14.2576156 439 235 9
-69.5085993 -56.8253221 10057 22700 15
-77.8387486 18.1961517 1162 1837 12
-76.2695325 -18.2494296 147 282 9
-91.594905 7.6698071 1 3 3
-116.7926741 -20.6060813 179 571 10
109.0552776 -1.9947569 52620 33131 16
-156.1846426 -79.3817554 33 449 9
-95.3403755 -27.8978407 1 4 3
-55.1827573 -73.2293796 44 103 7
-108.5207885 -48.0099293 50 167 8
23.7540108 -15.3395164 9273 8898 14
-155.6662842 -68.3295899 0 0 0
75.8139119 30.9914252 363 209 9
-135.8034544 64.7242469 0 1 2
-48.743352 70.9392876 23 13 6
-38.6968026 7.7867812 0 0 0
-18.5234838 11.8557704 29395 30594 16
-152.5632568 19.4069834 78 455 10
-63.2089431 -80.5909713 0 0 0
-94.1255611 -81.2028822 244 930 10
175.0862205 -33.0865142 3 2 2
-179.6241926 -37.0256609 1 625 10
135.6783824 -38.6011643 459739 323170 19
-139.6407533 -83.2495209 0 7 3
-14.1336447 -56.5465949 58 88 7
-30.7414568 -32.9543731 26 38 6
10.3306861 73.2444693 1082 399 11
-84.8379263 29.2363222 16 26 6
-94.0685822 -39.5503996 7821 20309 15
-86.5944356 -41.7491891 265 642 10
11.9182172 -80.5613703 34937 58784 16
91.8773752 -32.1741317 0 0 0
126.2879157 20.5759564 1742 904 11
-160.7743029 -47.3192128 27999 340565 19
-4.2449045 -50.3288332 31 42 6
-66.6857158 61.4380757 10 9 5
169.7372317 -74.3365704 3 3 2
87.4815328 75.6218888 95 21 7
60.3544927 28.3165267 0 0 0
-48.9614619 -59.3292497 2 5 3
-123.2935018 -59.5454886 80 362 9
-31.5909316 -14.8985476 13 17 5
58.1862173 59.0957666 2710 1209 12
-72.8881665 -2.2648849 1218 2073 12
-33.7267461 8.6006817 106512 124785 18
175.723181 46.4929742 7 2 3
-127.1963326 76.0328786 0 0 0
-161.7444367 -26.7634497 13293 151310 18
-163.976298 -8.1169845 91 1070 11
63.7757109 5.6049418 2 1 2
12.7012434 22.1157713 70160 57276 17
19.5832849 -25.0284049 1135 1171 11
-22.6619642 54.8831276 111 81 8
78.7736907 24.0919863 5888 3530 13
121.9003045 -64.6256685 107 94 7
-64.8766793 61.6655916 81 71 8
113.0498445 -70.0016518 416 397 9
-51.5116259 68.1532424 46781 31217 17
-89.9005747 87.9523248 512 0 11
59.2536822 -75.1520493 10 13 4
17.375372 74.9259262 287448 93371 19
75.6426945 8.4808632 186153 124873 18
144.89589 75.1647661 14786 2875 14
174.4350898 -29.268169 258091 153376 18
-91.8773113 50.6182166 0 0 0
5.3822308 45.1391794 134991 94156 18
43.0978373 -10.0764237 324909 276895 19
55.6682917 -40.9015342 21451 20470 15
-37.584032 52.253723 6 5 4
131.0141997 29.0271798 28309 13621 15
69.8830721 -86.8548645 363918 524287 19
-107.7917548 -76.9626654 26290 110787 17
-57.1736642 49.9345991 2 2 3
165.5170226 -84.9735363 982 1021 10
-139.7208984 -73.8754873 1 12 4
-154.5959463 -10.596718 4 33 6
-106.4164918 36.5042686 3348 6405 14
-92.9688259 -11.2262505 0 2 2
138.2722283 8.1109779 7 3 3
123.1389319 -40.3505677 862 637 10
-171.4780435 24.9112482 0 13 5
89.3668763 -63.1809434 392293 381781 19
-79.6906176 -13.376312 9130 17612 15
133.1329522 -28.9032634 445 298 9
115.0369496 70.6965823 6 1 3
-74.8926697 -78.9770185 2391 7144 13
51.9175766 73.0184277 164 50 8
178.1319784 43.7111421 509 186 9
162.4098389 61.1595443 0 0 0
7.6241126 -75.6182944 2 3 2
172.8902767 28.5068027 125 53 7
156.4030739 -76.7309238 478 431 9
-131.3963189 62.2039684 1 2 3
34.6057088 -36.2933264 2441 2491 12
-3.3896413 -48.2734347 15 20 5
83.528842 -48.219886 2998 2675 12
16.6000512 -31.6322244 17894 19421 15
-18.2425749 21.0749052 14 14 5
35.6035336 46.9916228 78498 46105 17
-109.3453091 -34.2312523 12 38 6
88.4909962 58.6104749 47 19 6
-129.7372783 21.7408241 571 1794 12
25.7269392 -40.1240139 1 1 1
26.3829579 5.248998 37570 31811 16
141.1768247 -41.4653038 14617 10269 14
151.3788752 -38.0160512 241302 161042 18
-92.7471483 -35.391745 15883 39664 16
142.5902623 -14.1023743 28 17 5
179.3461485 -86.7573357 3 3 2
-40.9746194 61.5689546 790 576 11
128.6399735 -54.8895009 56186 44772 16
-141.391583 -63.8272 0 2 2
-3.5004218 19.3089998 4016 3648 13
16.138208 -42.7868627 1 1 1
78.502315 -18.91667 2 2 2
-44.6311826 -15.7483106 98572 142686 18
-120.431941 -39.3431529 0 0 0
-70.4915024 25.4763412 9967 13984 15
118.0711114 -66.5691073 211 192 8
-114.945538 38.1764389 0 0 0
142.991315 -46.3378741 14699 10577 14
34.2770562 -84.7173756 312063 518834 19
109.5563415 -85.9138266 105424 131071 17
-171.8032643 70.1948223 0 3 4
-90.8434294 89.7252122 126 0 9
163.5677082 -53.9885419 3 2 2
128.884016 -63.0732584 112461 95358 17
116.5348575 -56.1616143 843 705 10
-171.5770602 37.9225943 11 197 9
48.1396653 -49.3932234 5191 5392 13
-157.6786731 15.3895763 32507 239456 19
15.7385145 -37.1364397 1113 1251 11
137.5179466 61.2025671 1 0 1
-70.4767722 42.9798424 19938 24086 16
27.8867901 43.4642562 9461 5991 14
68.5677462 -84.9560937 11312 16334 14
-56.790151 -67.124147 179437 395476 19
108.850832 43.3493384 26291 11996 15
-139.0655153 8.2673118 1 7 4
59.3726661 83.3857699 21788 1515 15
-158.4718709 -12.2313178 1 17 5
30.358316 -83.020501 2393 3871 12
-169.9667863 71.1152107 1 13 6
-89.9418297 -7.7258969 131156 273429 19
-16.5050312 47.1843923 116 89 8
-151.9641886 -36.3579042 5103 39881 16
169.7406916 60.0950674 62 18 6
32.6694543 -1.8435981 2 2 2
97.7880811 77.5295169 50569 9674 16
87.7554889 -85.6741368 389947 524287 19
-19.0174909 29.1940122 0 0 1
-86.6180019 82.6445919 1 0 2
-50.1997802 -21.1913243 1476 2294 12
73.8710121 75.2201385 5 1 3
41.7434624 79.1410045 322937 65770 19
-122.4312562 -68.4513916 10 48 6
-54.6116448 -23.1761137 1 2 2
-35.8774263 -51.5317442 102 170 8
179.2976644 -76.2729885 127 107 7
-111.6934402 -85.2696836 1 7 3
-24.2137947 28.4102025 3 3 3
-168.0816395 -64.0317696 16 375 9
43.2514876 6.4266793 2540 1974 12
25.5877932 49.3486828 4 2 3
-133.3671657 -25.0795973 8 36 6
-140.2002274 -37.3713396 452 2507 12
73.6326557 -21.9898207 360 288 9
-83.0901448 -69.1893461 2205 6305 13
-32.83227 -11.1061854 3348 4350 13
-151.8897244 14.6891958 0 0 0
-118.1125151 82.3085937 704 288 12
119.9903922 1.4884267 53 31 6
-116.9455865 -48.1971821 0 2 2
111.4279587 -52.6024326 828 688 10
-78.9207774 28.6183104 147207 218615 19
45.1367631 24.1416251 40 27 6
115.0905685 7.2971256 6714 3929 13
-58.0837371 -55.4033522 43 87 7
-44.6785779 83.0751777 6158 877 14
80.2002966 84.3087089 2960 91 12
-167.3118039 -59.2698371 72 1445 11
139.9974902 -74.5994693 455 419 9
-27.5858357 -36.1890547 6936 9960 14
68.8572424 20.2096749 353 226 9
-168.7172825 69.1607462 2053 15104 16
62.1361934 74.6007777 44079 11896 16
-102.9645124 65.3735325 112191 135144 19
178.8434887 18.6231394 65325 29316 16
-138.0494072 -80.3786289 29 228 8
33.3858934 62.9029909 155382 71699 18
-1.6915643 74.737228 1 0 2
18.2680756 6.6441482 1 0 1
34.0511738 -28.6862516 2 2 2
-24.0705994 -0.6026568 28386 32877 16
-176.8765092 -14.3252022 568 35403 16
154.6553417 -79.7390666 1903 1809 11
151.6055263 59.552346 14 4 4
-101.7681729 45.3498263 113933 187876 19
-52.3703658 -89.8260406 181 511 9
-85.7937259 16.5632413 2143 3713 13
114.7030999 6.6846014 104 61 7
13.6027861 88.6863877 2 0 2
60.5726928 38.256536 43794 25219 16
141.0903381 -35.4468007 7306 4959 13
-38.8182454 -55.2332792 200 350 9
179.7818018 -79.6600052 523970 462627 19
-45.2102175 82.7381225 196301 32058 19
-36.5811826 -35.3991346 0 0 0
-26.7719575 -75.7014102 223154 435372 19
77.3451937 -65.4613594 1 1 1
-37.3286225 38.3250599 51945 50407 17
70.8235495 35.3870419 365288 206979 19
99.8381373 -83.4101655 1 1 1
25.8851923 67.415543 9370 3991 14
-12.3393758 68.5972027 7 3 4
-142.9400273 -36.2904852 1 9 4
110.085689 -50.9514972 422467 348655 19
121.5093657 53.9939447 54888 21044 16
151.1307841 -33.0798435 58 38 6
100.4346499 -57.0129759 6 5 3
114.0564882 63.4987339 428250 141474 19
-17.3978586 19.2981593 57 57 7
-129.101039 -66.3423574 579 3067 12
117.6639917 14.0568892 433504 241463 19
97.7014577 69.1261732 202216 60490 18
-174.7931333 81.4174709 7583 46045 19
47.205341 -48.8608019 20680 21495 15
167.416796 -7.5063098 247 133 8
63.6744589 21.3392888 0 0 0
-106.0719817 33.8353547 53832 104862 18
-48.4051268 27.0438152 191648 221209 19
64.5675545 -27.0683253 5 4 3
110.7800249 -35.8217841 0 0 0
164.8954138 81.9558801 31393 2538 15
-54.4595565 -23.0128432 357 579 10
43.2542709 67.694011 2540 989 12
137.6537233 -78.7052092 28913 28450 15
76.9271563 -60.0777348 0 0 0
-145.0240216 47.3869213 6367 22947 16
136.2328853 -73.4534547 3598 3304 12
48.8047148 74.3001023 81 23 7
-144.6978756 33.6270048 200 820 11
64.6723407 -37.196427 21 19 5
-58.3356482 -19.0812366 22148 36307 16
19.611535 -31.3013119 0 0 0
-63.8923439 -25.9560287 1 2 2
-152.5288047 -30.9747477 0 1 1
-99.8509683 -69.0258965 7295 25181 15
-22.9015207 -21.0915082 13 17 5
161.4402438 61.1430241 15539 4652 14
-102.9499976 -1.2629414 1 4 3
-159.7995801 51.1570142 14 85 8
10.5265485 -86.8526122 67 127 7
47.1581041 -73.1628608 646 823 10
2.7577906 -66.3257104 66540 98133 17
96.9653593 -9.8258675 6 4 3
-55.4199846 25.3325116 2834 3499 13
-47.3590106 59.5085133 2 2 3
179.1441501 22.1324479 7 3 3
16.2649007 47.8480398 4 2 3
-27.8373963 -0.3926597 27700 32839 16
-99.7938802 -48.8013068 912 2685 12
133.4858024 28.457146 3 1 2
-174.7621207 -25.8318084 238 9409 14
106.856378 19.640472 203 113 8
31.4361995 -80.2488406 76981 116886 17
148.6539554 -70.0347611 116 99 7
45.1821773 17.5961595 80 57 7
-30.3630114 71.3238998 54481 27877 17
106.547704 44.9731358 6520 2947 13
-132.8057564 23.3928795 67 221 9
116.6455816 -10.1097592 52 33 6
172.5512559 -53.2307289 3 2 2
-114.2084519 42.834332 2994 6030 14
91.0172087 87.6025 1 0 1
-101.666812 -84.7858729 7130 32495 15
-14.8074931 68.3277393 0 0 0
140.3354277 -7.8709618 14 8 4
-130.4961987 -69.4777523 9011 50594 16
-121.239479 1.0896367 1 3 3
-141.2241052 3.4495348 56471 257117 19
42.6041377 -19.1328846 2532 2269 12
141.3750885 -1.8110503 468036 264781 19
-26.545021 -30.9641274 218 302 9
87.6154866 10.1978751 5 3 3
88.002559 -33.4108714 762 612 10
170.9910642 -7.1925019 3993 2130 12
-66.5680487 -88.1144993 165197 524287 19
-71.5925378 45.720316 0 0 0
-16.457642 57.1688038 930 625 11
20.8379624 -11.1485568 35 33 6
-72.9399538 -16.6504502 1 2 2
52.8746845 -71.5213577 10598 12927 14
93.2392918 12.5073156 48 29 6
-3.7803834 73.7748237 128319 49794 18
93.5713795 -38.8308882 24 19 5
87.3474619 -6.9970464 23 16 5
161.2199467 48.5612779 30 11 5
87.343969 -31.3153618 47 37 6
60.5318627 58.0869948 42 19 6
161.4388458 42.7612385 1 0 1
14.1262999 -26.2101142 4 4 3
-135.776346 -21.4248586 503 2297 12
-100.3980364 82.0236388 1 0 3
-55.8093833 -87.2455194 0 0 0
-15.6397352 64.454076 935 540 11
131.5974423 39.1251372 110 48 7
56.8045509 27.5658629 168 107 8
146.3634996 14.9287416 3 1 2
51.5699041 74.0370231 82 23 7
29.3100901 33.7208834 152414 104963 18
19.0622442 1.6781772 141 126 8
-22.2575472 73.6467471 114864 50126 18
125.0208495 47.8533914 3470 1426 12
-92.4804503 29.8409387 995 1691 12
113.6362202 86.1158625 0 0 0
113.6203756 28.4267778 26 13 5
124.472202 25.8347062 13856 6974 14
79.3654306 -33.7864728 46 38 6
-121.169233 -66.7642843 2 12 4
179.5816311 1.0182064 0 0 0
179.1123794 53.367624 0 0 0
-25.6611689 32.6575586 14048 13236 15
92.3370554 58.8306651 12 4 4
142.2756448 63.6603101 3 1 2
-162.8914282 -84.54406 6229 129034 17
-54.0759935 53.1086102 0 0 0
9.1647045 -39.4876873 34436 40604 16
59.3708822 -43.9789068 10894 10425 14
-16.6397572 46.5985252 929 723 11
-36.1053642 -67.6882841 0 1 1
-82.5851985 -69.5277766 4 12 4
117.0059969 -63.2697116 432546 382068 19
127.9740251 85.5341901 112129 0 17
-13.9255265 59.7720207 120931 76457 18
-167.7778382 41.7974194 69 761 11
-100.1217856 -70.5624949 454 1599 11
-42.4790343 -2.0016191 25034 33132 16
-8.0782317 65.9680074 30 16 6
-37.0481466 -55.2856125 203 350 9
149.074382 16.7121888 58 28 6
-53.1010518 -15.8492068 0 0 0
50.8517919 -30.8366257 42025 38674 16
-175.0355994 77.1929422 0 4 5
-33.3221217 72.5636809 6 3 4
-139.9201802 52.3400823 7296 21546 16
86.0299659 23.4535286 1513 886 11
105.6297238 -50.5521342 25998 21733 15
104.2700533 36.5417507 206999 102450 18
58.5238253 84.0320186 86843 3912 17
-121.9177826 65.4393267 1321 2108 13
-152.689211 57.4112922 39774 159515 19
94.2583831 80.8625455 6240 801 13
118.8199874 -37.6116567 53 39 6
5.787144 7.0599251 4227 3934 13
152.1682213 11.778732 236 119 8
37.4503636 64.311498 2474 1084 12
35.2616139 -59.8196291 38 45 6
-20.2808572 -26.9983008 29075 37875 16
-88.8541607 -20.4896703 66370 146320 18
125.7726709 41.2603793 27 11 5
-55.4322696 22.1767236 11338 14313 15
-38.2393439 -56.4681037 6 11 4
-139.4517643 -81.3621632 3 29 5
-146.7954207 -74.6050826 6044 53642 16
161.6654898 -71.7313805 15549 12957 14
-85.4720514 -73.177675 2 6 3
-25.7457381 -42.9842376 13 20 5
-2.0766311 51.0142455 0 0 1
-82.9179334 1.4865326 8836 16248 15
140.5661302 61.5056993 28 9 5
-30.2614099 35.5786378 54518 51659 17
-49.2072142 -38.6965571 0 1 1
124.6587534 9.5039576 433 242 9
-113.4516741 81.4585593 24229 11410 17
-4.5134723 68.229217 3 1 3
75.4838529 -44.997406 2906 2622 12
6.4715239 28.6900832 8486 6828 14
91.9187555 -24.8192643 6187 4679 13
-28.2510181 -42.6238777 26 40 6
-151.1042237 -21.4553189 2630 18384 15
-149.6272551 0.4235911 1382 8172 14
-51.9171488 74.630423 0 0 0
-36.5660117 37.242858 101 99 8
91.7136677 -30.9077617 772 604 10
61.6846009 -85.9378164 5 7 3
11.3772008 69.40183 34839 14980 16
82.6825938 9.4496443 11954 7759 14
61.8446231 -40.0114106 2751 2545 12
-51.6223196 -11.7880324 5 8 4
113.0309076 -73.4376173 13336 13217 14
-169.3808275 -72.7209175 0 25 5
-98.5653414 -80.0893122 231 910 10
-20.4653707 29.9801495 3 3 3
78.9156686 2.599349 0 0 0
76.0635255 -71.0823347 2913 3216 12
-26.1185551 22.3616029 28013 28589 16
177.8803853 -56.3662368 4071 2828 12
-157.7926463 78.4998022 15 34 8
168.6834344 -34.5535211 7934 4934 13
-77.208013 -44.0964079 0 1 1
-56.6162078 28.1240365 10 13 5
8.6548899 72.178831 137374 53767 18
-27.9342497 8.2525327 1 1 2
91.6356971 -13.5230128 6181 4406 13
-161.9980398 -75.4443511 0 13 4
46.8556576 -27.1078679 5162 4737 13
147.2806954 -48.1491071 465 334 9
-168.2679875 -29.0171568 0 2 2
10.0251187 -3.144812 8 8 4
109.0281873 81.9713348 26307 2528 15
-129.6281276 -36.9614028 73359 320148 19
7.3831244 -18.3270273 2132 2260 12
-34.4625217 53.2837646 52988 42524 17
129.8855275 -26.30807 3525 2358 12
-69.6374195 -45.7769025 10045 21081 15
59.9868336 50.3716565 43688 22120 16
126.4653338 -75.607391 1743 1698 11
-34.6459616 53.2502443 51 41 7
152.2415169 -71.7528837 1 1 1
-83.2126752 32.6685119 35239 52939 17
178.6388805 70.5727365 31 7 5
-153.5646223 -81.9491561 2 29 5
178.2668159 11.8222247 0 0 0
-27.136902 18.4287365 6 7 4
-104.7744923 -64.7769211 54777 193540 18
58.2318889 9.5897974 2710 1938 12
138.9707487 -65.2734433 14516 12149 14
-115.29331 -84.3402223 2944 16033 14
-66.3487123 -81.8340211 20 58 6
76.1802855 40.4007156 364 193 9
-77.5026834 -30.653231 145 301 9
-52.6095007 -79.7155889 11595 28942 15
-2.5594899 -31.6276806 7 9 4
-58.6267217 41.4851391 2 2 3
-0.7245205 -70.7329433 509 801 10
161.2822996 -79.0311957 124257 114418 17
144.8720197 80.1059269 14785 1811 14
159.3764075 -23.5100054 0 0 0
82.3109493 -7.0673699 95504 68115 17
94.3931949 63.0474034 97 34 7
87.4523391 -73.2690527 3043 3297 12
101.4256455 -0.8267694 12 8 4
-112.7666152 -82.3670281 12239 61007 16
-82.0948447 -38.0810449 8 19 5
113.2906728 -19.193243 104 70 7
16.953131 78.402684 35 8 6
-81.7974685 -53.9596787 34 86 7
69.8051889 58.1416894 181902 78760 18
-9.2435464 -53.4296594 3 5 3
30.0415066 11.4884737 4 3 3
125.2704157 -69.6324197 54 49 6
-41.2060435 63.8501787 789 548 11
120.407662 -4.9889504 6835 4209 13
92.0345558 -8.0809262 24761 17121 15
127.1061722 83.1311204 6988 428 13
-178.9414629 64.0086678 770 69897 18
49.0743035 -4.3000419 10425 8387 14
-45.109002 -55.1435498 1534 2803 12
3.2795498 75.95918 32 10 6
)";

View File

@ -0,0 +1,115 @@
#include "catch.hpp"
#include <osmium/geom/wkb.hpp>
#include "wnl_helper.hpp"
#if __BYTE_ORDER == __LITTLE_ENDIAN
TEST_CASE("WKB_Geometry_byte_order_dependent") {
SECTION("point") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string{"01010000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
}
SECTION("point_ewkb") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string{"0101000020E61000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
}
SECTION("linestring") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::string wkb {factory.create_linestring(wnl)};
REQUIRE(std::string{"0102000000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
}
{
std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(std::string{"010200000003000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
}
{
std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"0102000000040000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
}
{
std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"010200000004000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
}
}
SECTION("linestring_ewkb") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
std::string ewkb {factory.create_linestring(wnl)};
REQUIRE(std::string{"0102000020E6100000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == ewkb);
}
SECTION("linestring_with_two_same_locations") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_same_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
{
std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
}
{
std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
}
}
SECTION("linestring_with_undefined_location") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_undefined_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
}
}
#endif
TEST_CASE("WKB_Geometry_byte_order_independent") {
SECTION("empty_point") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
SECTION("empty_linestring") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_empty(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
}
}

View File

@ -0,0 +1,136 @@
#include "catch.hpp"
#include <osmium/geom/wkt.hpp>
#include "area_helper.hpp"
#include "wnl_helper.hpp"
TEST_CASE("WKT_Geometry") {
SECTION("point") {
osmium::geom::WKTFactory<> factory;
std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
REQUIRE(std::string{"POINT(3.2 4.2)"} == wkt);
}
SECTION("empty_point") {
osmium::geom::WKTFactory<> factory;
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
SECTION("linestring") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::string wkt {factory.create_linestring(wnl)};
REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.6 4.9)"} == wkt);
}
{
std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.2 4.2)"} == wkt);
}
{
std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.5 4.7,3.6 4.9)"} == wkt);
}
{
std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.5 4.7,3.2 4.2)"} == wkt);
}
}
SECTION("empty_linestring") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_empty(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
}
SECTION("linestring_with_two_same_locations") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_same_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
try {
factory.create_linestring(wnl);
} catch (osmium::geometry_error& e) {
REQUIRE(e.id() == 0);
REQUIRE(std::string(e.what()) == "need at least two points for linestring");
}
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
{
std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
}
{
std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
}
}
SECTION("linestring_with_undefined_location") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_undefined_location(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
}
SECTION("area_1outer_0inner") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
{
std::string wkt {factory.create_multipolygon(area)};
REQUIRE(std::string{"MULTIPOLYGON(((3.2 4.2,3.5 4.7,3.6 4.9,3.2 4.2)))"} == wkt);
}
}
SECTION("area_1outer_1inner") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
{
std::string wkt {factory.create_multipolygon(area)};
REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,8 1,8 8,1 8,1 1)))"} == wkt);
}
}
SECTION("area_2outer_2inner") {
osmium::geom::WKTFactory<> factory;
osmium::memory::Buffer buffer(10000);
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
{
std::string wkt {factory.create_multipolygon(area)};
REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,4 1,4 4,1 4,1 1),(5 5,5 7,7 7,5 5)),((10 10,11 10,11 11,10 11,10 10)))"} == wkt);
}
}
}

View File

@ -0,0 +1,44 @@
#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/node_ref_list.hpp>
using namespace osmium::builder::attr;
inline const osmium::WayNodeList& create_test_wnl_okay(osmium::memory::Buffer& buffer) {
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.2, 4.2}},
{3, {3.5, 4.7}},
{4, {3.5, 4.7}},
{2, {3.6, 4.9}}
}));
return buffer.get<osmium::WayNodeList>(pos);
}
inline const osmium::WayNodeList& create_test_wnl_empty(osmium::memory::Buffer& buffer) {
{
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
}
return buffer.get<osmium::WayNodeList>(buffer.commit());
}
inline const osmium::WayNodeList& create_test_wnl_same_location(osmium::memory::Buffer& buffer) {
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.5, 4.7}},
{2, {3.5, 4.7}}
}));
return buffer.get<osmium::WayNodeList>(pos);
}
inline const osmium::WayNodeList& create_test_wnl_undefined_location(osmium::memory::Buffer& buffer) {
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.5, 4.7}},
{2, osmium::Location()}
}));
return buffer.get<osmium::WayNodeList>(pos);
}

View File

@ -0,0 +1,170 @@
#include "catch.hpp"
#include <osmium/osm/types.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/index/map/dense_file_array.hpp>
#include <osmium/index/map/dense_mem_array.hpp>
#include <osmium/index/map/dense_mmap_array.hpp>
#include <osmium/index/map/dummy.hpp>
#include <osmium/index/map/sparse_file_array.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/index/map/sparse_mem_map.hpp>
#include <osmium/index/map/sparse_mem_table.hpp>
#include <osmium/index/map/sparse_mmap_array.hpp>
#include <osmium/index/node_locations_map.hpp>
template <typename TIndex>
void test_func_all(TIndex& index) {
osmium::unsigned_object_id_type id1 = 12;
osmium::unsigned_object_id_type id2 = 3;
osmium::Location loc1(1.2, 4.5);
osmium::Location loc2(3.5, -7.2);
REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
index.set(id1, loc1);
index.set(id2, loc2);
index.sort();
REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
}
template <typename TIndex>
void test_func_real(TIndex& index) {
osmium::unsigned_object_id_type id1 = 12;
osmium::unsigned_object_id_type id2 = 3;
osmium::Location loc1(1.2, 4.5);
osmium::Location loc2(3.5, -7.2);
index.set(id1, loc1);
index.set(id2, loc2);
index.sort();
REQUIRE(loc1 == index.get(id1));
REQUIRE(loc2 == index.get(id2));
REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
index.clear();
REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
}
TEST_CASE("IdToLocation") {
SECTION("Dummy") {
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
REQUIRE(0 == index1.size());
REQUIRE(0 == index1.used_memory());
test_func_all<index_type>(index1);
REQUIRE(0 == index1.size());
REQUIRE(0 == index1.used_memory());
}
SECTION("DenseMemArray") {
typedef osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
index1.reserve(1000);
test_func_all<index_type>(index1);
index_type index2;
index2.reserve(1000);
test_func_real<index_type>(index2);
}
#ifdef __linux__
SECTION("DenseMmapArray") {
typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
test_func_all<index_type>(index1);
index_type index2;
test_func_real<index_type>(index2);
}
#else
# pragma message("not running 'DenseMapMmap' test case on this machine")
#endif
SECTION("DenseFileArray") {
typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
test_func_all<index_type>(index1);
index_type index2;
test_func_real<index_type>(index2);
}
#ifdef OSMIUM_WITH_SPARSEHASH
SECTION("SparseMemTable") {
typedef osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
test_func_all<index_type>(index1);
index_type index2;
test_func_real<index_type>(index2);
}
#endif
SECTION("SparseMemMap") {
typedef osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
test_func_all<index_type>(index1);
index_type index2;
test_func_real<index_type>(index2);
}
SECTION("SparseMemArray") {
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
index_type index1;
REQUIRE(0 == index1.size());
REQUIRE(0 == index1.used_memory());
test_func_all<index_type>(index1);
REQUIRE(2 == index1.size());
index_type index2;
test_func_real<index_type>(index2);
}
SECTION("Dynamic map choice") {
typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> map_type;
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
std::vector<std::string> map_type_names = map_factory.map_types();
REQUIRE(map_type_names.size() >= 5);
for (const auto& map_type_name : map_type_names) {
std::unique_ptr<map_type> index1 = map_factory.create_map(map_type_name);
index1->reserve(1000);
test_func_all<map_type>(*index1);
std::unique_ptr<map_type> index2 = map_factory.create_map(map_type_name);
index2->reserve(1000);
test_func_real<map_type>(*index2);
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="testdata" upload="false">
<node id="1" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.02"/>
</osm>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
TESTDATA

Binary file not shown.

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="osmium/1.2.1">
<node id="1" version="1" timestamp="2015-09-17T11:52:00Z" uid="1" user="user_1" changeset="1" visible="false"/>
<node id="2" version="1" timestamp="2015-09-17T11:52:00Z" uid="1" user="user_1" changeset="1" visible="true" lat="1" lon="1"/>
</osm>

Binary file not shown.

View File

@ -0,0 +1,33 @@
#include "catch.hpp"
#include "utils.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <osmium/io/bzip2_compression.hpp>
TEST_CASE("Bzip2") {
SECTION("read_compressed_file") {
std::string input_file = with_data_dir("t/io/data_bzip2.txt.bz2");
int fd = ::open(input_file.c_str(), O_RDONLY);
REQUIRE(fd > 0);
size_t size = 0;
std::string all;
{
osmium::io::Bzip2Decompressor decomp(fd);
for (std::string data = decomp.read(); !data.empty(); data = decomp.read()) {
size += data.size();
all += data;
}
}
REQUIRE(9 == size);
REQUIRE("TESTDATA\n" == all);
}
}

View File

@ -0,0 +1,275 @@
#include "catch.hpp"
#include <iterator>
#include <osmium/io/file.hpp>
TEST_CASE("FileFormats") {
SECTION("default_file_format") {
osmium::io::File f;
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("stdin_stdout_empty") {
osmium::io::File f {""};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("stdin_stdout_dash") {
osmium::io::File f {"-"};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("stdin_stdout_bz2") {
osmium::io::File f {"-", "osm.bz2"};
REQUIRE("" == f.filename());
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osm") {
osmium::io::File f {"test.osm"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_pbf") {
osmium::io::File f {"test.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osm_pbf") {
osmium::io::File f {"test.osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_opl") {
osmium::io::File f {"test.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osm_opl") {
osmium::io::File f {"test.osm.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osm_gz") {
osmium::io::File f {"test.osm.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_opl_bz2") {
osmium::io::File f {"test.osm.opl.bz2"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osc_gz") {
osmium::io::File f {"test.osc.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_opl_gz") {
osmium::io::File f {"test.osh.opl.gz"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("detect_file_format_by_suffix_osh_pbf") {
osmium::io::File f {"test.osh.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osm") {
osmium::io::File f {"test", "osm"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_pbf") {
osmium::io::File f {"test", "pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osm_pbf") {
osmium::io::File f {"test", "osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_opl") {
osmium::io::File f {"test", "opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osm_opl") {
osmium::io::File f {"test", "osm.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osm_gz") {
osmium::io::File f {"test", "osm.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osm_opl_bz2") {
osmium::io::File f {"test", "osm.opl.bz2"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osc_gz") {
osmium::io::File f {"test", "osc.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osh_opl_gz") {
osmium::io::File f {"test", "osh.opl.gz"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("override_file_format_by_suffix_osh_pbf") {
osmium::io::File f {"test", "osh.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("format_options_pbf_history") {
osmium::io::File f {"test", "pbf,history=true"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
SECTION("format_options_pbf_foo") {
osmium::io::File f {"test.osm", "pbf,foo=bar"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE("bar" == f.get("foo"));
f.check();
}
SECTION("format_options_xml_abc_something") {
osmium::io::File f {"test.bla", "xml,abc,some=thing"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE("true" == f.get("abc"));
REQUIRE("thing" == f.get("some"));
REQUIRE(2 == std::distance(f.begin(), f.end()));
f.check();
}
SECTION("unknown_format_foo_bar") {
osmium::io::File f {"test.foo.bar"};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("unknown_format_foo") {
osmium::io::File f {"test", "foo"};
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("unknown_format_osm_foo") {
osmium::io::File f {"test", "osm.foo"};
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("unknown_format_bla_equals_foo") {
osmium::io::File f {"test", "bla=foo"};
REQUIRE_THROWS_AS(f.check(), std::runtime_error);
}
SECTION("url without format") {
osmium::io::File f {"http://www.example.com/api"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("url without format and filename") {
osmium::io::File f {"http://planet.osm.org/pbf/planet-latest.osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
f.check();
}
SECTION("url with format") {
osmium::io::File f {"http://www.example.com/api", "osh"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
f.check();
}
}

View File

@ -0,0 +1,37 @@
#include "catch.hpp"
#include <osmium/io/xml_output.hpp>
#include <osmium/io/output_iterator.hpp>
#include <osmium/io/writer.hpp>
TEST_CASE("output iterator") {
SECTION("should be copy constructable") {
osmium::io::Header header;
osmium::io::Writer writer("test.osm", header, osmium::io::overwrite::allow);
osmium::io::OutputIterator<osmium::io::Writer> out1(writer);
osmium::io::OutputIterator<osmium::io::Writer> out2(out1);
}
SECTION("should be copy assignable") {
osmium::io::Header header;
osmium::io::Writer writer1("test1.osm", header, osmium::io::overwrite::allow);
osmium::io::Writer writer2("test2.osm", header, osmium::io::overwrite::allow);
osmium::io::OutputIterator<osmium::io::Writer> out1(writer1);
osmium::io::OutputIterator<osmium::io::Writer> out2(writer2);
out2 = out1;
}
SECTION("should be incrementable") {
osmium::io::Header header;
osmium::io::Writer writer("test.osm", header, osmium::io::overwrite::allow);
osmium::io::OutputIterator<osmium::io::Writer> out(writer);
++out;
}
}

View File

@ -0,0 +1,153 @@
#include "catch.hpp"
#include <locale>
#include <osmium/io/detail/string_util.hpp>
TEST_CASE("output formatted") {
std::string out;
SECTION("small results") {
osmium::io::detail::append_printf_formatted_string(out, "%d", 17);
REQUIRE(out == "17");
}
SECTION("several parameters") {
osmium::io::detail::append_printf_formatted_string(out, "%d %s", 17, "foo");
REQUIRE(out == "17 foo");
}
SECTION("string already containing something") {
out += "foo";
osmium::io::detail::append_printf_formatted_string(out, " %d", 23);
REQUIRE(out == "foo 23");
}
SECTION("large results") {
const char* str =
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
osmium::io::detail::append_printf_formatted_string(out, "%s", str);
REQUIRE(out == str);
}
}
TEST_CASE("UTF8 encoding") {
std::string out;
SECTION("append to string") {
out += "1234";
osmium::io::detail::append_utf8_encoded_string(out, "abc");
REQUIRE(out == "1234abc");
}
SECTION("don't encode alphabetic characters") {
const char* s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
osmium::io::detail::append_utf8_encoded_string(out, s);
REQUIRE(out == s);
}
SECTION("don't encode numeric characters") {
const char* s = "0123456789";
osmium::io::detail::append_utf8_encoded_string(out, s);
REQUIRE(out == s);
}
SECTION("don't encode lots of often used characters characters") {
const char* s = ".-;:_#+";
osmium::io::detail::append_utf8_encoded_string(out, s);
REQUIRE(out == s);
}
SECTION("encode characters that are special in OPL") {
osmium::io::detail::append_utf8_encoded_string(out, " \n,=@");
REQUIRE(out == "%20%%0a%%2c%%3d%%40%");
}
// workaround for missing support for u8 string literals on Windows
#if !defined(_MSC_VER)
SECTION("encode multibyte character") {
osmium::io::detail::append_utf8_encoded_string(out, u8"\u30dc_\U0001d11e_\U0001f6eb");
REQUIRE(out == "%30dc%_%1d11e%_%1f6eb%");
}
#endif
}
TEST_CASE("html encoding") {
std::string out;
SECTION("do not encode normal characters") {
const char* s = "abc123,.-";
osmium::io::detail::append_xml_encoded_string(out, s);
REQUIRE(out == s);
}
SECTION("encode special XML characters") {
const char* s = "& \" \' < > \n \r \t";
osmium::io::detail::append_xml_encoded_string(out, s);
REQUIRE(out == "&amp; &quot; &apos; &lt; &gt; &#xA; &#xD; &#x9;");
}
}
TEST_CASE("debug encoding") {
std::string out;
SECTION("do not encode normal characters") {
const char* s = "abc123,.-";
osmium::io::detail::append_debug_encoded_string(out, s, "[", "]");
REQUIRE(out == s);
}
SECTION("encode some unicode characters") {
const char* s = u8"\n_\u30dc_\U0001d11e_\U0001f6eb";
osmium::io::detail::append_debug_encoded_string(out, s, "[", "]");
REQUIRE(out == "[<U+000A>]_[<U+30DC>]_[<U+1D11E>]_[<U+1F6EB>]");
}
}
TEST_CASE("encoding of non-printable characters in the first 127 characters") {
std::locale cloc("C");
char s[] = "a\0";
for (char c = 1; c < 0x7f; ++c) {
std::string out;
s[0] = c;
SECTION("utf8 encode") {
osmium::io::detail::append_utf8_encoded_string(out, s);
if (!std::isprint(c, cloc)) {
REQUIRE(out[0] == '%');
}
}
SECTION("debug encode") {
osmium::io::detail::append_debug_encoded_string(out, s, "", "");
if (!std::isprint(c, cloc)) {
REQUIRE(out[0] == '<');
}
}
}
}

View File

@ -0,0 +1,212 @@
#include "catch.hpp"
#include "utils.hpp"
#include <osmium/handler.hpp>
#include <osmium/io/any_compression.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/io/pbf_input.hpp>
#include <osmium/visitor.hpp>
#include <osmium/memory/buffer.hpp>
struct CountHandler : public osmium::handler::Handler {
int count = 0;
void node(osmium::Node&) {
++count;
}
}; // class CountHandler
struct ZeroPositionNodeCountHandler : public osmium::handler::Handler {
// number of nodes seen at zero position, or visible with undefined
// location.
int count = 0;
int total_count = 0; // total number of nodes seen
const osmium::Location zero = osmium::Location(int32_t(0), int32_t(0));
void node(osmium::Node &n) {
// no nodes in the history file have a zero location, and
// no visible nodes should have an undefined location.
if ((n.location() == zero) ||
(n.visible() && !n.location())) {
++count;
}
++total_count;
}
}; // class ZeroPositionNodeCountHandler
TEST_CASE("Reader") {
SECTION("reader can be initialized with file") {
osmium::io::File file(with_data_dir("t/io/data.osm"));
osmium::io::Reader reader(file);
osmium::handler::Handler handler;
osmium::apply(reader, handler);
}
SECTION("reader can be initialized with string") {
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
osmium::handler::Handler handler;
osmium::apply(reader, handler);
}
SECTION("should throw after eof") {
osmium::io::File file(with_data_dir("t/io/data.osm"));
osmium::io::Reader reader(file);
REQUIRE(!reader.eof());
while (osmium::memory::Buffer buffer = reader.read()) {
}
REQUIRE(reader.eof());
REQUIRE_THROWS_AS({
reader.read();
}, osmium::io_error);
}
SECTION("should not hang when apply() is called twice on reader") {
osmium::io::File file(with_data_dir("t/io/data.osm"));
osmium::io::Reader reader(file);
osmium::handler::Handler handler;
osmium::apply(reader, handler);
REQUIRE_THROWS_AS({
osmium::apply(reader, handler);
}, osmium::io_error);
}
SECTION("should work with a buffer with uncompressed data") {
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm"));
REQUIRE(fd >= 0);
const size_t buffer_size = 1000;
char buffer[buffer_size];
auto length = ::read(fd, buffer, buffer_size);
REQUIRE(length > 0);
osmium::io::File file(buffer, static_cast<size_t>(length), "osm");
osmium::io::Reader reader(file);
CountHandler handler;
REQUIRE(handler.count == 0);
osmium::apply(reader, handler);
REQUIRE(handler.count == 1);
}
SECTION("should work with a buffer with gzip-compressed data") {
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.gz"));
REQUIRE(fd >= 0);
const size_t buffer_size = 1000;
char buffer[buffer_size];
auto length = ::read(fd, buffer, buffer_size);
REQUIRE(length > 0);
osmium::io::File file(buffer, static_cast<size_t>(length), "osm.gz");
osmium::io::Reader reader(file);
CountHandler handler;
REQUIRE(handler.count == 0);
osmium::apply(reader, handler);
REQUIRE(handler.count == 1);
}
SECTION("should work with a buffer with bzip2-compressed data") {
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.bz2"));
REQUIRE(fd >= 0);
const size_t buffer_size = 1000;
char buffer[buffer_size];
auto length = ::read(fd, buffer, buffer_size);
REQUIRE(length > 0);
osmium::io::File file(buffer, static_cast<size_t>(length), "osm.bz2");
osmium::io::Reader reader(file);
CountHandler handler;
REQUIRE(handler.count == 0);
osmium::apply(reader, handler);
REQUIRE(handler.count == 1);
}
SECTION("should decode zero node positions in history (XML)") {
osmium::io::Reader reader(with_data_dir("t/io/deleted_nodes.osh"),
osmium::osm_entity_bits::node);
ZeroPositionNodeCountHandler handler;
REQUIRE(handler.count == 0);
REQUIRE(handler.total_count == 0);
osmium::apply(reader, handler);
REQUIRE(handler.count == 0);
REQUIRE(handler.total_count == 2);
}
SECTION("should decode zero node positions in history (PBF)") {
osmium::io::Reader reader(with_data_dir("t/io/deleted_nodes.osh.pbf"),
osmium::osm_entity_bits::node);
ZeroPositionNodeCountHandler handler;
REQUIRE(handler.count == 0);
REQUIRE(handler.total_count == 0);
osmium::apply(reader, handler);
REQUIRE(handler.count == 0);
REQUIRE(handler.total_count == 2);
}
}
TEST_CASE("Reader failure modes") {
SECTION("should fail with nonexistent file") {
REQUIRE_THROWS({
osmium::io::Reader reader(with_data_dir("t/io/nonexistent-file.osm"));
});
}
SECTION("should fail with nonexistent file (gz)") {
REQUIRE_THROWS({
osmium::io::Reader reader(with_data_dir("t/io/nonexistent-file.osm.gz"));
});
}
SECTION("should fail with nonexistent file (pbf)") {
REQUIRE_THROWS({
osmium::io::Reader reader(with_data_dir("t/io/nonexistent-file.osm.pbf"));
});
}
SECTION("should work when there is an exception in main thread before getting header") {
try {
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
REQUIRE(!reader.eof());
throw std::runtime_error("foo");
} catch (...) {
}
}
SECTION("should work when there is an exception in main thread while reading") {
try {
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
REQUIRE(!reader.eof());
auto header = reader.header();
throw std::runtime_error("foo");
} catch (...) {
}
}
}

View File

@ -0,0 +1,145 @@
#include "catch.hpp"
#include "utils.hpp"
#include <string>
#include <osmium/io/compression.hpp>
#include <osmium/io/xml_input.hpp>
// 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:
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 += "<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() 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 += "<?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");
} else {
for (int i = 1000; i < 2000; ++i) {
add_node(buffer, i);
}
}
} else if (m_read_count == 3) {
buffer += "</osm>";
}
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 (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 (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 (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 (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);
}
}

View File

@ -0,0 +1,114 @@
#include "catch.hpp"
#include "utils.hpp"
#include <string>
#include <osmium/builder/attr.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/compression.hpp>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/io/reader.hpp>
#include <osmium/thread/queue.hpp>
#include <osmium/thread/util.hpp>
class MockParser : public osmium::io::detail::Parser {
std::string m_fail_in;
public:
MockParser(osmium::io::detail::future_string_queue_type& input_queue,
osmium::io::detail::future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types,
const std::string& fail_in) :
Parser(input_queue, output_queue, header_promise, read_types),
m_fail_in(fail_in) {
}
void run() final {
osmium::thread::set_thread_name("_osmium_mock_in");
if (m_fail_in == "header") {
throw std::runtime_error("error in header");
}
set_header_value(osmium::io::Header{});
osmium::memory::Buffer buffer(1000);
osmium::builder::add_node(buffer, osmium::builder::attr::_user("foo"));
send_to_output_queue(std::move(buffer));
if (m_fail_in == "read") {
throw std::runtime_error("error in read");
}
}
}; // class MockParser
TEST_CASE("Test Reader using MockParser") {
std::string fail_in;
osmium::io::detail::ParserFactory::instance().register_parser(
osmium::io::file_format::xml,
[&](osmium::io::detail::future_string_queue_type& input_queue,
osmium::io::detail::future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<osmium::io::detail::Parser>(new MockParser(input_queue, output_queue, header_promise, read_which_entities, fail_in));
});
SECTION("no failure") {
fail_in = "";
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
auto header = reader.header();
REQUIRE(reader.read());
REQUIRE(!reader.read());
REQUIRE(reader.eof());
reader.close();
}
SECTION("throw in header") {
fail_in = "header";
try {
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
reader.header();
} catch (std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in header");
}
}
SECTION("throw in read") {
fail_in = "read";
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
reader.header();
try {
reader.read();
} catch (std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in read");
}
reader.close();
}
SECTION("throw in user code") {
fail_in = "";
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
reader.header();
try {
throw std::runtime_error("error in user code");
} catch (std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in user code");
}
REQUIRE(reader.read());
REQUIRE(!reader.read());
REQUIRE(reader.eof());
reader.close();
}
}

View File

@ -0,0 +1,94 @@
#include "catch.hpp"
#include <osmium/io/detail/string_table.hpp>
TEST_CASE("String store") {
osmium::io::detail::StringStore ss(100);
SECTION("empty") {
REQUIRE(ss.begin() == ss.end());
}
SECTION("add zero-length string") {
const char* s1 = ss.add("");
REQUIRE(std::string(s1) == "");
auto it = ss.begin();
REQUIRE(s1 == *it);
REQUIRE(std::string(*it) == "");
REQUIRE(++it == ss.end());
}
SECTION("add strings") {
const char* s1 = ss.add("foo");
const char* s2 = ss.add("bar");
REQUIRE(s1 != s2);
REQUIRE(std::string(s1) == "foo");
REQUIRE(std::string(s2) == "bar");
auto it = ss.begin();
REQUIRE(s1 == *it++);
REQUIRE(s2 == *it++);
REQUIRE(it == ss.end());
}
SECTION("add zero-length string and longer strings") {
ss.add("");
ss.add("xxx");
ss.add("yyyyy");
auto it = ss.begin();
REQUIRE(std::string(*it++) == "");
REQUIRE(std::string(*it++) == "xxx");
REQUIRE(std::string(*it++) == "yyyyy");
REQUIRE(it == ss.end());
}
SECTION("add many strings") {
for (const char* teststring : {"a", "abc", "abcd", "abcde"}) {
int i = 0;
for (; i < 100; ++i) {
ss.add(teststring);
}
for (const char* s : ss) {
REQUIRE(std::string(s) == teststring);
--i;
}
REQUIRE(i == 0);
ss.clear();
}
}
}
TEST_CASE("String table") {
osmium::io::detail::StringTable st;
SECTION("empty") {
REQUIRE(st.size() == 1);
REQUIRE(std::next(st.begin()) == st.end());
}
SECTION("add strings") {
REQUIRE(st.add("foo") == 1);
REQUIRE(st.add("bar") == 2);
REQUIRE(st.add("bar") == 2);
REQUIRE(st.add("baz") == 3);
REQUIRE(st.add("foo") == 1);
REQUIRE(st.size() == 4);
auto it = st.begin();
REQUIRE(std::string("") == *it++);
REQUIRE(std::string("foo") == *it++);
REQUIRE(std::string("bar") == *it++);
REQUIRE(std::string("baz") == *it++);
REQUIRE(it == st.end());
st.clear();
REQUIRE(st.size() == 1);
}
}

View File

@ -0,0 +1,118 @@
#include "catch.hpp"
#include "utils.hpp"
#include <algorithm>
#include <osmium/io/any_compression.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/io/xml_output.hpp>
#include <osmium/io/output_iterator.hpp>
#include <osmium/memory/buffer.hpp>
TEST_CASE("Writer") {
osmium::io::Header header;
header.set("generator", "test_writer.cpp");
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
osmium::memory::Buffer buffer = reader.read();
REQUIRE(buffer);
REQUIRE(buffer.committed() > 0);
auto num = std::distance(buffer.cbegin<osmium::OSMObject>(), buffer.cend<osmium::OSMObject>());
REQUIRE(num > 0);
REQUIRE(buffer.cbegin<osmium::OSMObject>()->id() == 1);
std::string filename;
SECTION("Empty writes") {
SECTION("Empty buffer") {
filename = "test-writer-out-empty-buffer.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
osmium::memory::Buffer empty_buffer(1024);
writer(std::move(empty_buffer));
writer.close();
}
SECTION("Invalid buffer") {
filename = "test-writer-out-invalid-buffer.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
osmium::memory::Buffer invalid_buffer;
writer(std::move(invalid_buffer));
writer.close();
}
osmium::io::Reader reader_check(filename);
osmium::memory::Buffer buffer_check = reader_check.read();
REQUIRE(!buffer_check);
}
SECTION("Successfull writes") {
SECTION("Writer buffer") {
filename = "test-writer-out-buffer.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
REQUIRE_THROWS_AS({
writer(osmium::memory::Buffer{});
}, osmium::io_error);
}
SECTION("Writer item") {
filename = "test-writer-out-item.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
for (const auto& item : buffer) {
writer(item);
}
writer.close();
}
SECTION("Writer output iterator") {
filename = "test-writer-out-iterator.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
auto it = osmium::io::make_output_iterator(writer);
std::copy(buffer.cbegin(), buffer.cend(), it);
writer.close();
}
osmium::io::Reader reader_check(filename);
osmium::memory::Buffer buffer_check = reader_check.read();
REQUIRE(buffer_check);
REQUIRE(buffer_check.committed() > 0);
REQUIRE(std::distance(buffer_check.cbegin<osmium::OSMObject>(), buffer_check.cend<osmium::OSMObject>()) == num);
REQUIRE(buffer_check.cbegin<osmium::OSMObject>()->id() == 1);
}
SECTION("Interrupted writer after open") {
int error = 0;
try {
filename = "test-writer-out-fail1.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
throw 1;
} catch (int e) {
error = e;
}
REQUIRE(error > 0);
}
SECTION("Interrupted writer after write") {
int error = 0;
try {
filename = "test-writer-out-fail2.osm";
osmium::io::Writer writer(filename, header, osmium::io::overwrite::allow);
writer(std::move(buffer));
throw 2;
} catch (int e) {
error = e;
}
REQUIRE(error > 0);
}
}

View File

@ -0,0 +1,99 @@
#include "catch.hpp"
#include "utils.hpp"
#include <stdexcept>
#include <string>
#include <osmium/io/compression.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/io/xml_output.hpp>
class MockCompressor : public osmium::io::Compressor {
std::string m_fail_in;
public:
MockCompressor(const std::string& fail_in) :
Compressor(osmium::io::fsync::no),
m_fail_in(fail_in) {
if (m_fail_in == "constructor") {
throw std::logic_error("constructor");
}
}
~MockCompressor() noexcept final = default;
void write(const std::string&) final {
if (m_fail_in == "write") {
throw std::logic_error("write");
}
}
void close() final {
if (m_fail_in == "close") {
throw std::logic_error("close");
}
}
}; // class MockCompressor
TEST_CASE("Write with mock compressor") {
std::string fail_in;
osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
[&](int, osmium::io::fsync) { return new MockCompressor(fail_in); },
[](int) { return nullptr; },
[](const char*, size_t) { return nullptr; }
);
osmium::io::Header header;
header.set("generator", "test_writer_with_mock_compression.cpp");
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
osmium::memory::Buffer buffer = reader.read();
REQUIRE(buffer);
REQUIRE(buffer.committed() > 0);
auto num = std::distance(buffer.cbegin<osmium::OSMObject>(), buffer.cend<osmium::OSMObject>());
REQUIRE(num > 0);
SECTION("fail on construction") {
fail_in = "constructor";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
SECTION("fail on write") {
fail_in = "write";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-write.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
SECTION("fail on close") {
fail_in = "close";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-close.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
}

View File

@ -0,0 +1,105 @@
#include "catch.hpp"
#include "utils.hpp"
#include <stdexcept>
#include <string>
#include <osmium/io/compression.hpp>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/xml_input.hpp>
#include <osmium/io/writer.hpp>
class MockOutputFormat : public osmium::io::detail::OutputFormat {
std::string m_fail_in;
public:
MockOutputFormat(const osmium::io::File&, osmium::io::detail::future_string_queue_type& output_queue, const std::string& fail_in) :
OutputFormat(output_queue),
m_fail_in(fail_in) {
}
void write_header(const osmium::io::Header&) final {
if (m_fail_in == "header") {
throw std::logic_error("header");
}
send_to_output_queue(std::string{"header"});
}
void write_buffer(osmium::memory::Buffer&&) final {
if (m_fail_in == "write") {
throw std::logic_error("write");
}
send_to_output_queue(std::string{"write"});
}
void write_end() final {
if (m_fail_in == "write_end") {
throw std::logic_error("write_end");
}
send_to_output_queue(std::string{"end"});
}
}; // class MockOutputFormat
TEST_CASE("Test Writer with MockOutputFormat") {
std::string fail_in;
osmium::io::detail::OutputFormatFactory::instance().register_output_format(
osmium::io::file_format::xml,
[&](const osmium::io::File& file, osmium::io::detail::future_string_queue_type& output_queue) {
return new MockOutputFormat(file, output_queue, fail_in);
});
osmium::io::Header header;
header.set("generator", "test_writer_with_mock_encoder.cpp");
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
osmium::memory::Buffer buffer = reader.read();
REQUIRE(buffer);
REQUIRE(buffer.committed() > 0);
auto num = std::distance(buffer.cbegin<osmium::OSMObject>(), buffer.cend<osmium::OSMObject>());
REQUIRE(num > 0);
SECTION("error in header") {
fail_in = "header";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
SECTION("error in write") {
fail_in = "write";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
SECTION("error in write_end") {
fail_in = "write_end";
REQUIRE_THROWS_AS({
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
}, std::logic_error);
}
}

View File

@ -0,0 +1,222 @@
#include "catch.hpp"
#include <algorithm>
#include <osmium/builder/attr.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/tags/taglist.hpp>
#include <osmium/tags/filter.hpp>
#include <osmium/tags/regex_filter.hpp>
template <class TFilter>
void check_filter(const osmium::TagList& tag_list, const TFilter filter, const std::vector<bool>& reference) {
REQUIRE(tag_list.size() == reference.size());
auto t_it = tag_list.begin();
for (auto it = reference.begin(); it != reference.end(); ++t_it, ++it) {
REQUIRE(filter(*t_it) == *it);
}
typename TFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
typename TFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
REQUIRE(std::distance(fi_begin, fi_end) == std::count(reference.begin(), reference.end(), true));
}
const osmium::TagList& make_tag_list(osmium::memory::Buffer& buffer, std::initializer_list<std::pair<const char*, const char*>> tags) {
auto pos = osmium::builder::add_tag_list(buffer, osmium::builder::attr::_tags(tags));
return buffer.get<osmium::TagList>(pos);
}
TEST_CASE("Filter") {
SECTION("KeyFilter_matches_some_tags") {
osmium::tags::KeyFilter filter(false);
filter.add(true, "highway").add(true, "railway");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" }, // match
{ "name", "Main Street" }, // no match
{ "source", "GPS" } // no match
});
std::vector<bool> results = { true, false, false };
check_filter(tag_list, filter, results);
}
SECTION("KeyFilter_iterator_filters_tags") {
osmium::tags::KeyFilter filter(false);
filter.add(true, "highway").add(true, "source");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tl = make_tag_list(buffer, {
{ "highway", "primary" }, // match
{ "name", "Main Street" }, // no match
{ "source", "GPS" } // no match
});
osmium::tags::KeyFilter::iterator it(filter, tl.begin(), tl.end());
const osmium::tags::KeyFilter::iterator end(filter, tl.end(), tl.end());
REQUIRE(2 == std::distance(it, end));
REQUIRE(it != end);
REQUIRE(std::string("highway") == it->key());
REQUIRE(std::string("primary") == it->value());
++it;
REQUIRE(std::string("source") == it->key());
REQUIRE(std::string("GPS") == it->value());
REQUIRE(++it == end);
}
SECTION("KeyValueFilter_matches_some_tags") {
osmium::tags::KeyValueFilter filter(false);
filter.add(true, "highway", "residential").add(true, "highway", "primary").add(true, "railway");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "railway", "tram" },
{ "source", "GPS" }
});
std::vector<bool> results = {true, true, false};
check_filter(tag_list, filter, results);
}
SECTION("KeyValueFilter_ordering_matters") {
osmium::tags::KeyValueFilter filter1(false);
filter1.add(true, "highway").add(false, "highway", "road");
osmium::tags::KeyValueFilter filter2(false);
filter2.add(false, "highway", "road").add(true, "highway");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list1 = make_tag_list(buffer, {
{ "highway", "road" },
{ "name", "Main Street" }
});
const osmium::TagList& tag_list2 = make_tag_list(buffer, {
{ "highway", "primary" },
{ "name", "Main Street" }
});
check_filter(tag_list1, filter1, {true, false});
check_filter(tag_list1, filter2, {false, false});
check_filter(tag_list2, filter2, {true, false});
}
SECTION("KeyValueFilter_matches_against_taglist_with_any") {
osmium::tags::KeyValueFilter filter(false);
filter.add(true, "highway", "primary").add(true, "name");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "railway", "tram" },
{ "source", "GPS" }
});
REQUIRE( osmium::tags::match_any_of(tag_list, filter));
REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter_matches_against_taglist_with_all") {
osmium::tags::KeyValueFilter filter(false);
filter.add(true, "highway", "primary").add(true, "name");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "name", "Main Street" }
});
REQUIRE( osmium::tags::match_any_of(tag_list, filter));
REQUIRE( osmium::tags::match_all_of(tag_list, filter));
REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter_matches_against_taglist_with_none") {
osmium::tags::KeyValueFilter filter(false);
filter.add(true, "highway", "road").add(true, "source");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "name", "Main Street" }
});
REQUIRE(!osmium::tags::match_any_of(tag_list, filter));
REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
REQUIRE( osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter_matches_against_taglist_with_any_called_with_rvalue") {
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "railway", "tram" },
{ "source", "GPS" }
});
REQUIRE(osmium::tags::match_any_of(tag_list,
osmium::tags::KeyValueFilter().add(true, "highway", "primary").add(true, "name")));
}
SECTION("RegexFilter_matches_some_tags") {
osmium::tags::RegexFilter filter(false);
filter.add(true, "highway", std::regex(".*_link"));
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list1 = make_tag_list(buffer, {
{ "highway", "primary_link" },
{ "source", "GPS" }
});
const osmium::TagList& tag_list2 = make_tag_list(buffer, {
{ "highway", "primary" },
{ "source", "GPS" }
});
check_filter(tag_list1, filter, {true, false});
check_filter(tag_list2, filter, {false, false});
}
SECTION("RegexFilter_matches_some_tags_with_lvalue_regex") {
osmium::tags::RegexFilter filter(false);
std::regex r(".*straße");
filter.add(true, "name", r);
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "name", "Hauptstraße" }
});
check_filter(tag_list, filter, {false, true});
}
SECTION("KeyPrefixFilter_matches_some_tags") {
osmium::tags::KeyPrefixFilter filter(false);
filter.add(true, "name:");
osmium::memory::Buffer buffer(10240);
const osmium::TagList& tag_list = make_tag_list(buffer, {
{ "highway", "primary" },
{ "name:de", "Hauptstraße" }
});
check_filter(tag_list, filter, {false, true});
}
}

View File

@ -0,0 +1,61 @@
#include "catch.hpp"
#include <iterator>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/tag.hpp>
TEST_CASE("Operators") {
SECTION("Equal") {
osmium::memory::Buffer buffer1(10240);
{
osmium::builder::TagListBuilder tl_builder(buffer1);
tl_builder.add_tag("highway", "primary");
tl_builder.add_tag("name", "Main Street");
tl_builder.add_tag("source", "GPS");
}
buffer1.commit();
osmium::memory::Buffer buffer2(10240);
{
osmium::builder::TagListBuilder tl_builder(buffer2);
tl_builder.add_tag("highway", "primary");
}
buffer2.commit();
const osmium::TagList& tl1 = buffer1.get<const osmium::TagList>(0);
const osmium::TagList& tl2 = buffer2.get<const osmium::TagList>(0);
auto tagit1 = tl1.begin();
auto tagit2 = tl2.begin();
REQUIRE(*tagit1 == *tagit2);
++tagit1;
REQUIRE(!(*tagit1 == *tagit2));
}
SECTION("Order") {
osmium::memory::Buffer buffer(10240);
{
osmium::builder::TagListBuilder tl_builder(buffer);
tl_builder.add_tag("highway", "residential");
tl_builder.add_tag("highway", "primary");
tl_builder.add_tag("name", "Main Street");
tl_builder.add_tag("amenity", "post_box");
}
buffer.commit();
const osmium::TagList& tl = buffer.get<const osmium::TagList>(0);
const osmium::Tag& t1 = *(tl.begin());
const osmium::Tag& t2 = *(std::next(tl.begin(), 1));
const osmium::Tag& t3 = *(std::next(tl.begin(), 2));
const osmium::Tag& t4 = *(std::next(tl.begin(), 3));
REQUIRE(t2 < t1);
REQUIRE(t1 < t3);
REQUIRE(t2 < t3);
REQUIRE(t4 < t1);
}
}

View File

@ -0,0 +1,224 @@
#include "catch.hpp"
#include <map>
#include <vector>
#include <osmium/builder/attr.hpp>
#include <osmium/builder/builder_helper.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/tag.hpp>
using namespace osmium::builder::attr;
TEST_CASE("create tag list") {
osmium::memory::Buffer buffer(10240);
SECTION("with TagListBuilder from char*") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag("highway", "primary");
builder.add_tag("name", "Main Street");
}
buffer.commit();
}
SECTION("with TagListBuilder from pair<const char*, const char*>") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag(std::pair<const char*, const char*>{"highway", "primary"});
builder.add_tag("name", "Main Street");
}
buffer.commit();
}
SECTION("with TagListBuilder from pair<const char* const, const char*>") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag(std::pair<const char* const, const char*>{"highway", "primary"});
builder.add_tag("name", "Main Street");
}
buffer.commit();
}
SECTION("with TagListBuilder from pair<const char*, const char* const>") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag(std::pair<const char*, const char* const>{"highway", "primary"});
builder.add_tag("name", "Main Street");
}
buffer.commit();
}
SECTION("with TagListBuilder from pair<const char* const, const char* const>") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag(std::pair<const char* const, const char* const>{"highway", "primary"});
builder.add_tag("name", "Main Street");
}
buffer.commit();
}
SECTION("with TagListBuilder from char* with length") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag("highway", strlen("highway"), "primary", strlen("primary"));
builder.add_tag("nameXX", 4, "Main Street", 11);
}
buffer.commit();
}
SECTION("with TagListBuilder from std::string") {
{
osmium::builder::TagListBuilder builder(buffer);
builder.add_tag(std::string("highway"), std::string("primary"));
const std::string source = "name";
std::string gps = "Main Street";
builder.add_tag(source, gps);
}
buffer.commit();
}
SECTION("with add_tag_list from pair<const char*, const char*>") {
osmium::builder::add_tag_list(buffer,
_tag(std::pair<const char*, const char*>{"highway", "primary"}),
_tag("name", "Main Street")
);
}
SECTION("with add_tag_list from pair<const char* const, const char*>") {
osmium::builder::add_tag_list(buffer,
_tag(std::pair<const char* const, const char*>{"highway", "primary"}),
_tag("name", "Main Street")
);
}
SECTION("with add_tag_list from pair<const char*, const char* const>") {
osmium::builder::add_tag_list(buffer,
_tag(std::pair<const char*, const char* const>{"highway", "primary"}),
_tag("name", "Main Street")
);
}
SECTION("with add_tag_list from pair<const char* const, const char* const>") {
osmium::builder::add_tag_list(buffer,
_tag(std::pair<const char* const, const char* const>{"highway", "primary"}),
_tag("name", "Main Street")
);
}
SECTION("with add_tag_list from vector of pairs (const/const)") {
std::vector<std::pair<const char* const, const char* const>> v{
{ "highway", "primary" },
{ "name", "Main Street" }
};
osmium::builder::add_tag_list(buffer, _tags(v));
}
SECTION("with add_tag_list from vector of pairs (const/nc)") {
std::vector<std::pair<const char* const, const char*>> v{
{ "highway", "primary" },
{ "name", "Main Street" }
};
osmium::builder::add_tag_list(buffer, _tags(v));
}
SECTION("with add_tag_list from vector of pairs (nc/const)") {
std::vector<std::pair<const char*, const char* const>> v{
{ "highway", "primary" },
{ "name", "Main Street" }
};
osmium::builder::add_tag_list(buffer, _tags(v));
}
SECTION("with add_tag_list from vector of pairs (nc/nc)") {
std::vector<std::pair<const char*, const char*>> v{
{ "highway", "primary" },
{ "name", "Main Street" }
};
osmium::builder::add_tag_list(buffer, _tags(v));
}
SECTION("with add_tag_list from initializer list") {
osmium::builder::add_tag_list(buffer, _tags({
{ "highway", "primary" },
{ "name", "Main Street" }
}));
}
SECTION("with add_tag_list from _tag") {
osmium::builder::add_tag_list(buffer,
_tag("highway", "primary"),
_tag("name", "Main Street")
);
}
SECTION("with add_tag_list from map") {
std::map<const char*, const char*> m{
{ "highway", "primary" },
{ "name", "Main Street" }
};
osmium::builder::add_tag_list(buffer, _tags(m));
}
SECTION("with build_tag_list_from_func") {
osmium::builder::build_tag_list_from_func(buffer, [](osmium::builder::TagListBuilder& tlb) {
tlb.add_tag("highway", "primary");
tlb.add_tag("name", "Main Street");
});
}
const osmium::TagList& tl = *buffer.begin<osmium::TagList>();
REQUIRE(osmium::item_type::tag_list == tl.type());
REQUIRE(2 == tl.size());
auto it = tl.begin();
REQUIRE(std::string("highway") == it->key());
REQUIRE(std::string("primary") == it->value());
++it;
REQUIRE(std::string("name") == it->key());
REQUIRE(std::string("Main Street") == it->value());
++it;
REQUIRE(it == tl.end());
REQUIRE(std::string("primary") == tl.get_value_by_key("highway"));
REQUIRE(nullptr == tl.get_value_by_key("foo"));
REQUIRE(std::string("default") == tl.get_value_by_key("foo", "default"));
REQUIRE(std::string("Main Street") == tl["name"]);
}
TEST_CASE("empty keys and values are okay") {
osmium::memory::Buffer buffer(10240);
auto pos = osmium::builder::add_tag_list(buffer,
_tag("empty value", ""),
_tag("", "empty key")
);
const osmium::TagList& tl = buffer.get<osmium::TagList>(pos);
REQUIRE(osmium::item_type::tag_list == tl.type());
REQUIRE(2 == tl.size());
auto it = tl.begin();
REQUIRE(std::string("empty value") == it->key());
REQUIRE(std::string("") == it->value());
++it;
REQUIRE(std::string("") == it->key());
REQUIRE(std::string("empty key") == it->value());
++it;
REQUIRE(it == tl.end());
REQUIRE(std::string("") == tl.get_value_by_key("empty value"));
REQUIRE(std::string("empty key") == tl.get_value_by_key(""));
}
TEST_CASE("tag key or value is too long") {
osmium::memory::Buffer buffer(10240);
osmium::builder::TagListBuilder builder(buffer);
const char kv[2000] = "";
builder.add_tag(kv, 1, kv, 1000);
REQUIRE_THROWS(builder.add_tag(kv, 1500, kv, 1));
REQUIRE_THROWS(builder.add_tag(kv, 1, kv, 1500));
}

View File

@ -0,0 +1,72 @@
#include "catch.hpp"
#include <chrono>
#include <stdexcept>
#include <thread>
#include <osmium/thread/pool.hpp>
#include <osmium/util/compatibility.hpp>
struct test_job_with_result {
int operator()() const {
return 42;
}
};
struct test_job_throw {
OSMIUM_NORETURN void operator()() const {
throw std::runtime_error("exception in pool thread");
}
};
TEST_CASE("number of threads in pool") {
// hardcoded setting
REQUIRE(osmium::thread::detail::get_pool_size( 1, 0, 2) == 1);
REQUIRE(osmium::thread::detail::get_pool_size( 4, 0, 2) == 4);
REQUIRE(osmium::thread::detail::get_pool_size( 4, 0, 4) == 4);
REQUIRE(osmium::thread::detail::get_pool_size(16, 0, 4) == 16);
REQUIRE(osmium::thread::detail::get_pool_size(16, 0, 16) == 16);
REQUIRE(osmium::thread::detail::get_pool_size( 8, 4, 2) == 8);
REQUIRE(osmium::thread::detail::get_pool_size( 8, 16, 2) == 8);
REQUIRE(osmium::thread::detail::get_pool_size(-2, 16, 2) == 1);
REQUIRE(osmium::thread::detail::get_pool_size(-2, 16, 8) == 6);
// user decides through OSMIUM_POOL_THREADS env variable
REQUIRE(osmium::thread::detail::get_pool_size( 0, 0, 2) == 1);
REQUIRE(osmium::thread::detail::get_pool_size( 0, -2, 4) == 2);
REQUIRE(osmium::thread::detail::get_pool_size( 0, -1, 8) == 7);
REQUIRE(osmium::thread::detail::get_pool_size( 0, 0, 16) == 14);
REQUIRE(osmium::thread::detail::get_pool_size( 0, 1, 16) == 1);
REQUIRE(osmium::thread::detail::get_pool_size( 0, 2, 16) == 2);
REQUIRE(osmium::thread::detail::get_pool_size( 0, 4, 16) == 4);
REQUIRE(osmium::thread::detail::get_pool_size( 0, 8, 16) == 8);
// outliers
REQUIRE(osmium::thread::detail::get_pool_size(-100, 0, 16) == 1);
REQUIRE(osmium::thread::detail::get_pool_size(1000, 0, 16) == 256);
}
TEST_CASE("thread") {
auto& pool = osmium::thread::Pool::instance();
SECTION("can get access to thread pool") {
REQUIRE(pool.queue_empty());
}
SECTION("can send job to thread pool") {
auto future = pool.submit(test_job_with_result {});
REQUIRE(future.get() == 42);
}
SECTION("can throw from job in thread pool") {
auto future = pool.submit(test_job_throw {});
REQUIRE_THROWS_AS(future.get(), std::runtime_error);
}
}

Some files were not shown because too many files have changed in this diff Show More