summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-07-15 16:27:19 +0200
committerDavid Robillard <d@drobilla.net>2020-07-16 23:37:49 +0200
commit133de18003a7fe1d7ab4b88beeeef413d1eb28ac (patch)
tree4720a92b811032b0905b532d5df44706150ab0b8 /test
parent35177a5becb4955ad3c48eaabd83bcc0fa60ef94 (diff)
downloadlilv-133de18003a7fe1d7ab4b88beeeef413d1eb28ac.tar.gz
lilv-133de18003a7fe1d7ab4b88beeeef413d1eb28ac.tar.bz2
lilv-133de18003a7fe1d7ab4b88beeeef413d1eb28ac.zip
Split test suite up into several independent programs
Diffstat (limited to 'test')
-rw-r--r--test/lilv_test.c2137
-rw-r--r--test/lilv_test_utils.h14
-rw-r--r--test/test_bad_port_index.c58
-rw-r--r--test/test_bad_port_symbol.c58
-rw-r--r--test/test_classes.c75
-rw-r--r--test/test_discovery.c96
-rw-r--r--test/test_get_symbol.c81
-rw-r--r--test/test_no_author.c87
-rw-r--r--test/test_no_verify.c48
-rw-r--r--test/test_plugin.c296
-rw-r--r--test/test_port.c331
-rw-r--r--test/test_preset.c93
-rw-r--r--test/test_project.c97
-rw-r--r--test/test_project_no_author.c87
-rw-r--r--test/test_prototype.c100
-rw-r--r--test/test_reload_bundle.c92
-rw-r--r--test/test_replace_version.c105
-rw-r--r--test/test_state.c581
-rw-r--r--test/test_string.c94
-rw-r--r--test/test_ui.c180
-rw-r--r--test/test_util.c63
-rw-r--r--test/test_value.c173
-rw-r--r--test/test_verify.c57
-rw-r--r--test/test_world.c51
24 files changed, 2917 insertions, 2137 deletions
diff --git a/test/lilv_test.c b/test/lilv_test.c
deleted file mode 100644
index 92e98be..0000000
--- a/test/lilv_test.c
+++ /dev/null
@@ -1,2137 +0,0 @@
-/*
- Copyright 2007-2019 David Robillard <http://drobilla.net>
- Copyright 2008 Krzysztof Foltman
-
- 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.
-*/
-
-#define _POSIX_C_SOURCE 200809L /* for setenv */
-#define _XOPEN_SOURCE 600 /* for mkstemp */
-
-#undef NDEBUG
-
-#include "lilv_test_utils.h"
-
-#include "../src/lilv_internal.h"
-
-#ifdef _WIN32
-# include <direct.h>
-# include <io.h>
-# define mkdir(path, flags) _mkdir(path)
-# define setenv(n, v, r) SetEnvironmentVariable((n), (v))
-# define unsetenv(n) SetEnvironmentVariable((n), NULL)
-# define mkstemp(pat) _mktemp(pat)
-#else
-# include <unistd.h>
-#endif
-
-#include "lilv/lilv.h"
-#include "lv2/core/lv2.h"
-#include "lv2/presets/presets.h"
-#include "lv2/state/state.h"
-#include "lv2/urid/urid.h"
-#include "serd/serd.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <float.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#define TEST_PATH_MAX 1024
-
-#if defined(__APPLE__)
-# define SHLIB_EXT ".dylib"
-#elif defined(_WIN32)
-# define SHLIB_EXT ".dll"
-#else
-# define SHLIB_EXT ".so"
-#endif
-
-#define TEST_CASE(name) { #name, test_##name }
-
-typedef int (*TestFunc)(LilvTestEnv*);
-
-struct TestCase {
- const char* title;
- TestFunc func;
-};
-
-static int
-test_value(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
- "] .")) {
- return 1;
- }
-
- LilvNode* uval = lilv_new_uri(world, "http://example.org");
- LilvNode* sval = lilv_new_string(world, "Foo");
- LilvNode* ival = lilv_new_int(world, 42);
- LilvNode* fval = lilv_new_float(world, 1.6180);
-
- assert(lilv_node_is_uri(uval));
- assert(lilv_node_is_string(sval));
- assert(lilv_node_is_int(ival));
- assert(lilv_node_is_float(fval));
-
- assert(!lilv_node_is_literal(NULL));
- assert(!lilv_node_is_literal(uval));
- assert(lilv_node_is_literal(sval));
- assert(lilv_node_is_literal(ival));
- assert(lilv_node_is_literal(fval));
- assert(!lilv_node_get_path(fval, NULL));
-
- assert(!strcmp(lilv_node_as_uri(uval), "http://example.org"));
- assert(!strcmp(lilv_node_as_string(sval), "Foo"));
- assert(lilv_node_as_int(ival) == 42);
- assert(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON);
- assert(isnan(lilv_node_as_float(sval)));
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
- assert(!strcmp(lilv_uri_to_path("file:///foo"), "/foo"));
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
-# pragma GCC diagnostic pop
-#endif
-
- LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar");
- LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo");
- LilvNode* host_abs = lilv_new_file_uri(world, "host", "/foo/bar");
- LilvNode* host_rel = lilv_new_file_uri(world, "host", "foo");
-
- assert(!strcmp(lilv_node_as_uri(loc_abs), "file:///foo/bar"));
- assert(!strncmp(lilv_node_as_uri(loc_rel), "file:///", 8));
- assert(!strcmp(lilv_node_as_uri(host_abs), "file://host/foo/bar"));
- assert(!strncmp(lilv_node_as_uri(host_rel), "file://host/", 12));
-
- lilv_node_free(host_rel);
- lilv_node_free(host_abs);
- lilv_node_free(loc_rel);
- lilv_node_free(loc_abs);
-
- char* tok = lilv_node_get_turtle_token(uval);
- assert(!strcmp(tok, "<http://example.org>"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(sval);
- assert(!strcmp(tok, "Foo"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(ival);
- assert(!strcmp(tok, "42"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(fval);
- assert(!strncmp(tok, "1.6180", 6));
- lilv_free(tok);
-
- LilvNode* uval_e = lilv_new_uri(world, "http://example.org");
- LilvNode* sval_e = lilv_new_string(world, "Foo");
- LilvNode* ival_e = lilv_new_int(world, 42);
- LilvNode* fval_e = lilv_new_float(world, 1.6180);
- LilvNode* uval_ne = lilv_new_uri(world, "http://no-example.org");
- LilvNode* sval_ne = lilv_new_string(world, "Bar");
- LilvNode* ival_ne = lilv_new_int(world, 24);
- LilvNode* fval_ne = lilv_new_float(world, 3.14159);
-
- assert(lilv_node_equals(uval, uval_e));
- assert(lilv_node_equals(sval, sval_e));
- assert(lilv_node_equals(ival, ival_e));
- assert(lilv_node_equals(fval, fval_e));
-
- assert(!lilv_node_equals(uval, uval_ne));
- assert(!lilv_node_equals(sval, sval_ne));
- assert(!lilv_node_equals(ival, ival_ne));
- assert(!lilv_node_equals(fval, fval_ne));
-
- assert(!lilv_node_equals(uval, sval));
- assert(!lilv_node_equals(sval, ival));
- assert(!lilv_node_equals(ival, fval));
-
- LilvNode* uval_dup = lilv_node_duplicate(uval);
- assert(lilv_node_equals(uval, uval_dup));
-
- LilvNode* ifval = lilv_new_float(world, 42.0);
- assert(!lilv_node_equals(ival, ifval));
- lilv_node_free(ifval);
-
- LilvNode* nil = NULL;
- assert(!lilv_node_equals(uval, nil));
- assert(!lilv_node_equals(nil, uval));
- assert(lilv_node_equals(nil, nil));
-
- LilvNode* nil2 = lilv_node_duplicate(nil);
- assert(lilv_node_equals(nil, nil2));
-
- lilv_node_free(uval);
- lilv_node_free(sval);
- lilv_node_free(ival);
- lilv_node_free(fval);
- lilv_node_free(uval_e);
- lilv_node_free(sval_e);
- lilv_node_free(ival_e);
- lilv_node_free(fval_e);
- lilv_node_free(uval_ne);
- lilv_node_free(sval_ne);
- lilv_node_free(ival_ne);
- lilv_node_free(fval_ne);
- lilv_node_free(uval_dup);
- lilv_node_free(nil2);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_util(LilvTestEnv* env)
-{
- assert(!lilv_realpath(NULL));
-
- char a_path[16];
- char b_path[16];
- strncpy(a_path, "copy_a_XXXXXX", sizeof(a_path));
- strncpy(b_path, "copy_b_XXXXXX", sizeof(b_path));
- mkstemp(a_path);
- mkstemp(b_path);
-
- FILE* fa = fopen(a_path, "w");
- FILE* fb = fopen(b_path, "w");
- fprintf(fa, "AA\n");
- fprintf(fb, "AB\n");
- fclose(fa);
- fclose(fb);
-
- assert(lilv_copy_file("does/not/exist", "copy"));
- assert(lilv_copy_file(a_path, "not/a/dir/copy"));
- assert(!lilv_copy_file(a_path, "copy_c"));
- assert(!lilv_file_equals(a_path, b_path));
- assert(lilv_file_equals(a_path, a_path));
- assert(lilv_file_equals(a_path, "copy_c"));
- assert(!lilv_file_equals("does/not/exist", b_path));
- assert(!lilv_file_equals(a_path, "does/not/exist"));
- assert(!lilv_file_equals("does/not/exist", "/does/not/either"));
- return 0;
-}
-
-/*****************************************************************************/
-
-static int discovery_plugin_found = 0;
-
-static void
-discovery_verify_plugin(const LilvTestEnv* env, const LilvPlugin* plugin)
-{
- const LilvNode* value = lilv_plugin_get_uri(plugin);
- if (lilv_node_equals(value, env->plugin1_uri)) {
- const LilvNode* lib_uri = NULL;
- assert(!lilv_node_equals(value, env->plugin2_uri));
- discovery_plugin_found = 1;
- lib_uri = lilv_plugin_get_library_uri(plugin);
- assert(lib_uri);
- assert(lilv_node_is_uri(lib_uri));
- assert(lilv_node_as_uri(lib_uri));
- assert(strstr(lilv_node_as_uri(lib_uri), "foo" SHLIB_EXT));
- assert(lilv_plugin_verify(plugin));
- }
-}
-
-static int
-test_discovery(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ;"
- "doap:name \"Test plugin\" ;"
- "lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; ] .")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- assert(lilv_plugins_size(plugins) > 0);
-
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(explug != NULL);
- const LilvPlugin* explug2 = lilv_plugins_get_by_uri(plugins, env->plugin2_uri);
- assert(explug2 == NULL);
-
- if (explug) {
- LilvNode* name = lilv_plugin_get_name(explug);
- assert(!strcmp(lilv_node_as_string(name), "Test plugin"));
- lilv_node_free(name);
- }
-
- discovery_plugin_found = 0;
- LILV_FOREACH(plugins, i, plugins)
- discovery_verify_plugin(env, lilv_plugins_get(plugins, i));
-
- assert(discovery_plugin_found);
- plugins = NULL;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_verify(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ] .")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(explug);
- assert(lilv_plugin_verify(explug));
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_no_verify(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin . ")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(explug);
- assert(!lilv_plugin_verify(explug));
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_classes(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
- "] .")) {
- return 1;
- }
-
- const LilvPluginClass* plugin = lilv_world_get_plugin_class(world);
- const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world);
- LilvPluginClasses* children = lilv_plugin_class_get_children(plugin);
-
- assert(lilv_plugin_class_get_parent_uri(plugin) == NULL);
- assert(lilv_plugin_classes_size(classes) > lilv_plugin_classes_size(children));
- assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_label(plugin)), "Plugin"));
- assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_uri(plugin)),
- "http://lv2plug.in/ns/lv2core#Plugin"));
-
- LILV_FOREACH(plugin_classes, i, children) {
- assert(lilv_node_equals(
- lilv_plugin_class_get_parent_uri(lilv_plugin_classes_get(children, i)),
- lilv_plugin_class_get_uri(plugin)));
- }
-
- LilvNode* some_uri = lilv_new_uri(world, "http://example.org/whatever");
- assert(lilv_plugin_classes_get_by_uri(classes, some_uri) == NULL);
- lilv_node_free(some_uri);
-
- lilv_plugin_classes_free(children);
-
- lilv_plugin_class_free(NULL);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_plugin(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:optionalFeature lv2:hardRTCapable ; "
- "lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
- "lv2:extensionData <http://example.org/extdata> ;"
- ":foo 1.6180 ; "
- ":bar true ; "
- ":baz false ; "
- ":blank [ a <http://example.org/blank> ] ; "
- "doap:maintainer [ foaf:name \"David Robillard\" ; "
- " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- ":thing doap:name \"Something else\" .\n")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- const LilvPluginClass* klass = lilv_plugin_get_class(plug);
- const LilvNode* klass_uri = lilv_plugin_class_get_uri(klass);
- assert(!strcmp(lilv_node_as_string(klass_uri),
- "http://lv2plug.in/ns/lv2core#CompressorPlugin"));
-
- LilvNode* rdf_type = lilv_new_uri(
- world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
- assert(lilv_world_ask(world,
- lilv_plugin_get_uri(plug),
- rdf_type,
- klass_uri));
- lilv_node_free(rdf_type);
-
- assert(!lilv_plugin_is_replaced(plug));
- assert(!lilv_plugin_get_related(plug, NULL));
-
- const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
- assert(!strcmp(lilv_node_as_string(plug_bundle_uri), env->test_bundle_uri));
-
- const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
- assert(lilv_nodes_size(data_uris) == 2);
-
- LilvNode* project = lilv_plugin_get_project(plug);
- assert(!project);
-
- char* manifest_uri = (char*)malloc(TEST_PATH_MAX);
- char* data_uri = (char*)malloc(TEST_PATH_MAX);
- snprintf(manifest_uri, TEST_PATH_MAX, "%s%s",
- lilv_node_as_string(plug_bundle_uri), "manifest.ttl");
- snprintf(data_uri, TEST_PATH_MAX, "%s%s",
- lilv_node_as_string(plug_bundle_uri), "plugin.ttl");
-
- LilvNode* manifest_uri_val = lilv_new_uri(world, manifest_uri);
- assert(lilv_nodes_contains(data_uris, manifest_uri_val));
- lilv_node_free(manifest_uri_val);
-
- LilvNode* data_uri_val = lilv_new_uri(world, data_uri);
- assert(lilv_nodes_contains(data_uris, data_uri_val));
- lilv_node_free(data_uri_val);
-
- LilvNode* unknown_uri_val = lilv_new_uri(world, "http://example.org/unknown");
- assert(!lilv_nodes_contains(data_uris, unknown_uri_val));
- lilv_node_free(unknown_uri_val);
-
- free(manifest_uri);
- free(data_uri);
-
- float mins[3];
- float maxs[3];
- float defs[3];
- lilv_plugin_get_port_ranges_float(plug, mins, maxs, defs);
- assert(mins[0] == -1.0f);
- assert(maxs[0] == 1.0f);
- assert(defs[0] == 0.5f);
-
- LilvNode* audio_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#AudioPort");
- LilvNode* control_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#ControlPort");
- LilvNode* in_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#InputPort");
- LilvNode* out_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#OutputPort");
-
- assert(lilv_plugin_get_num_ports_of_class(plug, control_class, NULL) == 3);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, NULL) == 0);
- assert(lilv_plugin_get_num_ports_of_class(plug, in_class, NULL) == 2);
- assert(lilv_plugin_get_num_ports_of_class(plug, out_class, NULL) == 1);
- assert(lilv_plugin_get_num_ports_of_class(plug, control_class, in_class, NULL) == 2);
- assert(lilv_plugin_get_num_ports_of_class(plug, control_class, out_class, NULL) == 1);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) == 0);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, out_class, NULL) == 0);
-
- assert(lilv_plugin_has_latency(plug));
- assert(lilv_plugin_get_latency_port_index(plug) == 2);
-
- LilvNode* lv2_latency = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#latency");
- const LilvPort* latency_port = lilv_plugin_get_port_by_designation(
- plug, out_class, lv2_latency);
- lilv_node_free(lv2_latency);
-
- assert(latency_port);
- assert(lilv_port_get_index(plug, latency_port) == 2);
- assert(lilv_node_is_blank(lilv_port_get_node(plug, latency_port)));
-
- LilvNode* rt_feature = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#hardRTCapable");
- LilvNode* event_feature = lilv_new_uri(world,
- "http://lv2plug.in/ns/ext/event");
- LilvNode* pretend_feature = lilv_new_uri(world,
- "http://example.org/solvesWorldHunger");
-
- assert(lilv_plugin_has_feature(plug, rt_feature));
- assert(lilv_plugin_has_feature(plug, event_feature));
- assert(!lilv_plugin_has_feature(plug, pretend_feature));
-
- lilv_node_free(rt_feature);
- lilv_node_free(event_feature);
- lilv_node_free(pretend_feature);
-
- LilvNodes* supported = lilv_plugin_get_supported_features(plug);
- LilvNodes* required = lilv_plugin_get_required_features(plug);
- LilvNodes* optional = lilv_plugin_get_optional_features(plug);
- assert(lilv_nodes_size(supported) == 2);
- assert(lilv_nodes_size(required) == 1);
- assert(lilv_nodes_size(optional) == 1);
- lilv_nodes_free(supported);
- lilv_nodes_free(required);
- lilv_nodes_free(optional);
-
- LilvNode* foo_p = lilv_new_uri(world, "http://example.org/foo");
- LilvNodes* foos = lilv_plugin_get_value(plug, foo_p);
- assert(lilv_nodes_size(foos) == 1);
- assert(fabs(lilv_node_as_float(lilv_nodes_get_first(foos)) - 1.6180) < FLT_EPSILON);
- lilv_node_free(foo_p);
- lilv_nodes_free(foos);
-
- LilvNode* bar_p = lilv_new_uri(world, "http://example.org/bar");
- LilvNodes* bars = lilv_plugin_get_value(plug, bar_p);
- assert(lilv_nodes_size(bars) == 1);
- assert(lilv_node_as_bool(lilv_nodes_get_first(bars)) == true);
- lilv_node_free(bar_p);
- lilv_nodes_free(bars);
-
- LilvNode* baz_p = lilv_new_uri(world, "http://example.org/baz");
- LilvNodes* bazs = lilv_plugin_get_value(plug, baz_p);
- assert(lilv_nodes_size(bazs) == 1);
- assert(lilv_node_as_bool(lilv_nodes_get_first(bazs)) == false);
- lilv_node_free(baz_p);
- lilv_nodes_free(bazs);
-
- LilvNode* blank_p = lilv_new_uri(world, "http://example.org/blank");
- LilvNodes* blanks = lilv_plugin_get_value(plug, blank_p);
- assert(lilv_nodes_size(blanks) == 1);
- LilvNode* blank = lilv_nodes_get_first(blanks);
- assert(lilv_node_is_blank(blank));
- const char* blank_str = lilv_node_as_blank(blank);
- char* blank_tok = lilv_node_get_turtle_token(blank);
- assert(!strncmp(blank_tok, "_:", 2));
- assert(!strcmp(blank_tok + 2, blank_str));
- lilv_free(blank_tok);
- lilv_node_free(blank_p);
- lilv_nodes_free(blanks);
-
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
- lilv_node_free(author_name);
-
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
- lilv_node_free(author_email);
-
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
- lilv_node_free(author_homepage);
-
- LilvNode* thing_uri = lilv_new_uri(world, "http://example.org/thing");
- LilvNode* name_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
- LilvNodes* thing_names = lilv_world_find_nodes(world, thing_uri, name_p, NULL);
- assert(lilv_nodes_size(thing_names) == 1);
- LilvNode* thing_name = lilv_nodes_get_first(thing_names);
- assert(thing_name);
- assert(lilv_node_is_string(thing_name));
- assert(!strcmp(lilv_node_as_string(thing_name), "Something else"));
- LilvNode* thing_name2 = lilv_world_get(world, thing_uri, name_p, NULL);
- assert(lilv_node_equals(thing_name, thing_name2));
-
- LilvUIs* uis = lilv_plugin_get_uis(plug);
- assert(lilv_uis_size(uis) == 0);
- lilv_uis_free(uis);
-
- LilvNode* extdata = lilv_new_uri(world, "http://example.org/extdata");
- LilvNode* noextdata = lilv_new_uri(world, "http://example.org/noextdata");
- LilvNodes* extdatas = lilv_plugin_get_extension_data(plug);
- assert(lilv_plugin_has_extension_data(plug, extdata));
- assert(!lilv_plugin_has_extension_data(plug, noextdata));
- assert(lilv_nodes_size(extdatas) == 1);
- assert(lilv_node_equals(lilv_nodes_get_first(extdatas), extdata));
- lilv_node_free(noextdata);
- lilv_node_free(extdata);
- lilv_nodes_free(extdatas);
-
- lilv_nodes_free(thing_names);
- lilv_node_free(thing_uri);
- lilv_node_free(thing_name2);
- lilv_node_free(name_p);
- lilv_node_free(control_class);
- lilv_node_free(audio_class);
- lilv_node_free(in_class);
- lilv_node_free(out_class);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_project(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin with project\" ;"
- "lv2:project [ "
- " doap:maintainer [ "
- " foaf:name \"David Robillard\" ; "
- " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
- "] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- ":thing doap:name \"Something else\" .\n")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
- lilv_node_free(author_name);
-
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
- lilv_node_free(author_email);
-
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
- lilv_node_free(author_homepage);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_no_author(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin with project\" ;"
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- ":thing doap:name \"Something else\" .\n")) {
- return 1;
- }
-
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!author_name);
-
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!author_email);
-
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!author_homepage);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_project_no_author(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin with project\" ;"
- "lv2:project [ "
- " doap:name \"Fake project\" ;"
- "] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- ":thing doap:name \"Something else\" .\n")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!author_name);
-
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!author_email);
-
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!author_homepage);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_preset(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin with project\" ;"
- "lv2:project [ "
- " doap:name \"Fake project\" ;"
- "] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- "<http://example.org/preset> a pset:Preset ;"
- " lv2:appliesTo :plug ;"
- " rdfs:label \"some preset\" .\n")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
- LilvNodes* related = lilv_plugin_get_related(plug, pset_Preset);
-
- assert(lilv_nodes_size(related) == 1);
-
- lilv_node_free(pset_Preset);
- lilv_nodes_free(related);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_prototype(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":prot a lv2:PluginBase ; rdfs:seeAlso <plugin.ttl> .\n"
- ":plug a lv2:Plugin ; lv2:binary <inst" SHLIB_EXT "> ; lv2:prototype :prot .\n",
- ":prot a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "lv2:project [ "
- " doap:name \"Fake project\" ;"
- "] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency ; "
- " lv2:designation lv2:latency "
- "] . \n"
- ":plug doap:name \"Instance\" .\n")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- // Test non-inherited property
- LilvNode* name = lilv_plugin_get_name(plug);
- assert(!strcmp(lilv_node_as_string(name), "Instance"));
- lilv_node_free(name);
-
- // Test inherited property
- const LilvNode* binary = lilv_plugin_get_library_uri(plug);
- assert(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_port(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n"
- ":plug a lv2:Plugin ; "
- "doap:name \"Test plugin\" ;"
- "doap:homepage <http://example.org/someplug> ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; "
- " lv2:name \"store\" ; "
- " lv2:name \"Laden\"@de-de ; lv2:name \"Geschaeft\"@de-at ; "
- " lv2:name \"tienda\"@es ; "
- " rdfs:comment \"comment\"@en , \"commentaires\"@fr ; "
- " lv2:portProperty lv2:integer ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 ; "
- " lv2:scalePoint [ rdfs:label \"Sin\"; rdf:value 3 ] ; "
- " lv2:scalePoint [ rdfs:label \"Cos\"; rdf:value 4 ] "
- "] , [\n"
- " a lv2:EventPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"event_in\" ; "
- " lv2:name \"Event Input\" ; "
- " lv2ev:supportsEvent <http://example.org/event> ;"
- " atom:supports <http://example.org/atomEvent> "
- "] , [\n"
- " a lv2:AudioPort ; a lv2:InputPort ; "
- " lv2:index 2 ; lv2:symbol \"audio_in\" ; "
- " lv2:name \"Audio Input\" ; "
- "] , [\n"
- " a lv2:AudioPort ; a lv2:OutputPort ; "
- " lv2:index 3 ; lv2:symbol \"audio_out\" ; "
- " lv2:name \"Audio Output\" ; "
- "] .")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* psym = lilv_new_string(world, "foo");
- const LilvPort* p = lilv_plugin_get_port_by_index(plug, 0);
- const LilvPort* p2 = lilv_plugin_get_port_by_symbol(plug, psym);
- lilv_node_free(psym);
- assert(p != NULL);
- assert(p2 != NULL);
- assert(p == p2);
-
- LilvNode* nopsym = lilv_new_string(world, "thisaintnoportfoo");
- const LilvPort* p3 = lilv_plugin_get_port_by_symbol(plug, nopsym);
- assert(p3 == NULL);
- lilv_node_free(nopsym);
-
- // Try getting an invalid property
- LilvNode* num = lilv_new_int(world, 1);
- LilvNodes* nothing = lilv_port_get_value(plug, p, num);
- assert(!nothing);
- lilv_node_free(num);
-
- LilvNode* audio_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#AudioPort");
- LilvNode* control_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#ControlPort");
- LilvNode* in_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#InputPort");
- LilvNode* out_class = lilv_new_uri(world,
- "http://lv2plug.in/ns/lv2core#OutputPort");
-
- assert(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
- assert(lilv_plugin_get_num_ports(plug) == 4);
- assert(lilv_port_is_a(plug, p, control_class));
- assert(lilv_port_is_a(plug, p, in_class));
- assert(!lilv_port_is_a(plug, p, audio_class));
-
- LilvNodes* port_properties = lilv_port_get_properties(plug, p);
- assert(lilv_nodes_size(port_properties) == 1);
- lilv_nodes_free(port_properties);
-
- // Untranslated name (current locale is set to "C" in main)
- assert(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
- LilvNode* name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- // Exact language match
- set_env("LANG", "de_DE");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "Laden"));
- lilv_node_free(name);
-
- // Exact language match (with charset suffix)
- set_env("LANG", "de_AT.utf8");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "Geschaeft"));
- lilv_node_free(name);
-
- // Partial language match (choose value translated for different country)
- set_env("LANG", "de_CH");
- name = lilv_port_get_name(plug, p);
- assert((!strcmp(lilv_node_as_string(name), "Laden"))
- ||(!strcmp(lilv_node_as_string(name), "Geschaeft")));
- lilv_node_free(name);
-
- // Partial language match (choose country-less language tagged value)
- set_env("LANG", "es_MX");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "tienda"));
- lilv_node_free(name);
-
- // No language match (choose untranslated value)
- set_env("LANG", "cn");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- // Invalid language
- set_env("LANG", "1!");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- set_env("LANG", "en_CA.utf-8");
-
- // Language tagged value with no untranslated values
- LilvNode* rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
- LilvNodes* comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
- "comment"));
- LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(comment), "comment"));
- lilv_node_free(comment);
- lilv_nodes_free(comments);
-
- set_env("LANG", "fr");
-
- comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
- "commentaires"));
- lilv_nodes_free(comments);
-
- set_env("LANG", "cn");
-
- comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!comments);
- lilv_nodes_free(comments);
-
- lilv_node_free(rdfs_comment);
-
- set_env("LANG", "C"); // Reset locale
-
- LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
- assert(lilv_scale_points_size(points) == 2);
-
- LilvIter* sp_iter = lilv_scale_points_begin(points);
- const LilvScalePoint* sp0 = lilv_scale_points_get(points, sp_iter);
- assert(sp0);
- sp_iter = lilv_scale_points_next(points, sp_iter);
- const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
- assert(sp1);
-
- assert(
- ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Sin")
- && lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3)
- &&
- (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Cos")
- && lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4))
- ||
- ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Cos")
- && lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4)
- &&
- (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Sin")
- && lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
-
- LilvNode* homepage_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
- LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
- assert(lilv_nodes_size(homepages) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
- "http://example.org/someplug"));
-
- LilvNode *min, *max, *def;
- lilv_port_get_range(plug, p, &def, &min, &max);
- assert(def);
- assert(min);
- assert(max);
- assert(lilv_node_as_float(def) == 0.5);
- assert(lilv_node_as_float(min) == -1.0);
- assert(lilv_node_as_float(max) == 1.0);
-
- LilvNode* integer_prop = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
- LilvNode* toggled_prop = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
-
- assert(lilv_port_has_property(plug, p, integer_prop));
- assert(!lilv_port_has_property(plug, p, toggled_prop));
-
- const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
-
- LilvNode* event_type = lilv_new_uri(world, "http://example.org/event");
- LilvNode* event_type_2 = lilv_new_uri(world, "http://example.org/otherEvent");
- LilvNode* atom_event = lilv_new_uri(world, "http://example.org/atomEvent");
- assert(lilv_port_supports_event(plug, ep, event_type));
- assert(!lilv_port_supports_event(plug, ep, event_type_2));
- assert(lilv_port_supports_event(plug, ep, atom_event));
-
- LilvNode* name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
- LilvNodes* names = lilv_port_get_value(plug, p, name_p);
- assert(lilv_nodes_size(names) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
- "store"));
- lilv_nodes_free(names);
-
- LilvNode* true_val = lilv_new_bool(world, true);
- LilvNode* false_val = lilv_new_bool(world, false);
-
- assert(!lilv_node_equals(true_val, false_val));
-
- lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
- names = lilv_port_get_value(plug, p, name_p);
- assert(lilv_nodes_size(names) == 4);
- lilv_nodes_free(names);
- lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
-
- lilv_node_free(false_val);
- lilv_node_free(true_val);
-
- names = lilv_port_get_value(plug, ep, name_p);
- assert(lilv_nodes_size(names) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
- "Event Input"));
-
- const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
-
- assert(lilv_port_is_a(plug, ap_in, in_class));
- assert(!lilv_port_is_a(plug, ap_in, out_class));
- assert(lilv_port_is_a(plug, ap_in, audio_class));
- assert(!lilv_port_is_a(plug, ap_in, control_class));
-
- const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
-
- assert(lilv_port_is_a(plug, ap_out, out_class));
- assert(!lilv_port_is_a(plug, ap_out, in_class));
- assert(lilv_port_is_a(plug, ap_out, audio_class));
- assert(!lilv_port_is_a(plug, ap_out, control_class));
-
- assert(lilv_plugin_get_num_ports_of_class(plug, control_class, in_class , NULL) == 1);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class , in_class , NULL) == 1);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class , out_class, NULL) == 1);
-
- lilv_nodes_free(names);
- lilv_node_free(name_p);
-
- lilv_node_free(integer_prop);
- lilv_node_free(toggled_prop);
- lilv_node_free(event_type);
- lilv_node_free(event_type_2);
- lilv_node_free(atom_event);
-
- lilv_node_free(min);
- lilv_node_free(max);
- lilv_node_free(def);
-
- lilv_node_free(homepage_p);
- lilv_nodes_free(homepages);
-
- lilv_scale_points_free(points);
- lilv_node_free(control_class);
- lilv_node_free(audio_class);
- lilv_node_free(out_class);
- lilv_node_free(in_class);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static unsigned
-ui_supported(const char* container_type_uri,
- const char* ui_type_uri)
-{
- return !strcmp(container_type_uri, ui_type_uri);
-}
-
-static int
-test_ui(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- "@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n"
- ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:optionalFeature lv2:hardRTCapable ; "
- "lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
- "lv2ui:ui :ui , :ui2 , :ui3 , :ui4 ; "
- "doap:maintainer [ foaf:name \"David Robillard\" ; "
- " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
- " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
- " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
- "] , [ "
- " a lv2:ControlPort ; a lv2:OutputPort ; "
- " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
- " lv2:portProperty lv2:reportsLatency "
- "] .\n"
- ":ui a lv2ui:GtkUI ; "
- " lv2ui:requiredFeature lv2ui:makeResident ; "
- " lv2ui:binary <ui" SHLIB_EXT "> ; "
- " lv2ui:optionalFeature lv2ui:ext_presets . "
- ":ui2 a lv2ui:GtkUI ; lv2ui:binary <ui2" SHLIB_EXT "> . "
- ":ui3 a lv2ui:GtkUI ; lv2ui:binary <ui3" SHLIB_EXT "> . "
- ":ui4 a lv2ui:GtkUI ; lv2ui:binary <ui4" SHLIB_EXT "> . ")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvUIs* uis = lilv_plugin_get_uis(plug);
- assert(lilv_uis_size(uis) == 4);
-
- const LilvUI* ui0 = lilv_uis_get(uis, lilv_uis_begin(uis));
- assert(ui0);
-
- LilvNode* ui_uri = lilv_new_uri(world, "http://example.org/ui");
- LilvNode* ui2_uri = lilv_new_uri(world, "http://example.org/ui3");
- LilvNode* ui3_uri = lilv_new_uri(world, "http://example.org/ui4");
- LilvNode* noui_uri = lilv_new_uri(world, "http://example.org/notaui");
-
- const LilvUI* ui0_2 = lilv_uis_get_by_uri(uis, ui_uri);
- assert(ui0 == ui0_2);
- assert(lilv_node_equals(lilv_ui_get_uri(ui0_2), ui_uri));
-
- const LilvUI* ui2 = lilv_uis_get_by_uri(uis, ui2_uri);
- assert(ui2 != ui0);
-
- const LilvUI* ui3 = lilv_uis_get_by_uri(uis, ui3_uri);
- assert(ui3 != ui0);
-
- const LilvUI* noui = lilv_uis_get_by_uri(uis, noui_uri);
- assert(noui == NULL);
-
- const LilvNodes* classes = lilv_ui_get_classes(ui0);
- assert(lilv_nodes_size(classes) == 1);
-
- LilvNode* ui_class_uri = lilv_new_uri(world,
- "http://lv2plug.in/ns/extensions/ui#GtkUI");
-
- LilvNode* unknown_ui_class_uri = lilv_new_uri(world,
- "http://example.org/mysteryUI");
-
- assert(lilv_node_equals(lilv_nodes_get_first(classes), ui_class_uri));
- assert(lilv_ui_is_a(ui0, ui_class_uri));
-
- const LilvNode* ui_type = NULL;
- assert(lilv_ui_is_supported(ui0, ui_supported, ui_class_uri, &ui_type));
- assert(!lilv_ui_is_supported(ui0, ui_supported, unknown_ui_class_uri, &ui_type));
- assert(lilv_node_equals(ui_type, ui_class_uri));
-
- const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
- const LilvNode* ui_bundle_uri = lilv_ui_get_bundle_uri(ui0);
- assert(lilv_node_equals(plug_bundle_uri, ui_bundle_uri));
-
- char* ui_binary_uri_str = (char*)malloc(TEST_PATH_MAX);
- snprintf(ui_binary_uri_str, TEST_PATH_MAX, "%s%s",
- lilv_node_as_string(plug_bundle_uri), "ui" SHLIB_EXT);
-
- const LilvNode* ui_binary_uri = lilv_ui_get_binary_uri(ui0);
-
- LilvNode* expected_uri = lilv_new_uri(world, ui_binary_uri_str);
- assert(lilv_node_equals(expected_uri, ui_binary_uri));
-
- free(ui_binary_uri_str);
- lilv_node_free(unknown_ui_class_uri);
- lilv_node_free(ui_class_uri);
- lilv_node_free(ui_uri);
- lilv_node_free(ui2_uri);
- lilv_node_free(ui3_uri);
- lilv_node_free(noui_uri);
- lilv_node_free(expected_uri);
- lilv_uis_free(uis);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-#ifndef _WIN32
-
-uint32_t atom_Float = 0;
-float in = 1.0;
-float out = 42.0;
-float control = 1234.0;
-
-static const void*
-get_port_value(const char* port_symbol,
- void* user_data,
- uint32_t* size,
- uint32_t* type)
-{
- if (!strcmp(port_symbol, "input")) {
- *size = sizeof(float);
- *type = atom_Float;
- return &in;
- } else if (!strcmp(port_symbol, "output")) {
- *size = sizeof(float);
- *type = atom_Float;
- return &out;
- } else if (!strcmp(port_symbol, "control")) {
- *size = sizeof(float);
- *type = atom_Float;
- return &control;
- } else {
- fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n",
- port_symbol);
- *size = *type = 0;
- return NULL;
- }
-}
-
-static void
-set_port_value(const char* port_symbol,
- void* user_data,
- const void* value,
- uint32_t size,
- uint32_t type)
-{
- if (!strcmp(port_symbol, "input")) {
- in = *(const float*)value;
- } else if (!strcmp(port_symbol, "output")) {
- out = *(const float*)value;
- } else if (!strcmp(port_symbol, "control")) {
- control = *(const float*)value;
- } else {
- fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n",
- port_symbol);
- }
-}
-
-char** uris = NULL;
-size_t n_uris = 0;
-
-static LV2_URID
-map_uri(LV2_URID_Map_Handle handle,
- const char* uri)
-{
- for (size_t i = 0; i < n_uris; ++i) {
- if (!strcmp(uris[i], uri)) {
- return i + 1;
- }
- }
-
- assert(serd_uri_string_has_scheme((const uint8_t*)uri));
- uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
- uris[n_uris - 1] = lilv_strdup(uri);
- return n_uris;
-}
-
-static const char*
-unmap_uri(LV2_URID_Map_Handle handle,
- LV2_URID urid)
-{
- if (urid > 0 && urid <= n_uris) {
- return uris[urid - 1];
- }
- return NULL;
-}
-
-static char* temp_dir = NULL;
-
-static char*
-lilv_make_path(LV2_State_Make_Path_Handle handle,
- const char* path)
-{
- return lilv_path_join(temp_dir, path);
-}
-
-static void
-lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
-{
- lilv_free(path);
-}
-
-static int
-test_state(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(LILV_TEST_BUNDLE);
- SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true);
- LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf);
- LilvNode* plugin_uri = lilv_new_uri(world,
- "http://example.org/lilv-test-plugin");
- lilv_world_load_bundle(world, bundle_uri);
- free(abs_bundle);
- serd_node_free(&bundle);
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
- assert(plugin);
-
- LV2_URID_Map map = { NULL, map_uri };
- LV2_Feature map_feature = { LV2_URID_MAP_URI, &map };
- LV2_URID_Unmap unmap = { NULL, unmap_uri };
- LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap };
- const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL };
-
- atom_Float = map.map(map.handle, "http://lv2plug.in/ns/ext/atom#Float");
-
- LilvNode* num = lilv_new_int(world, 5);
- LilvState* nostate = lilv_state_new_from_file(world, &map, num, "/junk");
- assert(!nostate);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, features);
- assert(instance);
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &in);
- lilv_instance_connect_port(instance, 1, &out);
- lilv_instance_run(instance, 1);
- assert(in == 1.0);
- assert(out == 1.0);
-
- temp_dir = lilv_realpath("temp");
-
- const char* scratch_dir = NULL;
- char* copy_dir = NULL;
- char* link_dir = NULL;
- char* save_dir = NULL;
-
- // Get instance state state
- LilvState* state = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, save_dir,
- get_port_value, world, 0, NULL);
-
- // Get another instance state
- LilvState* state2 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, save_dir,
- get_port_value, world, 0, NULL);
-
- // Ensure they are equal
- assert(lilv_state_equals(state, state2));
-
- // Check that we can't delete unsaved state
- assert(lilv_state_delete(world, state));
-
- // Check that state has no URI
- assert(!lilv_state_get_uri(state));
-
- // Check that we can't save a state with no URI
- char* bad_state_str = lilv_state_to_string(
- world, &map, &unmap, state, NULL, NULL);
- assert(!bad_state_str);
-
- // Check that we can't restore the NULL string (and it doesn't crash)
- LilvState* bad_state = lilv_state_new_from_string(world, &map, NULL);
- assert(!bad_state);
-
- // Save state to a string
- char* state1_str = lilv_state_to_string(
- world, &map, &unmap, state, "http://example.org/state1", NULL);
-
- // Restore from string
- LilvState* from_str = lilv_state_new_from_string(world, &map, state1_str);
-
- // Ensure they are equal
- assert(lilv_state_equals(state, from_str));
- lilv_free(state1_str);
-
- const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(state);
- assert(lilv_node_equals(state_plugin_uri, plugin_uri));
-
- // Tinker with the label of the first state
- assert(lilv_state_get_label(state) == NULL);
- lilv_state_set_label(state, "Test State Old Label");
- assert(!strcmp(lilv_state_get_label(state), "Test State Old Label"));
- lilv_state_set_label(state, "Test State");
- assert(!strcmp(lilv_state_get_label(state), "Test State"));
-
- assert(!lilv_state_equals(state, state2)); // Label changed
-
- // Run and get a new instance state (which should now differ)
- lilv_instance_run(instance, 1);
- LilvState* state3 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, save_dir,
- get_port_value, world, 0, NULL);
- assert(!lilv_state_equals(state2, state3)); // num_runs changed
-
- // Restore instance state to original state
- lilv_state_restore(state2, instance, set_port_value, NULL, 0, NULL);
-
- // Take a new snapshot and ensure it matches the set state
- LilvState* state4 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, save_dir,
- get_port_value, world, 0, NULL);
- assert(lilv_state_equals(state2, state4));
-
- // Set some metadata properties
- lilv_state_set_metadata(state, map.map(map.handle, LILV_NS_RDFS "comment"),
- "This is a comment",
- strlen("This is a comment") + 1,
- map.map(map.handle, "http://lv2plug.in/ns/ext/atom#Literal"),
- LV2_STATE_IS_POD);
- lilv_state_set_metadata(state, map.map(map.handle, "http://example.org/metablob"),
- "LIVEBEEF",
- strlen("LIVEBEEF") + 1,
- map.map(map.handle, "http://example.org/MetaBlob"),
- 0);
-
- // Save state to a directory
- int ret = lilv_state_save(world, &map, &unmap, state, NULL,
- "state/state.lv2", "state.ttl");
- assert(!ret);
-
- // Load state from directory
- LilvState* state5 = lilv_state_new_from_file(world, &map, NULL,
- "state/state.lv2/state.ttl");
-
- assert(lilv_state_equals(state, state5)); // Round trip accuracy
- assert(lilv_state_get_num_properties(state) == 8);
-
- // Attempt to save state to nowhere (error)
- ret = lilv_state_save(world, &map, &unmap, state, NULL, NULL, NULL);
- assert(ret);
-
- // Save another state to the same directory (update manifest)
- ret = lilv_state_save(world, &map, &unmap, state, NULL,
- "state/state.lv2", "state2.ttl");
- assert(!ret);
-
- // Save state with URI to a directory
- const char* state_uri = "http://example.org/state";
- ret = lilv_state_save(world, &map, &unmap, state, state_uri,
- "state/state6.lv2", "state6.ttl");
- assert(!ret);
-
- // Load state bundle into world and verify it matches
- {
- uint8_t* state6_path = (uint8_t*)lilv_path_absolute("state/state6.lv2/");
- SerdNode state6_uri = serd_node_new_file_uri(state6_path, 0, 0, true);
- LilvNode* state6_bundle = lilv_new_uri(world, (const char*)state6_uri.buf);
- LilvNode* state6_node = lilv_new_uri(world, state_uri);
- lilv_world_load_bundle(world, state6_bundle);
- lilv_world_load_resource(world, state6_node);
- serd_node_free(&state6_uri);
- lilv_free(state6_path);
-
- LilvState* state6 = lilv_state_new_from_world(world, &map, state6_node);
- assert(lilv_state_equals(state, state6)); // Round trip accuracy
-
- // Check that loaded state has correct URI
- assert(lilv_state_get_uri(state6));
- assert(!strcmp(lilv_node_as_string(lilv_state_get_uri(state6)),
- state_uri));
-
- // Unload state from world
- lilv_world_unload_resource(world, state6_node);
- lilv_world_unload_bundle(world, state6_bundle);
-
- // Ensure that it is no longer present
- assert(!lilv_state_new_from_world(world, &map, state6_node));
- lilv_node_free(state6_bundle);
- lilv_node_free(state6_node);
-
- // Delete state
- lilv_state_delete(world, state6);
- lilv_state_free(state6);
- }
-
- // Make directories and test files support
- mkdir("temp", 0700);
- scratch_dir = temp_dir;
- mkdir("files", 0700);
- copy_dir = lilv_realpath("files");
- mkdir("links", 0700);
- link_dir = lilv_realpath("links");
-
- LV2_State_Make_Path make_path = { NULL, lilv_make_path };
- LV2_Feature make_path_feature = { LV2_STATE__makePath, &make_path };
- LV2_State_Free_Path free_path = { NULL, lilv_free_path };
- LV2_Feature free_path_feature = { LV2_STATE__freePath, &free_path };
- const LV2_Feature* ffeatures[] = {
- &make_path_feature, &map_feature, &free_path_feature, NULL
- };
-
- lilv_instance_deactivate(instance);
- lilv_instance_free(instance);
- instance = lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &in);
- lilv_instance_connect_port(instance, 1, &out);
- lilv_instance_run(instance, 1);
-
- // Test instantiating twice
- LilvInstance* instance2 = lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
- if (!instance2) {
- fprintf(stderr,
- "Failed to create multiple instances of <%s>\n",
- lilv_node_as_uri(state_plugin_uri));
- return 1;
- }
- lilv_instance_free(instance2);
-
- // Get instance state state
- LilvState* fstate = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, "state/fstate.lv2",
- get_port_value, world, 0, ffeatures);
-
- {
- // Get another instance state
- LilvState* fstate2 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, "state/fstate2.lv2",
- get_port_value, world, 0, ffeatures);
-
- // Check that it is identical
- assert(lilv_state_equals(fstate, fstate2));
-
- lilv_state_delete(world, fstate2);
- lilv_state_free(fstate2);
- }
-
- // Run, writing more to rec file
- lilv_instance_run(instance, 2);
-
- // Get yet another instance state
- LilvState* fstate3 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, "state/fstate3.lv2",
- get_port_value, world, 0, ffeatures);
-
- // Should be different
- assert(!lilv_state_equals(fstate, fstate3));
-
- // Save state to a directory
- ret = lilv_state_save(world, &map, &unmap, fstate, NULL,
- "state/fstate.lv2", "fstate.ttl");
- assert(!ret);
-
- // Load state from directory
- LilvState* fstate4 = lilv_state_new_from_file(
- world, &map, NULL, "state/fstate.lv2/fstate.ttl");
- assert(lilv_state_equals(fstate, fstate4)); // Round trip accuracy
-
- // Restore instance state to loaded state
- lilv_state_restore(fstate4, instance, set_port_value, NULL, 0, ffeatures);
-
- // Take a new snapshot and ensure it matches
- LilvState* fstate5 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, "state/fstate5.lv2",
- get_port_value, world, 0, ffeatures);
- assert(lilv_state_equals(fstate3, fstate5));
-
- // Save state to a (different) directory again
- ret = lilv_state_save(world, &map, &unmap, fstate, NULL,
- "state/fstate6.lv2", "fstate6.ttl");
- assert(!ret);
-
- // Reload it and ensure it's identical to the other loaded version
- LilvState* fstate6 = lilv_state_new_from_file(
- world, &map, NULL, "state/fstate6.lv2/fstate6.ttl");
- assert(lilv_state_equals(fstate4, fstate6));
-
- // Run, changing rec file (without changing size)
- lilv_instance_run(instance, 3);
-
- // Take a new snapshot
- LilvState* fstate7 = lilv_state_new_from_instance(
- plugin, instance, &map,
- scratch_dir, copy_dir, link_dir, "state/fstate7.lv2",
- get_port_value, world, 0, ffeatures);
- assert(!lilv_state_equals(fstate6, fstate7));
-
- // Save the changed state to a (different) directory again
- ret = lilv_state_save(world, &map, &unmap, fstate7, NULL,
- "state/fstate7.lv2", "fstate7.ttl");
- assert(!ret);
-
- // Reload it and ensure it's changed
- LilvState* fstate72 = lilv_state_new_from_file(
- world, &map, NULL, "state/fstate7.lv2/fstate7.ttl");
- assert(lilv_state_equals(fstate72, fstate7));
- assert(!lilv_state_equals(fstate6, fstate72));
-
- // Delete saved state we still have a state in memory that points to
- lilv_state_delete(world, fstate7);
- lilv_state_delete(world, fstate6);
- lilv_state_delete(world, fstate5);
- lilv_state_delete(world, fstate3);
- lilv_state_delete(world, fstate);
- lilv_state_delete(world, state2);
- lilv_state_delete(world, state);
-
- // Delete remaining states on disk we've lost a reference to
- const char* const old_state_paths[] = {"state/state.lv2/state.ttl",
- "state/state.lv2/state2.ttl",
- "state/fstate.lv2/fstate.ttl",
- NULL};
-
- for (const char*const* p = old_state_paths; *p; ++p) {
- const char* path = *p;
- LilvState* old_state =
- lilv_state_new_from_file(world, &map, NULL, path);
- lilv_state_delete(world, old_state);
- lilv_state_free(old_state);
- }
-
- lilv_instance_deactivate(instance);
- lilv_instance_free(instance);
-
- lilv_node_free(num);
-
- lilv_state_free(state);
- lilv_state_free(from_str);
- lilv_state_free(state2);
- lilv_state_free(state3);
- lilv_state_free(state4);
- lilv_state_free(state5);
- lilv_state_free(fstate);
- lilv_state_free(fstate3);
- lilv_state_free(fstate4);
- lilv_state_free(fstate5);
- lilv_state_free(fstate6);
- lilv_state_free(fstate7);
- lilv_state_free(fstate72);
-
- rmdir("state");
-
- // Free URI map
- for (size_t i = 0; i < n_uris; ++i) {
- free(uris[i]);
- }
- free(uris);
- n_uris = 0;
-
- lilv_node_free(plugin_uri);
- lilv_node_free(bundle_uri);
- free(link_dir);
- free(copy_dir);
- free(temp_dir);
-
- return 0;
-}
-#endif
-
-/*****************************************************************************/
-
-static int
-test_bad_port_symbol(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Test plugin\" ;"
- "doap:homepage <http://example.org/someplug> ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index 0 ; lv2:symbol \"0invalid\" ;"
- " lv2:name \"Invalid\" ; "
- "] .")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
-
- uint32_t n_ports = lilv_plugin_get_num_ports(plug);
- assert(n_ports == 0);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_bad_port_index(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Test plugin\" ;"
- "doap:homepage <http://example.org/someplug> ; "
- "lv2:port [ "
- " a lv2:ControlPort ; a lv2:InputPort ; "
- " lv2:index \"notaninteger\" ; lv2:symbol \"invalid\" ;"
- " lv2:name \"Invalid\" ; "
- "] .")) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
-
- uint32_t n_ports = lilv_plugin_get_num_ports(plug);
- assert(n_ports == 0);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_string(LilvTestEnv* env)
-{
- char* s = NULL;
-
- assert(!strcmp((s = lilv_dirname("/foo/bar")), "/foo")); free(s);
- assert(!strcmp((s = lilv_dirname("/foo/bar/")), "/foo")); free(s);
- assert(!strcmp((s = lilv_dirname("/foo///bar/")), "/foo")); free(s);
- assert(!strcmp((s = lilv_dirname("/foo///bar//")), "/foo")); free(s);
- assert(!strcmp((s = lilv_dirname("foo")), ".")); free(s);
- assert(!strcmp((s = lilv_dirname("/foo")), "/")); free(s);
- assert(!strcmp((s = lilv_dirname("/")), "/")); free(s);
- assert(!strcmp((s = lilv_dirname("//")), "/")); free(s);
- assert(!strcmp((s = lilv_path_relative_to("/a/b", "/a/")), "b")); free(s);
- assert(!strcmp((s = lilv_path_relative_to("/a", "/b/c/")), "/a")); free(s);
- assert(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/")), "../c")); free(s);
- assert(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/e/")), "../../c")); free(s);
- assert(!strcmp((s = lilv_path_join("/a", "b")), "/a/b")); free(s);
- assert(!strcmp((s = lilv_path_join("/a", "/b")), "/a/b")); free(s);
- assert(!strcmp((s = lilv_path_join("/a/", "/b")), "/a/b")); free(s);
- assert(!strcmp((s = lilv_path_join("/a/", "b")), "/a/b")); free(s);
- assert(!strcmp((s = lilv_path_join("/a", NULL)), "/a/")); free(s);
- assert(!strcmp((s = lilv_path_join(NULL, "/b")), "/b")); free(s);
-
-#ifndef _WIN32
- setenv("LILV_TEST_1", "test", 1);
- char* home_foo = lilv_strjoin(getenv("HOME"), "/foo", NULL);
- assert(!strcmp((s = lilv_expand("$LILV_TEST_1")), "test")); free(s);
- assert(!strcmp((s = lilv_expand("~")), getenv("HOME"))); free(s);
- assert(!strcmp((s = lilv_expand("~foo")), "~foo")); free(s);
- assert(!strcmp((s = lilv_expand("~/foo")), home_foo)); free(s);
- assert(!strcmp((s = lilv_expand("$NOT_A_VAR")), "$NOT_A_VAR")); free(s);
- free(home_foo);
- unsetenv("LILV_TEST_1");
-#endif
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_world(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- LilvNode* num = lilv_new_int(env->world, 4);
- LilvNode* uri = lilv_new_uri(env->world, "http://example.org/object");
-
- LilvNodes* matches = lilv_world_find_nodes(world, num, NULL, NULL);
- assert(!matches);
-
- matches = lilv_world_find_nodes(world, NULL, num, NULL);
- assert(!matches);
-
- matches = lilv_world_find_nodes(world, NULL, uri, NULL);
- assert(!matches);
-
- lilv_node_free(uri);
- lilv_node_free(num);
-
- lilv_world_unload_bundle(world, NULL);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_reload_bundle(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- // Create a simple plugin bundle
- create_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"First name\" .");
-
- lilv_world_load_specifications(world);
-
- // Load bundle
- LilvNode* bundle_uri = lilv_new_uri(world, env->test_bundle_uri);
- lilv_world_load_bundle(world, bundle_uri);
-
- // Check that plugin is present
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- // Check that plugin name is correct
- LilvNode* name = lilv_plugin_get_name(plug);
- assert(!strcmp(lilv_node_as_string(name), "First name"));
- lilv_node_free(name);
-
- // Unload bundle from world and delete it
- lilv_world_unload_bundle(world, bundle_uri);
- delete_bundle(env);
-
- // Create a new version of the same bundle, but with a different name
- create_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Second name\" .");
-
- // Check that plugin is no longer in the world's plugin list
- assert(lilv_plugins_size(plugins) == 0);
-
- // Load new bundle
- lilv_world_load_bundle(world, bundle_uri);
-
- // Check that plugin is present again and is the same LilvPlugin
- const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug2);
- assert(plug2 == plug);
-
- // Check that plugin now has new name
- LilvNode* name2 = lilv_plugin_get_name(plug2);
- assert(name2);
- assert(!strcmp(lilv_node_as_string(name2), "Second name"));
- lilv_node_free(name2);
-
- // Load new bundle again (noop)
- lilv_world_load_bundle(world, bundle_uri);
-
- lilv_node_free(bundle_uri);
- delete_bundle(env);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_replace_version(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- LilvNode* plug_uri = lilv_new_uri(world, "http://example.org/versioned");
- LilvNode* lv2_minorVersion = lilv_new_uri(world, LV2_CORE__minorVersion);
- LilvNode* lv2_microVersion = lilv_new_uri(world, LV2_CORE__microVersion);
- LilvNode* minor = NULL;
- LilvNode* micro = NULL;
-
- char* old_bundle_path = lilv_strjoin(LILV_TEST_DIR, "old_version.lv2/", 0);
-
- // Load plugin from old bundle
- LilvNode* old_bundle = lilv_new_file_uri(world, NULL, old_bundle_path);
- lilv_world_load_bundle(world, old_bundle);
- lilv_world_load_resource(world, plug_uri);
-
- // Check version
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* old_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
- assert(old_plug);
- minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
- micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
- assert(!strcmp(lilv_node_as_string(minor), "1"));
- assert(!strcmp(lilv_node_as_string(micro), "0"));
- lilv_node_free(micro);
- lilv_node_free(minor);
-
- char* new_bundle_path = lilv_strjoin(LILV_TEST_DIR, "new_version.lv2/", 0);
-
- // Load plugin from new bundle
- LilvNode* new_bundle = lilv_new_file_uri(world, NULL, new_bundle_path);
- lilv_world_load_bundle(world, new_bundle);
- lilv_world_load_resource(world, plug_uri);
-
- // Check that version in the world model has changed
- plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* new_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
- assert(new_plug);
- assert(lilv_node_equals(lilv_plugin_get_bundle_uri(new_plug), new_bundle));
- minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
- micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
- assert(!strcmp(lilv_node_as_string(minor), "2"));
- assert(!strcmp(lilv_node_as_string(micro), "1"));
- lilv_node_free(micro);
- lilv_node_free(minor);
-
- // Try to load the old version again
- lilv_world_load_bundle(world, old_bundle);
- lilv_world_load_resource(world, plug_uri);
-
- // Check that version in the world model has not changed
- plugins = lilv_world_get_all_plugins(world);
- new_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
- assert(new_plug);
- minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
- micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
- assert(!strcmp(lilv_node_as_string(minor), "2"));
- assert(!strcmp(lilv_node_as_string(micro), "1"));
- lilv_node_free(micro);
- lilv_node_free(minor);
-
- lilv_node_free(new_bundle);
- lilv_node_free(old_bundle);
- free(new_bundle_path);
- free(old_bundle_path);
- lilv_node_free(plug_uri);
- lilv_node_free(lv2_minorVersion);
- lilv_node_free(lv2_microVersion);
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-test_get_symbol(LilvTestEnv* env)
-{
- LilvWorld* const world = env->world;
-
- if (start_bundle(env,
- ":plug a lv2:Plugin ; lv2:symbol \"plugsym\" ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Test plugin\" ;"
- "lv2:symbol \"plugsym\" .")) {
- return 1;
- }
-
- LilvNode* plug_sym = lilv_world_get_symbol(world, env->plugin1_uri);
- LilvNode* path = lilv_new_uri(world, "http://example.org/foo");
- LilvNode* path_sym = lilv_world_get_symbol(world, path);
- LilvNode* query = lilv_new_uri(world, "http://example.org/foo?bar=baz");
- LilvNode* query_sym = lilv_world_get_symbol(world, query);
- LilvNode* frag = lilv_new_uri(world, "http://example.org/foo#bar");
- LilvNode* frag_sym = lilv_world_get_symbol(world, frag);
- LilvNode* queryfrag = lilv_new_uri(world, "http://example.org/foo?bar=baz#quux");
- LilvNode* queryfrag_sym = lilv_world_get_symbol(world, queryfrag);
- LilvNode* nonuri = lilv_new_int(world, 42);
-
- assert(lilv_world_get_symbol(world, nonuri) == NULL);
- assert(!strcmp(lilv_node_as_string(plug_sym), "plugsym"));
- assert(!strcmp(lilv_node_as_string(path_sym), "foo"));
- assert(!strcmp(lilv_node_as_string(query_sym), "bar_baz"));
- assert(!strcmp(lilv_node_as_string(frag_sym), "bar"));
- assert(!strcmp(lilv_node_as_string(queryfrag_sym), "quux"));
-
- lilv_node_free(nonuri);
- lilv_node_free(queryfrag_sym);
- lilv_node_free(queryfrag);
- lilv_node_free(frag_sym);
- lilv_node_free(frag);
- lilv_node_free(query_sym);
- lilv_node_free(query);
- lilv_node_free(path_sym);
- lilv_node_free(path);
- lilv_node_free(plug_sym);
-
- delete_bundle(env);
- return 0;
-}
-
-/*****************************************************************************/
-
-/* add tests here */
-static struct TestCase tests[] = {
- TEST_CASE(util),
- TEST_CASE(value),
- TEST_CASE(verify),
- TEST_CASE(no_verify),
- TEST_CASE(discovery),
- TEST_CASE(classes),
- TEST_CASE(plugin),
- TEST_CASE(project),
- TEST_CASE(no_author),
- TEST_CASE(project_no_author),
- TEST_CASE(preset),
- TEST_CASE(prototype),
- TEST_CASE(port),
- TEST_CASE(ui),
- TEST_CASE(bad_port_symbol),
- TEST_CASE(bad_port_index),
- TEST_CASE(bad_port_index),
- TEST_CASE(string),
- TEST_CASE(world),
- // FIXME: State is not currently working on Windows
-#ifndef _WIN32
- TEST_CASE(state),
-#endif
- TEST_CASE(reload_bundle),
- TEST_CASE(replace_version),
- TEST_CASE(get_symbol),
- { NULL, NULL }
-};
-
-static unsigned
-run_tests(void)
-{
- unsigned n_failures = 0;
-
- for (int i = 0; tests[i].title; ++i) {
- printf("*** Test %s\n", tests[i].title);
- LilvTestEnv* env = lilv_test_env_new();
- if (tests[i].func(env)) {
- fprintf(stderr, "\nTest %s failed\n", tests[i].title);
- ++n_failures;
- }
- lilv_test_env_free(env);
- }
-
- return n_failures;
-}
-
-int
-main(int argc, char* argv[])
-{
- if (argc != 1) {
- printf("Usage: %s\n", argv[0]);
- return 1;
- }
-
- set_env("LANG", "C");
-
- const unsigned n_failures = run_tests();
-
- if (n_failures == 0) {
- fprintf(stderr, "\n*** All tests passed\n");
- } else {
- fprintf(stderr, "\n*** %u tests failed\n", n_failures);
- }
-
- return n_failures;
-}
diff --git a/test/lilv_test_utils.h b/test/lilv_test_utils.h
index 88e1fcd..f027c80 100644
--- a/test/lilv_test_utils.h
+++ b/test/lilv_test_utils.h
@@ -33,6 +33,20 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
+#define SIMPLE_MANIFEST_TTL \
+ "\
+:plug a lv2:Plugin ;\n\
+ lv2:binary <foo" SHLIB_EXT "> ;\n\
+ rdfs:seeAlso <plugin.ttl> .\n"
+
+#if defined(__APPLE__)
+# define SHLIB_EXT ".dylib"
+#elif defined(_WIN32)
+# define SHLIB_EXT ".dll"
+#else
+# define SHLIB_EXT ".so"
+#endif
+
typedef struct
{
LilvWorld* world;
diff --git a/test/test_bad_port_index.c b/test/test_bad_port_index.c
new file mode 100644
index 0000000..a4d9ad2
--- /dev/null
+++ b/test/test_bad_port_index.c
@@ -0,0 +1,58 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <stdint.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ doap:homepage <http://example.org/someplug> ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index \"notaninteger\" ;\n\
+ lv2:symbol \"invalid\" ;\n\
+ lv2:name \"Invalid\" ;\n\
+ ] .";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+
+ uint32_t n_ports = lilv_plugin_get_num_ports(plug);
+ assert(n_ports == 0);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_bad_port_symbol.c b/test/test_bad_port_symbol.c
new file mode 100644
index 0000000..be00986
--- /dev/null
+++ b/test/test_bad_port_symbol.c
@@ -0,0 +1,58 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <stdint.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ doap:homepage <http://example.org/someplug> ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"0invalid\" ;\n\
+ lv2:name \"Invalid\" ;\n\
+ ] .";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+
+ uint32_t n_ports = lilv_plugin_get_num_ports(plug);
+ assert(n_ports == 0);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_classes.c b/test/test_classes.c
new file mode 100644
index 0000000..2c74c07
--- /dev/null
+++ b/test/test_classes.c
@@ -0,0 +1,75 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"Foo\" ;\n\
+] .";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPluginClass* plugin = lilv_world_get_plugin_class(world);
+ const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world);
+ LilvPluginClasses* children = lilv_plugin_class_get_children(plugin);
+
+ assert(lilv_plugin_class_get_parent_uri(plugin) == NULL);
+ assert(lilv_plugin_classes_size(classes) >
+ lilv_plugin_classes_size(children));
+ assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_label(plugin)),
+ "Plugin"));
+ assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_uri(plugin)),
+ "http://lv2plug.in/ns/lv2core#Plugin"));
+
+ LILV_FOREACH (plugin_classes, i, children) {
+ assert(lilv_node_equals(lilv_plugin_class_get_parent_uri(
+ lilv_plugin_classes_get(children, i)),
+ lilv_plugin_class_get_uri(plugin)));
+ }
+
+ LilvNode* some_uri = lilv_new_uri(world, "http://example.org/whatever");
+ assert(lilv_plugin_classes_get_by_uri(classes, some_uri) == NULL);
+ lilv_node_free(some_uri);
+
+ lilv_plugin_classes_free(children);
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_discovery.c b/test/test_discovery.c
new file mode 100644
index 0000000..2585959
--- /dev/null
+++ b/test/test_discovery.c
@@ -0,0 +1,96 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ ] .\n";
+
+static int discovery_plugin_found = 0;
+
+static void
+discovery_verify_plugin(const LilvTestEnv* env, const LilvPlugin* plugin)
+{
+ const LilvNode* value = lilv_plugin_get_uri(plugin);
+ if (lilv_node_equals(value, env->plugin1_uri)) {
+ const LilvNode* lib_uri = NULL;
+ assert(!lilv_node_equals(value, env->plugin2_uri));
+ discovery_plugin_found = 1;
+ lib_uri = lilv_plugin_get_library_uri(plugin);
+ assert(lib_uri);
+ assert(lilv_node_is_uri(lib_uri));
+ assert(lilv_node_as_uri(lib_uri));
+ assert(strstr(lilv_node_as_uri(lib_uri), "foo" SHLIB_EXT));
+ assert(lilv_plugin_verify(plugin));
+ }
+}
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ assert(lilv_plugins_size(plugins) > 0);
+
+ const LilvPlugin* plug1 =
+ lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+
+ const LilvPlugin* plug2 =
+ lilv_plugins_get_by_uri(plugins, env->plugin2_uri);
+
+ assert(plug1);
+ assert(!plug2);
+
+ {
+ LilvNode* name = lilv_plugin_get_name(plug1);
+ assert(!strcmp(lilv_node_as_string(name), "Test plugin"));
+ lilv_node_free(name);
+ }
+
+ discovery_plugin_found = 0;
+ LILV_FOREACH (plugins, i, plugins) {
+ discovery_verify_plugin(env, lilv_plugins_get(plugins, i));
+ }
+
+ assert(discovery_plugin_found);
+ plugins = NULL;
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_get_symbol.c b/test/test_get_symbol.c
new file mode 100644
index 0000000..0427447
--- /dev/null
+++ b/test/test_get_symbol.c
@@ -0,0 +1,81 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const char* const manifest_ttl = "\
+ :plug a lv2:Plugin ;\n\
+ lv2:symbol \"plugsym\" ;\n\
+ lv2:binary <foo" SHLIB_EXT "> ;\n\
+ rdfs:seeAlso <plugin.ttl> .\n";
+
+static const char* const plugin_ttl = "\
+ :plug a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:symbol \"plugsym\" .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, manifest_ttl, plugin_ttl)) {
+ return 1;
+ }
+
+ LilvNode* plug_sym = lilv_world_get_symbol(world, env->plugin1_uri);
+ LilvNode* path = lilv_new_uri(world, "http://example.org/foo");
+ LilvNode* path_sym = lilv_world_get_symbol(world, path);
+ LilvNode* query = lilv_new_uri(world, "http://example.org/foo?bar=baz");
+ LilvNode* query_sym = lilv_world_get_symbol(world, query);
+ LilvNode* frag = lilv_new_uri(world, "http://example.org/foo#bar");
+ LilvNode* frag_sym = lilv_world_get_symbol(world, frag);
+ LilvNode* queryfrag =
+ lilv_new_uri(world, "http://example.org/foo?bar=baz#quux");
+ LilvNode* queryfrag_sym = lilv_world_get_symbol(world, queryfrag);
+ LilvNode* nonuri = lilv_new_int(world, 42);
+
+ assert(lilv_world_get_symbol(world, nonuri) == NULL);
+ assert(!strcmp(lilv_node_as_string(plug_sym), "plugsym"));
+ assert(!strcmp(lilv_node_as_string(path_sym), "foo"));
+ assert(!strcmp(lilv_node_as_string(query_sym), "bar_baz"));
+ assert(!strcmp(lilv_node_as_string(frag_sym), "bar"));
+ assert(!strcmp(lilv_node_as_string(queryfrag_sym), "quux"));
+
+ lilv_node_free(nonuri);
+ lilv_node_free(queryfrag_sym);
+ lilv_node_free(queryfrag);
+ lilv_node_free(frag_sym);
+ lilv_node_free(frag);
+ lilv_node_free(query_sym);
+ lilv_node_free(query);
+ lilv_node_free(path_sym);
+ lilv_node_free(path);
+ lilv_node_free(plug_sym);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_no_author.c b/test/test_no_author.c
new file mode 100644
index 0000000..9cceedc
--- /dev/null
+++ b/test/test_no_author.c
@@ -0,0 +1,87 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+
+static const char* const plugin_ttl = "\
+ :plug\n\
+ a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin with project\" ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5 \n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+ ] . \n\
+\n\
+ :thing doap:name \"Something else\" .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!author_name);
+
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!author_email);
+
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!author_homepage);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_no_verify.c b/test/test_no_verify.c
new file mode 100644
index 0000000..70812a5
--- /dev/null
+++ b/test/test_no_verify.c
@@ -0,0 +1,48 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+
+static const char* const plugin_ttl = ":plug a lv2:Plugin .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* explug =
+ lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+
+ assert(explug);
+ assert(!lilv_plugin_verify(explug));
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_plugin.c b/test/test_plugin.c
new file mode 100644
index 0000000..6eab638
--- /dev/null
+++ b/test/test_plugin.c
@@ -0,0 +1,296 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "../src/lilv_internal.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+:plug\n\
+ a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:optionalFeature lv2:hardRTCapable ;\n\
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ;\n\
+ lv2:extensionData <http://example.org/extdata> ;\n\
+ :foo 1.6180 ;\n\
+ :bar true ;\n\
+ :baz false ;\n\
+ :blank [ a <http://example.org/blank> ] ;\n\
+ doap:maintainer [\n\
+ foaf:name \"David Robillard\" ;\n\
+ foaf:homepage <http://drobilla.net> ;\n\
+ foaf:mbox <mailto:d@drobilla.net>\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+] .\n\
+\n\
+:thing doap:name \"Something else\" .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ const LilvPluginClass* klass = lilv_plugin_get_class(plug);
+ const LilvNode* klass_uri = lilv_plugin_class_get_uri(klass);
+ assert(!strcmp(lilv_node_as_string(klass_uri),
+ "http://lv2plug.in/ns/lv2core#CompressorPlugin"));
+
+ LilvNode* rdf_type =
+ lilv_new_uri(world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+ assert(
+ lilv_world_ask(world, lilv_plugin_get_uri(plug), rdf_type, klass_uri));
+ lilv_node_free(rdf_type);
+
+ assert(!lilv_plugin_is_replaced(plug));
+ assert(!lilv_plugin_get_related(plug, NULL));
+
+ const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
+ assert(!strcmp(lilv_node_as_string(plug_bundle_uri), env->test_bundle_uri));
+
+ const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
+ assert(lilv_nodes_size(data_uris) == 2);
+
+ LilvNode* project = lilv_plugin_get_project(plug);
+ assert(!project);
+
+ char* manifest_uri = lilv_strjoin(lilv_node_as_string(plug_bundle_uri),
+ "manifest.ttl",
+ NULL);
+
+ char* data_uri =
+ lilv_strjoin(lilv_node_as_string(plug_bundle_uri), "plugin.ttl", NULL);
+
+ LilvNode* manifest_uri_val = lilv_new_uri(world, manifest_uri);
+ assert(lilv_nodes_contains(data_uris, manifest_uri_val));
+ lilv_node_free(manifest_uri_val);
+
+ LilvNode* data_uri_val = lilv_new_uri(world, data_uri);
+ assert(lilv_nodes_contains(data_uris, data_uri_val));
+ lilv_node_free(data_uri_val);
+
+ LilvNode* unknown_uri_val =
+ lilv_new_uri(world, "http://example.org/unknown");
+ assert(!lilv_nodes_contains(data_uris, unknown_uri_val));
+ lilv_node_free(unknown_uri_val);
+
+ free(manifest_uri);
+ free(data_uri);
+
+ float mins[3];
+ float maxs[3];
+ float defs[3];
+ lilv_plugin_get_port_ranges_float(plug, mins, maxs, defs);
+ assert(mins[0] == -1.0f);
+ assert(maxs[0] == 1.0f);
+ assert(defs[0] == 0.5f);
+
+ LilvNode* audio_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
+ LilvNode* control_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
+ LilvNode* in_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
+ LilvNode* out_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
+
+ assert(lilv_plugin_get_num_ports_of_class(plug, control_class, NULL) == 3);
+ assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, NULL) == 0);
+ assert(lilv_plugin_get_num_ports_of_class(plug, in_class, NULL) == 2);
+ assert(lilv_plugin_get_num_ports_of_class(plug, out_class, NULL) == 1);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, in_class, NULL) == 2);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, out_class, NULL) == 1);
+ assert(
+ lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) ==
+ 0);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, audio_class, out_class, NULL) == 0);
+
+ assert(lilv_plugin_has_latency(plug));
+ assert(lilv_plugin_get_latency_port_index(plug) == 2);
+
+ LilvNode* lv2_latency =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#latency");
+ const LilvPort* latency_port =
+ lilv_plugin_get_port_by_designation(plug, out_class, lv2_latency);
+ lilv_node_free(lv2_latency);
+
+ assert(latency_port);
+ assert(lilv_port_get_index(plug, latency_port) == 2);
+ assert(lilv_node_is_blank(lilv_port_get_node(plug, latency_port)));
+
+ LilvNode* rt_feature =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#hardRTCapable");
+ LilvNode* event_feature =
+ lilv_new_uri(world, "http://lv2plug.in/ns/ext/event");
+ LilvNode* pretend_feature =
+ lilv_new_uri(world, "http://example.org/solvesWorldHunger");
+
+ assert(lilv_plugin_has_feature(plug, rt_feature));
+ assert(lilv_plugin_has_feature(plug, event_feature));
+ assert(!lilv_plugin_has_feature(plug, pretend_feature));
+
+ lilv_node_free(rt_feature);
+ lilv_node_free(event_feature);
+ lilv_node_free(pretend_feature);
+
+ LilvNodes* supported = lilv_plugin_get_supported_features(plug);
+ LilvNodes* required = lilv_plugin_get_required_features(plug);
+ LilvNodes* optional = lilv_plugin_get_optional_features(plug);
+ assert(lilv_nodes_size(supported) == 2);
+ assert(lilv_nodes_size(required) == 1);
+ assert(lilv_nodes_size(optional) == 1);
+ lilv_nodes_free(supported);
+ lilv_nodes_free(required);
+ lilv_nodes_free(optional);
+
+ LilvNode* foo_p = lilv_new_uri(world, "http://example.org/foo");
+ LilvNodes* foos = lilv_plugin_get_value(plug, foo_p);
+ assert(lilv_nodes_size(foos) == 1);
+ assert(fabs(lilv_node_as_float(lilv_nodes_get_first(foos)) - 1.6180) <
+ FLT_EPSILON);
+ lilv_node_free(foo_p);
+ lilv_nodes_free(foos);
+
+ LilvNode* bar_p = lilv_new_uri(world, "http://example.org/bar");
+ LilvNodes* bars = lilv_plugin_get_value(plug, bar_p);
+ assert(lilv_nodes_size(bars) == 1);
+ assert(lilv_node_as_bool(lilv_nodes_get_first(bars)) == true);
+ lilv_node_free(bar_p);
+ lilv_nodes_free(bars);
+
+ LilvNode* baz_p = lilv_new_uri(world, "http://example.org/baz");
+ LilvNodes* bazs = lilv_plugin_get_value(plug, baz_p);
+ assert(lilv_nodes_size(bazs) == 1);
+ assert(lilv_node_as_bool(lilv_nodes_get_first(bazs)) == false);
+ lilv_node_free(baz_p);
+ lilv_nodes_free(bazs);
+
+ LilvNode* blank_p = lilv_new_uri(world, "http://example.org/blank");
+ LilvNodes* blanks = lilv_plugin_get_value(plug, blank_p);
+ assert(lilv_nodes_size(blanks) == 1);
+ LilvNode* blank = lilv_nodes_get_first(blanks);
+ assert(lilv_node_is_blank(blank));
+ const char* blank_str = lilv_node_as_blank(blank);
+ char* blank_tok = lilv_node_get_turtle_token(blank);
+ assert(!strncmp(blank_tok, "_:", 2));
+ assert(!strcmp(blank_tok + 2, blank_str));
+ lilv_free(blank_tok);
+ lilv_node_free(blank_p);
+ lilv_nodes_free(blanks);
+
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
+ lilv_node_free(author_name);
+
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
+ lilv_node_free(author_email);
+
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(
+ !strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
+ lilv_node_free(author_homepage);
+
+ LilvNode* thing_uri = lilv_new_uri(world, "http://example.org/thing");
+ LilvNode* name_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
+ LilvNodes* thing_names =
+ lilv_world_find_nodes(world, thing_uri, name_p, NULL);
+ assert(lilv_nodes_size(thing_names) == 1);
+ LilvNode* thing_name = lilv_nodes_get_first(thing_names);
+ assert(thing_name);
+ assert(lilv_node_is_string(thing_name));
+ assert(!strcmp(lilv_node_as_string(thing_name), "Something else"));
+ LilvNode* thing_name2 = lilv_world_get(world, thing_uri, name_p, NULL);
+ assert(lilv_node_equals(thing_name, thing_name2));
+
+ LilvUIs* uis = lilv_plugin_get_uis(plug);
+ assert(lilv_uis_size(uis) == 0);
+ lilv_uis_free(uis);
+
+ LilvNode* extdata = lilv_new_uri(world, "http://example.org/extdata");
+ LilvNode* noextdata = lilv_new_uri(world, "http://example.org/noextdata");
+ LilvNodes* extdatas = lilv_plugin_get_extension_data(plug);
+ assert(lilv_plugin_has_extension_data(plug, extdata));
+ assert(!lilv_plugin_has_extension_data(plug, noextdata));
+ assert(lilv_nodes_size(extdatas) == 1);
+ assert(lilv_node_equals(lilv_nodes_get_first(extdatas), extdata));
+ lilv_node_free(noextdata);
+ lilv_node_free(extdata);
+ lilv_nodes_free(extdatas);
+
+ lilv_nodes_free(thing_names);
+ lilv_node_free(thing_uri);
+ lilv_node_free(thing_name2);
+ lilv_node_free(name_p);
+ lilv_node_free(control_class);
+ lilv_node_free(audio_class);
+ lilv_node_free(in_class);
+ lilv_node_free(out_class);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_port.c b/test/test_port.c
new file mode 100644
index 0000000..63f8bd0
--- /dev/null
+++ b/test/test_port.c
@@ -0,0 +1,331 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n\
+:plug\n\
+ a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ doap:homepage <http://example.org/someplug> ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"store\" ;\n\
+ lv2:name \"Laden\"@de-de ;\n\
+ lv2:name \"Geschaeft\"@de-at ;\n\
+ lv2:name \"tienda\"@es ;\n\
+ rdfs:comment \"comment\"@en , \"commentaires\"@fr ;\n\
+ lv2:portProperty lv2:integer ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5 ;\n\
+ lv2:scalePoint [\n\
+ rdfs:label \"Sin\";\n\
+ rdf:value 3\n\
+ ] ;\n\
+ lv2:scalePoint [\n\
+ rdfs:label \"Cos\";\n\
+ rdf:value 4\n\
+ ]\n\
+ ] , [\n\
+ a lv2:EventPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"event_in\" ;\n\
+ lv2:name \"Event Input\" ;\n\
+ lv2ev:supportsEvent <http://example.org/event> ;\n\
+ atom:supports <http://example.org/atomEvent>\n\
+ ] , [\n\
+ a lv2:AudioPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"audio_in\" ;\n\
+ lv2:name \"Audio Input\" ;\n\
+ ] , [\n\
+ a lv2:AudioPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 3 ;\n\
+ lv2:symbol \"audio_out\" ;\n\
+ lv2:name \"Audio Output\" ;\n\
+ ] .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* psym = lilv_new_string(world, "foo");
+ const LilvPort* p = lilv_plugin_get_port_by_index(plug, 0);
+ const LilvPort* p2 = lilv_plugin_get_port_by_symbol(plug, psym);
+ lilv_node_free(psym);
+ assert(p != NULL);
+ assert(p2 != NULL);
+ assert(p == p2);
+
+ LilvNode* nopsym = lilv_new_string(world, "thisaintnoportfoo");
+ const LilvPort* p3 = lilv_plugin_get_port_by_symbol(plug, nopsym);
+ assert(p3 == NULL);
+ lilv_node_free(nopsym);
+
+ // Try getting an invalid property
+ LilvNode* num = lilv_new_int(world, 1);
+ LilvNodes* nothing = lilv_port_get_value(plug, p, num);
+ assert(!nothing);
+ lilv_node_free(num);
+
+ LilvNode* audio_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
+ LilvNode* control_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
+ LilvNode* in_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
+ LilvNode* out_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
+
+ assert(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
+ assert(lilv_plugin_get_num_ports(plug) == 4);
+ assert(lilv_port_is_a(plug, p, control_class));
+ assert(lilv_port_is_a(plug, p, in_class));
+ assert(!lilv_port_is_a(plug, p, audio_class));
+
+ LilvNodes* port_properties = lilv_port_get_properties(plug, p);
+ assert(lilv_nodes_size(port_properties) == 1);
+ lilv_nodes_free(port_properties);
+
+ // Untranslated name (current locale is set to "C" in main)
+ assert(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
+ LilvNode* name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ // Exact language match
+ set_env("LANG", "de_DE");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "Laden"));
+ lilv_node_free(name);
+
+ // Exact language match (with charset suffix)
+ set_env("LANG", "de_AT.utf8");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "Geschaeft"));
+ lilv_node_free(name);
+
+ // Partial language match (choose value translated for different country)
+ set_env("LANG", "de_CH");
+ name = lilv_port_get_name(plug, p);
+ assert((!strcmp(lilv_node_as_string(name), "Laden")) ||
+ (!strcmp(lilv_node_as_string(name), "Geschaeft")));
+ lilv_node_free(name);
+
+ // Partial language match (choose country-less language tagged value)
+ set_env("LANG", "es_MX");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "tienda"));
+ lilv_node_free(name);
+
+ // No language match (choose untranslated value)
+ set_env("LANG", "cn");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ // Invalid language
+ set_env("LANG", "1!");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ set_env("LANG", "en_CA.utf-8");
+
+ // Language tagged value with no untranslated values
+ LilvNode* rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
+ LilvNodes* comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
+ "comment"));
+ LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
+ assert(!strcmp(lilv_node_as_string(comment), "comment"));
+ lilv_node_free(comment);
+ lilv_nodes_free(comments);
+
+ set_env("LANG", "fr");
+
+ comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
+ "commentaires"));
+ lilv_nodes_free(comments);
+
+ set_env("LANG", "cn");
+
+ comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(!comments);
+ lilv_nodes_free(comments);
+
+ lilv_node_free(rdfs_comment);
+
+ set_env("LANG", "C"); // Reset locale
+
+ LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
+ assert(lilv_scale_points_size(points) == 2);
+
+ LilvIter* sp_iter = lilv_scale_points_begin(points);
+ const LilvScalePoint* sp0 = lilv_scale_points_get(points, sp_iter);
+ assert(sp0);
+ sp_iter = lilv_scale_points_next(points, sp_iter);
+ const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
+ assert(sp1);
+
+ assert(((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)),
+ "Sin") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3) &&
+ (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)),
+ "Cos") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4)) ||
+ ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)),
+ "Cos") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4) &&
+ (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)),
+ "Sin") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
+
+ LilvNode* homepage_p =
+ lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
+ LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
+ assert(lilv_nodes_size(homepages) == 1);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
+ "http://example.org/someplug"));
+
+ LilvNode *min, *max, *def;
+ lilv_port_get_range(plug, p, &def, &min, &max);
+ assert(def);
+ assert(min);
+ assert(max);
+ assert(lilv_node_as_float(def) == 0.5);
+ assert(lilv_node_as_float(min) == -1.0);
+ assert(lilv_node_as_float(max) == 1.0);
+
+ LilvNode* integer_prop =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
+ LilvNode* toggled_prop =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
+
+ assert(lilv_port_has_property(plug, p, integer_prop));
+ assert(!lilv_port_has_property(plug, p, toggled_prop));
+
+ const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
+
+ LilvNode* event_type = lilv_new_uri(world, "http://example.org/event");
+ LilvNode* event_type_2 =
+ lilv_new_uri(world, "http://example.org/otherEvent");
+ LilvNode* atom_event = lilv_new_uri(world, "http://example.org/atomEvent");
+ assert(lilv_port_supports_event(plug, ep, event_type));
+ assert(!lilv_port_supports_event(plug, ep, event_type_2));
+ assert(lilv_port_supports_event(plug, ep, atom_event));
+
+ LilvNode* name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
+ LilvNodes* names = lilv_port_get_value(plug, p, name_p);
+ assert(lilv_nodes_size(names) == 1);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "store"));
+ lilv_nodes_free(names);
+
+ LilvNode* true_val = lilv_new_bool(world, true);
+ LilvNode* false_val = lilv_new_bool(world, false);
+
+ assert(!lilv_node_equals(true_val, false_val));
+
+ lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
+ names = lilv_port_get_value(plug, p, name_p);
+ assert(lilv_nodes_size(names) == 4);
+ lilv_nodes_free(names);
+ lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
+
+ lilv_node_free(false_val);
+ lilv_node_free(true_val);
+
+ names = lilv_port_get_value(plug, ep, name_p);
+ assert(lilv_nodes_size(names) == 1);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
+ "Event Input"));
+
+ const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
+
+ assert(lilv_port_is_a(plug, ap_in, in_class));
+ assert(!lilv_port_is_a(plug, ap_in, out_class));
+ assert(lilv_port_is_a(plug, ap_in, audio_class));
+ assert(!lilv_port_is_a(plug, ap_in, control_class));
+
+ const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
+
+ assert(lilv_port_is_a(plug, ap_out, out_class));
+ assert(!lilv_port_is_a(plug, ap_out, in_class));
+ assert(lilv_port_is_a(plug, ap_out, audio_class));
+ assert(!lilv_port_is_a(plug, ap_out, control_class));
+
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, in_class, NULL) == 1);
+ assert(
+ lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) ==
+ 1);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, audio_class, out_class, NULL) == 1);
+
+ lilv_nodes_free(names);
+ lilv_node_free(name_p);
+
+ lilv_node_free(integer_prop);
+ lilv_node_free(toggled_prop);
+ lilv_node_free(event_type);
+ lilv_node_free(event_type_2);
+ lilv_node_free(atom_event);
+
+ lilv_node_free(min);
+ lilv_node_free(max);
+ lilv_node_free(def);
+
+ lilv_node_free(homepage_p);
+ lilv_nodes_free(homepages);
+
+ lilv_scale_points_free(points);
+ lilv_node_free(control_class);
+ lilv_node_free(audio_class);
+ lilv_node_free(out_class);
+ lilv_node_free(in_class);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_preset.c b/test/test_preset.c
new file mode 100644
index 0000000..d26d844
--- /dev/null
+++ b/test/test_preset.c
@@ -0,0 +1,93 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+#include "lv2/presets/presets.h"
+
+#include <assert.h>
+
+static const char* const plugin_ttl = "\
+:plug\n\
+ a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin with project\" ;\n\
+ lv2:project [\n\
+ doap:name \"Fake project\" ;\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+ ] .\n\
+\n\
+<http://example.org/preset>\n\
+ a pset:Preset ;\n\
+ lv2:appliesTo :plug ;\n\
+ rdfs:label \"some preset\" .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
+ LilvNodes* related = lilv_plugin_get_related(plug, pset_Preset);
+
+ assert(lilv_nodes_size(related) == 1);
+
+ lilv_node_free(pset_Preset);
+ lilv_nodes_free(related);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_project.c b/test/test_project.c
new file mode 100644
index 0000000..bc2e2c3
--- /dev/null
+++ b/test/test_project.c
@@ -0,0 +1,97 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+:plug\n\
+ a lv2:Plugin;\n\
+ a lv2:CompressorPlugin;\n\
+ doap:name \"Test plugin with project\" ;\n\
+ lv2:project [\n\
+ doap:maintainer [\n\
+ foaf:name \"David Robillard\" ;\n\
+ foaf:homepage <http://drobilla.net> ;\n\
+ foaf:mbox <mailto:d@drobilla.net>\n\
+ ] ;\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+ ] .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
+ lilv_node_free(author_name);
+
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
+ lilv_node_free(author_email);
+
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(
+ !strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
+ lilv_node_free(author_homepage);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_project_no_author.c b/test/test_project_no_author.c
new file mode 100644
index 0000000..017d359
--- /dev/null
+++ b/test/test_project_no_author.c
@@ -0,0 +1,87 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin with project\" ;\n\
+ lv2:project [\n\
+ doap:name \"Fake project\" ;\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+ ] .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!author_name);
+
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!author_email);
+
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!author_homepage);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_prototype.c b/test/test_prototype.c
new file mode 100644
index 0000000..4ad516e
--- /dev/null
+++ b/test/test_prototype.c
@@ -0,0 +1,100 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const char* const manifest_ttl = "\
+:prot\n\
+ a lv2:PluginBase ;\n\
+ rdfs:seeAlso <plugin.ttl> .\n\
+\n\
+:plug\n\
+ a lv2:Plugin ;\n\
+ lv2:binary <inst" SHLIB_EXT "> ;\n\
+ lv2:prototype :prot .\n";
+
+static const char* const plugin_ttl = "\
+:prot\n\
+ a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ lv2:project [\n\
+ doap:name \"Fake project\" ;\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency ;\n\
+ lv2:designation lv2:latency\n\
+ ] .\n\
+\n\
+:plug doap:name \"Instance\" .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, manifest_ttl, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ // Test non-inherited property
+ LilvNode* name = lilv_plugin_get_name(plug);
+ assert(!strcmp(lilv_node_as_string(name), "Instance"));
+ lilv_node_free(name);
+
+ // Test inherited property
+ const LilvNode* binary = lilv_plugin_get_library_uri(plug);
+ assert(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_reload_bundle.c b/test/test_reload_bundle.c
new file mode 100644
index 0000000..19644ff
--- /dev/null
+++ b/test/test_reload_bundle.c
@@ -0,0 +1,92 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <string.h>
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ // Create a simple plugin bundle
+ create_bundle(env,
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
+ "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ ":plug a lv2:Plugin ; "
+ "doap:name \"First name\" .");
+
+ lilv_world_load_specifications(world);
+
+ // Load bundle
+ LilvNode* bundle_uri = lilv_new_uri(world, env->test_bundle_uri);
+ lilv_world_load_bundle(world, bundle_uri);
+
+ // Check that plugin is present
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ // Check that plugin name is correct
+ LilvNode* name = lilv_plugin_get_name(plug);
+ assert(!strcmp(lilv_node_as_string(name), "First name"));
+ lilv_node_free(name);
+
+ // Unload bundle from world and delete it
+ lilv_world_unload_bundle(world, bundle_uri);
+ delete_bundle(env);
+
+ // Create a new version of the same bundle, but with a different name
+ create_bundle(env,
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
+ "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ ":plug a lv2:Plugin ; "
+ "doap:name \"Second name\" .");
+
+ // Check that plugin is no longer in the world's plugin list
+ assert(lilv_plugins_size(plugins) == 0);
+
+ // Load new bundle
+ lilv_world_load_bundle(world, bundle_uri);
+
+ // Check that plugin is present again and is the same LilvPlugin
+ const LilvPlugin* plug2 =
+ lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug2);
+ assert(plug2 == plug);
+
+ // Check that plugin now has new name
+ LilvNode* name2 = lilv_plugin_get_name(plug2);
+ assert(name2);
+ assert(!strcmp(lilv_node_as_string(name2), "Second name"));
+ lilv_node_free(name2);
+
+ // Load new bundle again (noop)
+ lilv_world_load_bundle(world, bundle_uri);
+
+ lilv_node_free(bundle_uri);
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_replace_version.c b/test/test_replace_version.c
new file mode 100644
index 0000000..a686572
--- /dev/null
+++ b/test/test_replace_version.c
@@ -0,0 +1,105 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "../src/lilv_internal.h"
+
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ LilvNode* plug_uri = lilv_new_uri(world, "http://example.org/versioned");
+ LilvNode* lv2_minorVersion = lilv_new_uri(world, LV2_CORE__minorVersion);
+ LilvNode* lv2_microVersion = lilv_new_uri(world, LV2_CORE__microVersion);
+ LilvNode* minor = NULL;
+ LilvNode* micro = NULL;
+
+ char* old_bundle_path = lilv_strjoin(LILV_TEST_DIR, "old_version.lv2/", 0);
+
+ // Load plugin from old bundle
+ LilvNode* old_bundle = lilv_new_file_uri(world, NULL, old_bundle_path);
+ lilv_world_load_bundle(world, old_bundle);
+ lilv_world_load_resource(world, plug_uri);
+
+ // Check version
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* old_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
+ assert(old_plug);
+ minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
+ micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
+ assert(!strcmp(lilv_node_as_string(minor), "1"));
+ assert(!strcmp(lilv_node_as_string(micro), "0"));
+ lilv_node_free(micro);
+ lilv_node_free(minor);
+
+ char* new_bundle_path = lilv_strjoin(LILV_TEST_DIR, "new_version.lv2/", 0);
+
+ // Load plugin from new bundle
+ LilvNode* new_bundle = lilv_new_file_uri(world, NULL, new_bundle_path);
+ lilv_world_load_bundle(world, new_bundle);
+ lilv_world_load_resource(world, plug_uri);
+
+ // Check that version in the world model has changed
+ plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* new_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
+ assert(new_plug);
+ assert(lilv_node_equals(lilv_plugin_get_bundle_uri(new_plug), new_bundle));
+ minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
+ micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
+ assert(!strcmp(lilv_node_as_string(minor), "2"));
+ assert(!strcmp(lilv_node_as_string(micro), "1"));
+ lilv_node_free(micro);
+ lilv_node_free(minor);
+
+ // Try to load the old version again
+ lilv_world_load_bundle(world, old_bundle);
+ lilv_world_load_resource(world, plug_uri);
+
+ // Check that version in the world model has not changed
+ plugins = lilv_world_get_all_plugins(world);
+ new_plug = lilv_plugins_get_by_uri(plugins, plug_uri);
+ assert(new_plug);
+ minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
+ micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
+ assert(!strcmp(lilv_node_as_string(minor), "2"));
+ assert(!strcmp(lilv_node_as_string(micro), "1"));
+ lilv_node_free(micro);
+ lilv_node_free(minor);
+
+ lilv_node_free(new_bundle);
+ lilv_node_free(old_bundle);
+ free(new_bundle_path);
+ free(old_bundle_path);
+ lilv_node_free(plug_uri);
+ lilv_node_free(lv2_minorVersion);
+ lilv_node_free(lv2_microVersion);
+
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_state.c b/test/test_state.c
new file mode 100644
index 0000000..6eb7793
--- /dev/null
+++ b/test/test_state.c
@@ -0,0 +1,581 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "../src/lilv_internal.h"
+
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+#include "lv2/state/state.h"
+#include "lv2/urid/urid.h"
+#include "serd/serd.h"
+
+#ifdef _WIN32
+# include <direct.h>
+# define mkdir(path, flags) _mkdir(path)
+#else
+# include <sys/stat.h>
+# include <unistd.h>
+#endif
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+uint32_t atom_Float = 0;
+float in = 1.0;
+float out = 42.0;
+float control = 1234.0;
+
+static const void*
+get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type)
+{
+ if (!strcmp(port_symbol, "input")) {
+ *size = sizeof(float);
+ *type = atom_Float;
+ return &in;
+ } else if (!strcmp(port_symbol, "output")) {
+ *size = sizeof(float);
+ *type = atom_Float;
+ return &out;
+ } else if (!strcmp(port_symbol, "control")) {
+ *size = sizeof(float);
+ *type = atom_Float;
+ return &control;
+ } else {
+ fprintf(stderr,
+ "error: get_port_value for nonexistent port `%s'\n",
+ port_symbol);
+ *size = *type = 0;
+ return NULL;
+ }
+}
+
+static void
+set_port_value(const char* port_symbol,
+ void* user_data,
+ const void* value,
+ uint32_t size,
+ uint32_t type)
+{
+ if (!strcmp(port_symbol, "input")) {
+ in = *(const float*)value;
+ } else if (!strcmp(port_symbol, "output")) {
+ out = *(const float*)value;
+ } else if (!strcmp(port_symbol, "control")) {
+ control = *(const float*)value;
+ } else {
+ fprintf(stderr,
+ "error: set_port_value for nonexistent port `%s'\n",
+ port_symbol);
+ }
+}
+
+char** uris = NULL;
+size_t n_uris = 0;
+
+static LV2_URID
+map_uri(LV2_URID_Map_Handle handle, const char* uri)
+{
+ for (size_t i = 0; i < n_uris; ++i) {
+ if (!strcmp(uris[i], uri)) {
+ return i + 1;
+ }
+ }
+
+ assert(serd_uri_string_has_scheme((const uint8_t*)uri));
+ uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
+ uris[n_uris - 1] = lilv_strdup(uri);
+ return n_uris;
+}
+
+static const char*
+unmap_uri(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+ if (urid > 0 && urid <= n_uris) {
+ return uris[urid - 1];
+ }
+ return NULL;
+}
+
+static char* temp_dir = NULL;
+
+static char*
+lilv_make_path(LV2_State_Make_Path_Handle handle, const char* path)
+{
+ return lilv_path_join(temp_dir, path);
+}
+
+static void
+lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
+{
+ lilv_free(path);
+}
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(LILV_TEST_BUNDLE);
+ SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true);
+ LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf);
+ LilvNode* plugin_uri =
+ lilv_new_uri(world, "http://example.org/lilv-test-plugin");
+ lilv_world_load_bundle(world, bundle_uri);
+ free(abs_bundle);
+ serd_node_free(&bundle);
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
+ assert(plugin);
+
+ LV2_URID_Map map = {NULL, map_uri};
+ LV2_Feature map_feature = {LV2_URID_MAP_URI, &map};
+ LV2_URID_Unmap unmap = {NULL, unmap_uri};
+ LV2_Feature unmap_feature = {LV2_URID_UNMAP_URI, &unmap};
+ const LV2_Feature* features[] = {&map_feature, &unmap_feature, NULL};
+
+ atom_Float = map.map(map.handle, "http://lv2plug.in/ns/ext/atom#Float");
+
+ LilvNode* num = lilv_new_int(world, 5);
+ LilvState* nostate = lilv_state_new_from_file(world, &map, num, "/junk");
+ assert(!nostate);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, features);
+ assert(instance);
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &in);
+ lilv_instance_connect_port(instance, 1, &out);
+ lilv_instance_run(instance, 1);
+ assert(in == 1.0);
+ assert(out == 1.0);
+
+ temp_dir = lilv_realpath("temp");
+
+ const char* scratch_dir = NULL;
+ char* copy_dir = NULL;
+ char* link_dir = NULL;
+ char* save_dir = NULL;
+
+ // Get instance state state
+ LilvState* state = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ save_dir,
+ get_port_value,
+ world,
+ 0,
+ NULL);
+
+ // Get another instance state
+ LilvState* state2 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ save_dir,
+ get_port_value,
+ world,
+ 0,
+ NULL);
+
+ // Ensure they are equal
+ assert(lilv_state_equals(state, state2));
+
+ // Check that we can't delete unsaved state
+ assert(lilv_state_delete(world, state));
+
+ // Check that state has no URI
+ assert(!lilv_state_get_uri(state));
+
+ // Check that we can't save a state with no URI
+ char* bad_state_str =
+ lilv_state_to_string(world, &map, &unmap, state, NULL, NULL);
+ assert(!bad_state_str);
+
+ // Check that we can't restore the NULL string (and it doesn't crash)
+ LilvState* bad_state = lilv_state_new_from_string(world, &map, NULL);
+ assert(!bad_state);
+
+ // Save state to a string
+ char* state1_str = lilv_state_to_string(
+ world, &map, &unmap, state, "http://example.org/state1", NULL);
+
+ // Restore from string
+ LilvState* from_str = lilv_state_new_from_string(world, &map, state1_str);
+
+ // Ensure they are equal
+ assert(lilv_state_equals(state, from_str));
+ lilv_free(state1_str);
+
+ const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(state);
+ assert(lilv_node_equals(state_plugin_uri, plugin_uri));
+
+ // Tinker with the label of the first state
+ assert(lilv_state_get_label(state) == NULL);
+ lilv_state_set_label(state, "Test State Old Label");
+ assert(!strcmp(lilv_state_get_label(state), "Test State Old Label"));
+ lilv_state_set_label(state, "Test State");
+ assert(!strcmp(lilv_state_get_label(state), "Test State"));
+
+ assert(!lilv_state_equals(state, state2)); // Label changed
+
+ // Run and get a new instance state (which should now differ)
+ lilv_instance_run(instance, 1);
+ LilvState* state3 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ save_dir,
+ get_port_value,
+ world,
+ 0,
+ NULL);
+ assert(!lilv_state_equals(state2, state3)); // num_runs changed
+
+ // Restore instance state to original state
+ lilv_state_restore(state2, instance, set_port_value, NULL, 0, NULL);
+
+ // Take a new snapshot and ensure it matches the set state
+ LilvState* state4 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ save_dir,
+ get_port_value,
+ world,
+ 0,
+ NULL);
+ assert(lilv_state_equals(state2, state4));
+
+ // Set some metadata properties
+ lilv_state_set_metadata(state,
+ map.map(map.handle, LILV_NS_RDFS "comment"),
+ "This is a comment",
+ strlen("This is a comment") + 1,
+ map.map(map.handle,
+ "http://lv2plug.in/ns/ext/atom#Literal"),
+ LV2_STATE_IS_POD);
+ lilv_state_set_metadata(state,
+ map.map(map.handle, "http://example.org/metablob"),
+ "LIVEBEEF",
+ strlen("LIVEBEEF") + 1,
+ map.map(map.handle, "http://example.org/MetaBlob"),
+ 0);
+
+ // Save state to a directory
+ int ret = lilv_state_save(
+ world, &map, &unmap, state, NULL, "state/state.lv2", "state.ttl");
+ assert(!ret);
+
+ // Load state from directory
+ LilvState* state5 = lilv_state_new_from_file(world,
+ &map,
+ NULL,
+ "state/state.lv2/state.ttl");
+
+ assert(lilv_state_equals(state, state5)); // Round trip accuracy
+ assert(lilv_state_get_num_properties(state) == 8);
+
+ // Attempt to save state to nowhere (error)
+ ret = lilv_state_save(world, &map, &unmap, state, NULL, NULL, NULL);
+ assert(ret);
+
+ // Save another state to the same directory (update manifest)
+ ret = lilv_state_save(
+ world, &map, &unmap, state, NULL, "state/state.lv2", "state2.ttl");
+ assert(!ret);
+
+ // Save state with URI to a directory
+ const char* state_uri = "http://example.org/state";
+ ret = lilv_state_save(world,
+ &map,
+ &unmap,
+ state,
+ state_uri,
+ "state/state6.lv2",
+ "state6.ttl");
+ assert(!ret);
+
+ // Load state bundle into world and verify it matches
+ {
+ uint8_t* state6_path =
+ (uint8_t*)lilv_path_absolute("state/state6.lv2/");
+ SerdNode state6_uri = serd_node_new_file_uri(state6_path, 0, 0, true);
+ LilvNode* state6_bundle =
+ lilv_new_uri(world, (const char*)state6_uri.buf);
+ LilvNode* state6_node = lilv_new_uri(world, state_uri);
+ lilv_world_load_bundle(world, state6_bundle);
+ lilv_world_load_resource(world, state6_node);
+ serd_node_free(&state6_uri);
+ lilv_free(state6_path);
+
+ LilvState* state6 = lilv_state_new_from_world(world, &map, state6_node);
+ assert(lilv_state_equals(state, state6)); // Round trip accuracy
+
+ // Check that loaded state has correct URI
+ assert(lilv_state_get_uri(state6));
+ assert(!strcmp(lilv_node_as_string(lilv_state_get_uri(state6)),
+ state_uri));
+
+ // Unload state from world
+ lilv_world_unload_resource(world, state6_node);
+ lilv_world_unload_bundle(world, state6_bundle);
+
+ // Ensure that it is no longer present
+ assert(!lilv_state_new_from_world(world, &map, state6_node));
+ lilv_node_free(state6_bundle);
+ lilv_node_free(state6_node);
+
+ // Delete state
+ lilv_state_delete(world, state6);
+ lilv_state_free(state6);
+ }
+
+ // Make directories and test files support
+ mkdir("temp", 0700);
+ scratch_dir = temp_dir;
+ mkdir("files", 0700);
+ copy_dir = lilv_realpath("files");
+ mkdir("links", 0700);
+ link_dir = lilv_realpath("links");
+
+ LV2_State_Make_Path make_path = {NULL, lilv_make_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+ LV2_State_Free_Path free_path = {NULL, lilv_free_path};
+ LV2_Feature free_path_feature = {LV2_STATE__freePath, &free_path};
+ const LV2_Feature* ffeatures[] = {&make_path_feature,
+ &map_feature,
+ &free_path_feature,
+ NULL};
+
+ lilv_instance_deactivate(instance);
+ lilv_instance_free(instance);
+ instance = lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &in);
+ lilv_instance_connect_port(instance, 1, &out);
+ lilv_instance_run(instance, 1);
+
+ // Test instantiating twice
+ LilvInstance* instance2 =
+ lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
+ if (!instance2) {
+ fprintf(stderr,
+ "Failed to create multiple instances of <%s>\n",
+ lilv_node_as_uri(state_plugin_uri));
+ return 1;
+ }
+ lilv_instance_free(instance2);
+
+ // Get instance state state
+ LilvState* fstate = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ "state/fstate.lv2",
+ get_port_value,
+ world,
+ 0,
+ ffeatures);
+
+ {
+ // Get another instance state
+ LilvState* fstate2 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ "state/fstate2.lv2",
+ get_port_value,
+ world,
+ 0,
+ ffeatures);
+
+ // Check that it is identical
+ assert(lilv_state_equals(fstate, fstate2));
+
+ lilv_state_delete(world, fstate2);
+ lilv_state_free(fstate2);
+ }
+
+ // Run, writing more to rec file
+ lilv_instance_run(instance, 2);
+
+ // Get yet another instance state
+ LilvState* fstate3 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ "state/fstate3.lv2",
+ get_port_value,
+ world,
+ 0,
+ ffeatures);
+
+ // Should be different
+ assert(!lilv_state_equals(fstate, fstate3));
+
+ // Save state to a directory
+ ret = lilv_state_save(
+ world, &map, &unmap, fstate, NULL, "state/fstate.lv2", "fstate.ttl");
+ assert(!ret);
+
+ // Load state from directory
+ LilvState* fstate4 = lilv_state_new_from_file(
+ world, &map, NULL, "state/fstate.lv2/fstate.ttl");
+ assert(lilv_state_equals(fstate, fstate4)); // Round trip accuracy
+
+ // Restore instance state to loaded state
+ lilv_state_restore(fstate4, instance, set_port_value, NULL, 0, ffeatures);
+
+ // Take a new snapshot and ensure it matches
+ LilvState* fstate5 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ "state/fstate5.lv2",
+ get_port_value,
+ world,
+ 0,
+ ffeatures);
+ assert(lilv_state_equals(fstate3, fstate5));
+
+ // Save state to a (different) directory again
+ ret = lilv_state_save(
+ world, &map, &unmap, fstate, NULL, "state/fstate6.lv2", "fstate6.ttl");
+ assert(!ret);
+
+ // Reload it and ensure it's identical to the other loaded version
+ LilvState* fstate6 = lilv_state_new_from_file(
+ world, &map, NULL, "state/fstate6.lv2/fstate6.ttl");
+ assert(lilv_state_equals(fstate4, fstate6));
+
+ // Run, changing rec file (without changing size)
+ lilv_instance_run(instance, 3);
+
+ // Take a new snapshot
+ LilvState* fstate7 = lilv_state_new_from_instance(plugin,
+ instance,
+ &map,
+ scratch_dir,
+ copy_dir,
+ link_dir,
+ "state/fstate7.lv2",
+ get_port_value,
+ world,
+ 0,
+ ffeatures);
+ assert(!lilv_state_equals(fstate6, fstate7));
+
+ // Save the changed state to a (different) directory again
+ ret = lilv_state_save(
+ world, &map, &unmap, fstate7, NULL, "state/fstate7.lv2", "fstate7.ttl");
+ assert(!ret);
+
+ // Reload it and ensure it's changed
+ LilvState* fstate72 = lilv_state_new_from_file(
+ world, &map, NULL, "state/fstate7.lv2/fstate7.ttl");
+ assert(lilv_state_equals(fstate72, fstate7));
+ assert(!lilv_state_equals(fstate6, fstate72));
+
+ // Delete saved state we still have a state in memory that points to
+ lilv_state_delete(world, fstate7);
+ lilv_state_delete(world, fstate6);
+ lilv_state_delete(world, fstate5);
+ lilv_state_delete(world, fstate3);
+ lilv_state_delete(world, fstate);
+ lilv_state_delete(world, state2);
+ lilv_state_delete(world, state);
+
+ // Delete remaining states on disk we've lost a reference to
+ const char* const old_state_paths[] = {"state/state.lv2/state.ttl",
+ "state/state.lv2/state2.ttl",
+ "state/fstate.lv2/fstate.ttl",
+ NULL};
+
+ for (const char* const* p = old_state_paths; *p; ++p) {
+ const char* path = *p;
+ LilvState* old_state =
+ lilv_state_new_from_file(world, &map, NULL, path);
+ lilv_state_delete(world, old_state);
+ lilv_state_free(old_state);
+ }
+
+ lilv_instance_deactivate(instance);
+ lilv_instance_free(instance);
+
+ lilv_node_free(num);
+
+ lilv_state_free(state);
+ lilv_state_free(from_str);
+ lilv_state_free(state2);
+ lilv_state_free(state3);
+ lilv_state_free(state4);
+ lilv_state_free(state5);
+ lilv_state_free(fstate);
+ lilv_state_free(fstate3);
+ lilv_state_free(fstate4);
+ lilv_state_free(fstate5);
+ lilv_state_free(fstate6);
+ lilv_state_free(fstate7);
+ lilv_state_free(fstate72);
+
+ rmdir("state");
+
+ // Free URI map
+ for (size_t i = 0; i < n_uris; ++i) {
+ free(uris[i]);
+ }
+ free(uris);
+ n_uris = 0;
+
+ lilv_node_free(plugin_uri);
+ lilv_node_free(bundle_uri);
+ free(link_dir);
+ free(copy_dir);
+ free(temp_dir);
+
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_string.c b/test/test_string.c
new file mode 100644
index 0000000..8d79327
--- /dev/null
+++ b/test/test_string.c
@@ -0,0 +1,94 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#define _POSIX_C_SOURCE 200809L /* for setenv */
+
+#undef NDEBUG
+
+#include "../src/lilv_internal.h"
+
+#ifdef _WIN32
+# include <windows.h>
+# define setenv(n, v, r) SetEnvironmentVariable((n), (v))
+# define unsetenv(n) SetEnvironmentVariable((n), NULL)
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(void)
+{
+ char* s = NULL;
+
+ assert(!strcmp((s = lilv_dirname("/foo/bar")), "/foo"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("/foo/bar/")), "/foo"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("/foo///bar/")), "/foo"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("/foo///bar//")), "/foo"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("foo")), "."));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("/foo")), "/"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("/")), "/"));
+ free(s);
+ assert(!strcmp((s = lilv_dirname("//")), "/"));
+ free(s);
+ assert(!strcmp((s = lilv_path_relative_to("/a/b", "/a/")), "b"));
+ free(s);
+ assert(!strcmp((s = lilv_path_relative_to("/a", "/b/c/")), "/a"));
+ free(s);
+ assert(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/")), "../c"));
+ free(s);
+ assert(
+ !strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/e/")), "../../c"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join("/a", "b")), "/a/b"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join("/a", "/b")), "/a/b"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join("/a/", "/b")), "/a/b"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join("/a/", "b")), "/a/b"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join("/a", NULL)), "/a/"));
+ free(s);
+ assert(!strcmp((s = lilv_path_join(NULL, "/b")), "/b"));
+ free(s);
+
+#ifndef _WIN32
+ setenv("LILV_TEST_1", "test", 1);
+ char* home_foo = lilv_strjoin(getenv("HOME"), "/foo", NULL);
+ assert(!strcmp((s = lilv_expand("$LILV_TEST_1")), "test"));
+ free(s);
+ assert(!strcmp((s = lilv_expand("~")), getenv("HOME")));
+ free(s);
+ assert(!strcmp((s = lilv_expand("~foo")), "~foo"));
+ free(s);
+ assert(!strcmp((s = lilv_expand("~/foo")), home_foo));
+ free(s);
+ assert(!strcmp((s = lilv_expand("$NOT_A_VAR")), "$NOT_A_VAR"));
+ free(s);
+ free(home_foo);
+ unsetenv("LILV_TEST_1");
+#endif
+
+ return 0;
+}
diff --git a/test/test_ui.c b/test/test_ui.c
new file mode 100644
index 0000000..6230318
--- /dev/null
+++ b/test/test_ui.c
@@ -0,0 +1,180 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
+:plug a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:optionalFeature lv2:hardRTCapable ;\n\
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ;\n\
+ lv2ui:ui :ui , :ui2 , :ui3 , :ui4 ;\n\
+ doap:maintainer [\n\
+ foaf:name \"David Robillard\" ;\n\
+ foaf:homepage <http://drobilla.net> ;\n\
+ foaf:mbox <mailto:d@drobilla.net>\n\
+ ] ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\" ;\n\
+ lv2:minimum -1.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:default 0.5\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 1 ;\n\
+ lv2:symbol \"bar\" ;\n\
+ lv2:name \"Baz\" ;\n\
+ lv2:minimum -2.0 ;\n\
+ lv2:maximum 2.0 ;\n\
+ lv2:default 1.0\n\
+ ] , [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:OutputPort ;\n\
+ lv2:index 2 ;\n\
+ lv2:symbol \"latency\" ;\n\
+ lv2:name \"Latency\" ;\n\
+ lv2:portProperty lv2:reportsLatency\n\
+ ] .\n\
+\n\
+ :ui\n\
+ a lv2ui:GtkUI ;\n\
+ lv2ui:requiredFeature lv2ui:makeResident ;\n\
+ lv2ui:binary <ui" SHLIB_EXT "> ;\n\
+ lv2ui:optionalFeature lv2ui:ext_presets .\n\
+\n\
+ :ui2\n\
+ a lv2ui:GtkUI ;\n\
+ lv2ui:binary <ui2" SHLIB_EXT "> .\n\
+\n\
+ :ui3\n\
+ a lv2ui:GtkUI ;\n\
+ lv2ui:binary <ui3" SHLIB_EXT "> .\n\
+\n\
+ :ui4\n\
+ a lv2ui:GtkUI ;\n\
+ lv2ui:binary <ui4" SHLIB_EXT "> .\n";
+
+static unsigned
+ui_supported(const char* container_type_uri, const char* ui_type_uri)
+{
+ return !strcmp(container_type_uri, ui_type_uri);
+}
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvUIs* uis = lilv_plugin_get_uis(plug);
+ assert(lilv_uis_size(uis) == 4);
+
+ const LilvUI* ui0 = lilv_uis_get(uis, lilv_uis_begin(uis));
+ assert(ui0);
+
+ LilvNode* ui_uri = lilv_new_uri(world, "http://example.org/ui");
+ LilvNode* ui2_uri = lilv_new_uri(world, "http://example.org/ui3");
+ LilvNode* ui3_uri = lilv_new_uri(world, "http://example.org/ui4");
+ LilvNode* noui_uri = lilv_new_uri(world, "http://example.org/notaui");
+
+ const LilvUI* ui0_2 = lilv_uis_get_by_uri(uis, ui_uri);
+ assert(ui0 == ui0_2);
+ assert(lilv_node_equals(lilv_ui_get_uri(ui0_2), ui_uri));
+
+ const LilvUI* ui2 = lilv_uis_get_by_uri(uis, ui2_uri);
+ assert(ui2 != ui0);
+
+ const LilvUI* ui3 = lilv_uis_get_by_uri(uis, ui3_uri);
+ assert(ui3 != ui0);
+
+ const LilvUI* noui = lilv_uis_get_by_uri(uis, noui_uri);
+ assert(noui == NULL);
+
+ const LilvNodes* classes = lilv_ui_get_classes(ui0);
+ assert(lilv_nodes_size(classes) == 1);
+
+ LilvNode* ui_class_uri =
+ lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI");
+
+ LilvNode* unknown_ui_class_uri =
+ lilv_new_uri(world, "http://example.org/mysteryUI");
+
+ assert(lilv_node_equals(lilv_nodes_get_first(classes), ui_class_uri));
+ assert(lilv_ui_is_a(ui0, ui_class_uri));
+
+ const LilvNode* ui_type = NULL;
+ assert(lilv_ui_is_supported(ui0, ui_supported, ui_class_uri, &ui_type));
+ assert(!lilv_ui_is_supported(
+ ui0, ui_supported, unknown_ui_class_uri, &ui_type));
+ assert(lilv_node_equals(ui_type, ui_class_uri));
+
+ const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
+ const LilvNode* ui_bundle_uri = lilv_ui_get_bundle_uri(ui0);
+ assert(lilv_node_equals(plug_bundle_uri, ui_bundle_uri));
+
+ const size_t ui_binary_uri_str_len =
+ strlen(lilv_node_as_string(plug_bundle_uri)) + strlen("ui" SHLIB_EXT);
+
+ char* ui_binary_uri_str = (char*)calloc(1, ui_binary_uri_str_len + 1);
+ snprintf(ui_binary_uri_str,
+ ui_binary_uri_str_len + 1,
+ "%s%s",
+ lilv_node_as_string(plug_bundle_uri),
+ "ui" SHLIB_EXT);
+
+ const LilvNode* ui_binary_uri = lilv_ui_get_binary_uri(ui0);
+
+ LilvNode* expected_uri = lilv_new_uri(world, ui_binary_uri_str);
+ assert(lilv_node_equals(expected_uri, ui_binary_uri));
+
+ free(ui_binary_uri_str);
+ lilv_node_free(unknown_ui_class_uri);
+ lilv_node_free(ui_class_uri);
+ lilv_node_free(ui_uri);
+ lilv_node_free(ui2_uri);
+ lilv_node_free(ui3_uri);
+ lilv_node_free(noui_uri);
+ lilv_node_free(expected_uri);
+ lilv_uis_free(uis);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_util.c b/test/test_util.c
new file mode 100644
index 0000000..982df3e
--- /dev/null
+++ b/test/test_util.c
@@ -0,0 +1,63 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#define _XOPEN_SOURCE 600 /* for mkstemp */
+
+#undef NDEBUG
+
+#include "../src/lilv_internal.h"
+
+#ifdef _WIN32
+# include <io.h>
+# define mkstemp(pat) _mktemp(pat)
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(void)
+{
+ assert(!lilv_realpath(NULL));
+
+ char a_path[16];
+ char b_path[16];
+ strncpy(a_path, "copy_a_XXXXXX", sizeof(a_path));
+ strncpy(b_path, "copy_b_XXXXXX", sizeof(b_path));
+ mkstemp(a_path);
+ mkstemp(b_path);
+
+ FILE* fa = fopen(a_path, "w");
+ FILE* fb = fopen(b_path, "w");
+ fprintf(fa, "AA\n");
+ fprintf(fb, "AB\n");
+ fclose(fa);
+ fclose(fb);
+
+ assert(lilv_copy_file("does/not/exist", "copy"));
+ assert(lilv_copy_file(a_path, "not/a/dir/copy"));
+ assert(!lilv_copy_file(a_path, "copy_c"));
+ assert(!lilv_file_equals(a_path, b_path));
+ assert(lilv_file_equals(a_path, a_path));
+ assert(lilv_file_equals(a_path, "copy_c"));
+ assert(!lilv_file_equals("does/not/exist", b_path));
+ assert(!lilv_file_equals(a_path, "does/not/exist"));
+ assert(!lilv_file_equals("does/not/exist", "/does/not/either"));
+
+ return 0;
+}
diff --git a/test/test_value.c b/test/test_value.c
new file mode 100644
index 0000000..ce95166
--- /dev/null
+++ b/test/test_value.c
@@ -0,0 +1,173 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <string.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ a lv2:CompressorPlugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ; a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"Foo\" ;\n\
+ ] .";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ LilvNode* uval = lilv_new_uri(world, "http://example.org");
+ LilvNode* sval = lilv_new_string(world, "Foo");
+ LilvNode* ival = lilv_new_int(world, 42);
+ LilvNode* fval = lilv_new_float(world, 1.6180);
+
+ assert(lilv_node_is_uri(uval));
+ assert(lilv_node_is_string(sval));
+ assert(lilv_node_is_int(ival));
+ assert(lilv_node_is_float(fval));
+
+ assert(!lilv_node_is_literal(NULL));
+ assert(!lilv_node_is_literal(uval));
+ assert(lilv_node_is_literal(sval));
+ assert(lilv_node_is_literal(ival));
+ assert(lilv_node_is_literal(fval));
+ assert(!lilv_node_get_path(fval, NULL));
+
+ assert(!strcmp(lilv_node_as_uri(uval), "http://example.org"));
+ assert(!strcmp(lilv_node_as_string(sval), "Foo"));
+ assert(lilv_node_as_int(ival) == 42);
+ assert(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON);
+ assert(isnan(lilv_node_as_float(sval)));
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+ assert(!strcmp(lilv_uri_to_path("file:///foo"), "/foo"));
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# pragma GCC diagnostic pop
+#endif
+
+ LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar");
+ LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo");
+ LilvNode* host_abs = lilv_new_file_uri(world, "host", "/foo/bar");
+ LilvNode* host_rel = lilv_new_file_uri(world, "host", "foo");
+
+ assert(!strcmp(lilv_node_as_uri(loc_abs), "file:///foo/bar"));
+ assert(!strncmp(lilv_node_as_uri(loc_rel), "file:///", 8));
+ assert(!strcmp(lilv_node_as_uri(host_abs), "file://host/foo/bar"));
+ assert(!strncmp(lilv_node_as_uri(host_rel), "file://host/", 12));
+
+ lilv_node_free(host_rel);
+ lilv_node_free(host_abs);
+ lilv_node_free(loc_rel);
+ lilv_node_free(loc_abs);
+
+ char* tok = lilv_node_get_turtle_token(uval);
+ assert(!strcmp(tok, "<http://example.org>"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(sval);
+ assert(!strcmp(tok, "Foo"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(ival);
+ assert(!strcmp(tok, "42"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(fval);
+ assert(!strncmp(tok, "1.6180", 6));
+ lilv_free(tok);
+
+ LilvNode* uval_e = lilv_new_uri(world, "http://example.org");
+ LilvNode* sval_e = lilv_new_string(world, "Foo");
+ LilvNode* ival_e = lilv_new_int(world, 42);
+ LilvNode* fval_e = lilv_new_float(world, 1.6180);
+ LilvNode* uval_ne = lilv_new_uri(world, "http://no-example.org");
+ LilvNode* sval_ne = lilv_new_string(world, "Bar");
+ LilvNode* ival_ne = lilv_new_int(world, 24);
+ LilvNode* fval_ne = lilv_new_float(world, 3.14159);
+
+ assert(lilv_node_equals(uval, uval_e));
+ assert(lilv_node_equals(sval, sval_e));
+ assert(lilv_node_equals(ival, ival_e));
+ assert(lilv_node_equals(fval, fval_e));
+
+ assert(!lilv_node_equals(uval, uval_ne));
+ assert(!lilv_node_equals(sval, sval_ne));
+ assert(!lilv_node_equals(ival, ival_ne));
+ assert(!lilv_node_equals(fval, fval_ne));
+
+ assert(!lilv_node_equals(uval, sval));
+ assert(!lilv_node_equals(sval, ival));
+ assert(!lilv_node_equals(ival, fval));
+
+ LilvNode* uval_dup = lilv_node_duplicate(uval);
+ assert(lilv_node_equals(uval, uval_dup));
+
+ LilvNode* ifval = lilv_new_float(world, 42.0);
+ assert(!lilv_node_equals(ival, ifval));
+ lilv_node_free(ifval);
+
+ LilvNode* nil = NULL;
+ assert(!lilv_node_equals(uval, nil));
+ assert(!lilv_node_equals(nil, uval));
+ assert(lilv_node_equals(nil, nil));
+
+ LilvNode* nil2 = lilv_node_duplicate(nil);
+ assert(lilv_node_equals(nil, nil2));
+
+ lilv_node_free(uval);
+ lilv_node_free(sval);
+ lilv_node_free(ival);
+ lilv_node_free(fval);
+ lilv_node_free(uval_e);
+ lilv_node_free(sval_e);
+ lilv_node_free(ival_e);
+ lilv_node_free(fval_e);
+ lilv_node_free(uval_ne);
+ lilv_node_free(sval_ne);
+ lilv_node_free(ival_ne);
+ lilv_node_free(fval_ne);
+ lilv_node_free(uval_dup);
+ lilv_node_free(nil2);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_verify.c b/test/test_verify.c
new file mode 100644
index 0000000..dd88ba5
--- /dev/null
+++ b/test/test_verify.c
@@ -0,0 +1,57 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+
+static const char* const plugin_ttl = "\
+:plug a lv2:Plugin ;\n\
+ doap:name \"Test plugin\" ;\n\
+ lv2:port [\n\
+ a lv2:ControlPort ;\n\
+ a lv2:InputPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"foo\" ;\n\
+ lv2:name \"bar\"\n\
+ ] .\n";
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* explug =
+ lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+
+ assert(explug);
+ assert(lilv_plugin_verify(explug));
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
+}
diff --git a/test/test_world.c b/test/test_world.c
new file mode 100644
index 0000000..b8572d2
--- /dev/null
+++ b/test/test_world.c
@@ -0,0 +1,51 @@
+/*
+ Copyright 2007-2020 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.
+*/
+
+#undef NDEBUG
+
+#include "lilv_test_utils.h"
+
+#include "lilv/lilv.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main(void)
+{
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ LilvNode* num = lilv_new_int(env->world, 4);
+ LilvNode* uri = lilv_new_uri(env->world, "http://example.org/object");
+
+ LilvNodes* matches = lilv_world_find_nodes(world, num, NULL, NULL);
+ assert(!matches);
+
+ matches = lilv_world_find_nodes(world, NULL, num, NULL);
+ assert(!matches);
+
+ matches = lilv_world_find_nodes(world, NULL, uri, NULL);
+ assert(!matches);
+
+ lilv_node_free(uri);
+ lilv_node_free(num);
+
+ lilv_world_unload_bundle(world, NULL);
+ lilv_test_env_free(env);
+
+ return 0;
+}