aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-06-16 10:26:47 -0400
committerDavid Robillard <d@drobilla.net>2018-11-25 22:12:48 +0100
commita70ee297d71d03c004e78aa1061877f231cfd8d2 (patch)
tree7f0095fcda00b69901d1f133e7c8b4ffc358884b /tests
parent535bc536f0541792b0bab84041e7d82eaa457368 (diff)
downloadserd-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.cpp397
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;
+}