/* Copyright 2018 David Robillard 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 #include #include #include #include #include template static int test_move_only(T&& obj) { static_assert(!std::is_copy_constructible::value, ""); static_assert(!std::is_copy_assignable::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 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 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::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::make_string("node"))); const serd::Node node = serd::make_string("node"); const serd::Node other = serd::make_string("other"); // Truthiness CHECK(!serd::Optional()); CHECK(!serd::Optional(nullptr)); CHECK(serd::Optional(node)); // Comparison and general sanity serd::Optional 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 copied{optional}; CHECK(copied == nonconst); CHECK(copied.ptr() != c_node); optional = std::move(nonconst); serd::Optional moved{std::move(optional)}; CHECK(moved.ptr() == c_node); CHECK(!optional); serd::Optional copy_assigned; copy_assigned = optional; CHECK(copy_assigned == optional); CHECK(copy_assigned.ptr() != c_node); serd::Optional 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: ." "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 .\n" "@prefix eg: .\n" "\n" "\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; }