diff options
author | David Robillard <d@drobilla.net> | 2018-06-16 10:26:47 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2018-11-25 22:12:48 +0100 |
commit | a70ee297d71d03c004e78aa1061877f231cfd8d2 (patch) | |
tree | 7f0095fcda00b69901d1f133e7c8b4ffc358884b /tests | |
parent | 535bc536f0541792b0bab84041e7d82eaa457368 (diff) | |
download | serd-a70ee297d71d03c004e78aa1061877f231cfd8d2.tar.gz serd-a70ee297d71d03c004e78aa1061877f231cfd8d2.tar.bz2 serd-a70ee297d71d03c004e78aa1061877f231cfd8d2.zip |
WIP: Add C++ bindings
Diffstat (limited to 'tests')
-rw-r--r-- | tests/serd_cxx_test.cpp | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/tests/serd_cxx_test.cpp b/tests/serd_cxx_test.cpp new file mode 100644 index 00000000..1f5656cc --- /dev/null +++ b/tests/serd_cxx_test.cpp @@ -0,0 +1,397 @@ +/* + Copyright 2018 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "test_utils.h" + +#include "serd/serd.hpp" + +#include <cassert> +#include <iostream> +#include <sstream> +#include <type_traits> +#include <utility> +#include <vector> + +template <typename T> +static int +test_move_only(T&& obj) +{ + static_assert(!std::is_copy_constructible<T>::value, ""); + static_assert(!std::is_copy_assignable<T>::value, ""); + + const auto* const ptr = obj.c_obj(); + + // Move construct + T moved{std::move(obj)}; + CHECK(moved.c_obj() == ptr); + CHECK(!obj.c_obj()); + + // Move assign + obj = std::move(moved); + CHECK(obj.c_obj() == ptr); + CHECK(!moved.c_obj()); + + return 0; +} + +template <typename T> +static int +test_copy(const T& obj) +{ + T copy{obj}; + CHECK(copy == obj); + + T copy_assigned{obj}; + copy_assigned = obj; + CHECK(copy_assigned == obj); + + return 0; +} + +template <typename T> +static int +test_copy_move(const T& obj) +{ + T copy{obj}; + CHECK(copy == obj); + + T moved{std::move(copy)}; + CHECK(moved == obj); + CHECK(copy != obj); + + T copy_assigned{obj}; + copy_assigned = obj; + CHECK(copy_assigned == obj); + + T move_assigned{obj}; + move_assigned = std::move(copy_assigned); + CHECK(move_assigned == obj); + CHECK(copy_assigned != obj); + + return 0; +} + +static int +test_operators() +{ + int st = 0; + + serd::World world; + + serd::Model model(world, serd::IndexOption::SPO, {}); + model.insert(serd::make_uri("http://example.org/s"), + serd::make_uri("http://example.org/p"), + serd::make_uri("http://example.org/o")); + + serd::Sink sink; + serd::Env env; + + std::ostringstream stream; + serd::ByteSink byte_sink{stream}; + + st |= test_copy_move( + serd::Optional<serd::Node>{serd::make_string("hello")}); + st |= test_move_only(serd::World{}); + st |= test_move_only(*model.begin()); + st |= test_copy_move(serd::Env{}); + // st |= test_move_only(serd::Reader{world, serd::Syntax::Turtle, sink, 4096}); + st |= test_move_only(serd::ByteSink{stream}); + st |= test_copy_move(model.begin()); + st |= test_copy_move(model.all()); + // Sink + st |= test_copy_move(model); + // st |= test_move_only(serd::Inserter{model, env}); + // st |= test_copy_move(model.all()); + // st |= test_move_only(serd::Sink{}); + // st |= test_move(serd::Statement{}); + + st |= test_copy_move(serd::Env{}); + + return st; +} + +static int +test_optional() +{ + test_copy_move(serd::Optional<serd::Node>(serd::make_string("node"))); + + const serd::Node node = serd::make_string("node"); + const serd::Node other = serd::make_string("other"); + + // Truthiness + CHECK(!serd::Optional<serd::Node>()); + CHECK(!serd::Optional<serd::Node>(nullptr)); + CHECK(serd::Optional<serd::Node>(node)); + + // Comparison and general sanity + serd::Optional<serd::Node> optional{node}; + CHECK(optional); + CHECK(optional == node); + CHECK(optional != other); + CHECK(*optional == node); + CHECK(optional->str() == "node"); + CHECK(optional.ptr() != node.c_obj()); // non-const, must be a copy + + // Reset + optional.reset(); + CHECK(!optional); + CHECK(!optional.ptr()); + + // Copying and moving + serd::Node nonconst = serd::make_string("nonconst"); + const SerdNode* c_node = nonconst.c_obj(); + + optional = nonconst; + serd::Optional<serd::Node> copied{optional}; + CHECK(copied == nonconst); + CHECK(copied.ptr() != c_node); + + optional = std::move(nonconst); + serd::Optional<serd::Node> moved{std::move(optional)}; + CHECK(moved.ptr() == c_node); + CHECK(!optional); + + serd::Optional<serd::Node> copy_assigned; + copy_assigned = optional; + CHECK(copy_assigned == optional); + CHECK(copy_assigned.ptr() != c_node); + + serd::Optional<serd::Node> move_assigned; + move_assigned = std::move(moved); + CHECK(move_assigned.ptr() == c_node); + CHECK(!optional); + + return 0; +} + +static int +test_node(const serd::Node& node) +{ + test_copy_move(node); + + if (node.datatype()) { + return test_node(*node.datatype()); + } else if (node.language()) { + return test_node(*node.language()); + } + return 0; +} + +static int +test_nodes() +{ + using namespace serd; + + const auto type = make_uri("http://example.org/Type"); + const auto base = make_uri("http://example.org/"); + const auto root = make_uri("http://example.org/"); + + CHECK(!test_node(make_string("hello"))); + CHECK(!test_node(make_plain_literal("hello", "en"))); + CHECK(!test_node(make_typed_literal("hello", type))); + CHECK(!test_node(make_blank("blank"))); + CHECK(!test_node(make_curie("eg:curie"))); + CHECK(!test_node(make_uri("http://example.org/thing"))); + CHECK(!test_node(make_resolved_uri("thing", base))); + CHECK(!test_node(make_file_uri("/foo/bar", "host"))); + CHECK(!test_node(make_file_uri("/foo/bar"))); + CHECK(!test_node(make_file_uri("/foo/bar", "host"))); + CHECK(!test_node(make_file_uri("/foo/bar"))); + CHECK(!test_node(make_relative_uri("http://example.org/a", base))); + CHECK(!test_node(make_relative_uri("http://example.org/a", base, root))); + CHECK(!test_node(make_decimal(1.2, 7))); + CHECK(!test_node(make_decimal(3.4, 7, type))); + CHECK(!test_node(make_integer(56))); + CHECK(!test_node(make_integer(78, type))); + CHECK(!test_node(make_blob("blob", 4, true))); + CHECK(!test_node(make_blob("blob", 4, true, type))); + + return 0; +} + +static int +test_reader() +{ + struct Sink : public serd::Sink + { + serd::Status statement(serd::StatementFlags, + const serd::Statement& statement) override + { + ++n_statements; + stream << statement.subject() << " " << statement.predicate() << " " + << statement.object() << std::endl; + return serd::Status::Success; + } + + size_t n_statements{}; + std::stringstream stream{}; + }; + + Sink sink; + serd::World world; + serd::Reader reader(world, serd::Syntax::Turtle, sink, 4096); + + reader.start_string("@prefix eg: <http://example.org> ." + "eg:s eg:p eg:o1 , eg:o2 ."); + reader.read_document(); + + CHECK(sink.n_statements == 2); + CHECK(sink.stream.str() == "eg:s eg:p eg:o1\neg:s eg:p eg:o2\n"); + + return 0; +} + +static int +test_writer() +{ + serd::World world; + serd::Env env; + std::ostringstream stream; + serd::ByteSink sink(stream); + serd::Writer writer(world, serd::Syntax::Turtle, 0, env, sink); + + writer.base(serd::make_uri("http://drobilla.net/base/")); + writer.set_root_uri(serd::make_uri("http://drobilla.net/")); + writer.prefix(serd::make_string("eg"), + serd::make_uri("http://example.org/")); + writer.nodes(0, + serd::make_uri("http://drobilla.net/base/s"), + serd::make_uri("http://example.org/p"), + serd::make_uri("http://drobilla.net/o")); + + writer.finish(); + + CHECK(stream.str() == "@base <http://drobilla.net/base/> .\n" + "@prefix eg: <http://example.org/> .\n" + "\n" + "<s>\n" + "\teg:p <../o> .\n"); + + return 0; +} + +static int +test_env() +{ + serd::Env env; + + const auto base = serd::make_uri("http://drobilla.net/"); + env.set_base_uri(base); + CHECK(env.base_uri() == base); + + env.set_prefix(serd::make_string("eg"), + serd::make_uri("http://example.org/")); + + CHECK(env.qualify(serd::make_uri("http://example.org/foo")) == + serd::make_curie("eg:foo")); + + CHECK(env.expand(serd::make_uri("foo")) == + serd::make_uri("http://drobilla.net/foo")); + + serd::Env copied{env}; + CHECK(copied.qualify(serd::make_uri("http://example.org/foo")) == + serd::make_curie("eg:foo")); + + CHECK(copied.expand(serd::make_uri("foo")) == + serd::make_uri("http://drobilla.net/foo")); + + serd::Env assigned; + assigned = env; + auto curie = env.qualify(serd::make_uri("http://example.org/foo")); + + CHECK(assigned.qualify(serd::make_uri("http://example.org/foo")) == + serd::make_curie("eg:foo")); + + CHECK(assigned.expand(serd::make_uri("foo")) == + serd::make_uri("http://drobilla.net/foo")); + + return 0; +} + +static int +test_model() +{ + serd::World world; + serd::Model model( + world, serd::IndexOption::SPO | serd::IndexOption::OPS, 0); + + CHECK(model.empty()); + + const auto s = serd::make_uri("http://example.org/s"); + const auto p = serd::make_uri("http://example.org/p"); + const auto o1 = serd::make_uri("http://example.org/o1"); + const auto o2 = serd::make_uri("http://example.org/o2"); + + model.insert(s, p, o1); + model.insert(s, p, o2); + + CHECK(!model.empty()); + CHECK(model.size() == 2); + CHECK(model.ask(s, p, o1)); + CHECK(model.ask(s, p, o1)); + CHECK(!model.ask(s, p, s)); + + size_t total_count = 0; + for (const auto& statement : model) { + CHECK(statement.subject() == s); + CHECK(statement.predicate() == p); + CHECK(statement.object() == o1 || statement.object() == o2); + ++total_count; + } + CHECK(total_count == 2); + + size_t o1_count = 0; + for (const auto& statement : model.range({}, {}, o1)) { + CHECK(statement.subject() == s); + CHECK(statement.predicate() == p); + CHECK(statement.object() == o1); + ++o1_count; + } + CHECK(o1_count == 1); + + size_t o2_count = 0; + for (const auto& statement : model.range({}, {}, o2)) { + CHECK(statement.subject() == s); + CHECK(statement.predicate() == p); + CHECK(statement.object() == o2); + ++o2_count; + } + CHECK(o2_count == 1); + + serd::Model copy(model); + CHECK(copy == model); + + copy.insert(s, p, s); + CHECK(copy != model); + + return 0; +} + +int +main() +{ + int st = 0; + + st |= test_operators(); + st |= test_optional(); + st |= test_nodes(); + st |= test_env(); + st |= test_reader(); + st |= test_writer(); + st |= test_model(); + + return st; +} |