summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-07-15 00:02:32 +0200
committerDavid Robillard <d@drobilla.net>2020-07-15 10:47:05 +0200
commitf115728a52eab27852af57ef8904419309ca52b4 (patch)
tree40b74fb5e40abbdab83c2e852178ec88684a459a /test
parent81babb758e614ae622b39849c0c65cf38505a912 (diff)
downloadlilv-f115728a52eab27852af57ef8904419309ca52b4.tar.gz
lilv-f115728a52eab27852af57ef8904419309ca52b4.tar.bz2
lilv-f115728a52eab27852af57ef8904419309ca52b4.zip
Rewrite and separate common test facilities
Diffstat (limited to 'test')
-rw-r--r--test/lilv_test.c644
-rw-r--r--test/lilv_test_utils.c184
-rw-r--r--test/lilv_test_utils.h71
3 files changed, 485 insertions, 414 deletions
diff --git a/test/lilv_test.c b/test/lilv_test.c
index 9d7d42f..e4d143f 100644
--- a/test/lilv_test.c
+++ b/test/lilv_test.c
@@ -18,6 +18,8 @@
#define _POSIX_C_SOURCE 200809L /* for setenv */
#define _XOPEN_SOURCE 600 /* for mkstemp */
+#include "lilv_test_utils.h"
+
#include "../src/lilv_internal.h"
#ifdef _WIN32
@@ -60,226 +62,38 @@
# define SHLIB_EXT ".so"
#endif
-static char test_bundle_path[TEST_PATH_MAX + sizeof("/.lv2/lilv-test.lv2")];
-static char test_bundle_uri[sizeof(test_bundle_path) + sizeof("file:///")];
-static char test_manifest_path[sizeof(test_bundle_path) + sizeof("/manifest.ttl")];
-static char test_content_path[sizeof(test_bundle_path) + sizeof("plugin.ttl")];
-
-static LilvWorld* world;
-
-int test_count = 0;
-int error_count = 0;
-
-static void
-delete_bundle(void)
-{
- unlink(test_content_path);
- unlink(test_manifest_path);
- remove(test_bundle_path);
-}
-
-static void
-init_tests(void)
-{
- char* test_path = lilv_realpath(LILV_TEST_DIR);
-
- snprintf(test_bundle_path, sizeof(test_bundle_path),
- "%s/test_lv2_path/lilv-test.lv2", test_path);
- lilv_mkdir_p(test_bundle_path);
-
- SerdNode s = serd_node_new_file_uri(
- (const uint8_t*)test_bundle_path, NULL, NULL, true);
-
- snprintf(test_bundle_uri, sizeof(test_bundle_uri), "%s/",
- (const char*)s.buf);
- snprintf(test_manifest_path, sizeof(test_manifest_path), "%s/manifest.ttl",
- test_bundle_path);
- snprintf(test_content_path, sizeof(test_content_path), "%s/plugin.ttl",
- test_bundle_path);
-
- serd_node_free(&s);
- lilv_free(test_path);
-
- delete_bundle();
-}
-
-static void
-fatal_error(const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, args);
- va_end(args);
- exit(1);
-}
-
-static void
-write_file(const char* name, const char* content)
-{
- FILE* f = fopen(name, "w");
- size_t len = strlen(content);
- if (fwrite(content, 1, len, f) != len) {
- fatal_error("Failed to write to file '%s' (%s)\n",
- name, strerror(errno));
- }
- fclose(f);
-}
-
-static int
-init_world(void)
-{
- world = lilv_world_new();
-
- // Set custom LV2_PATH in build directory to only use test data
- char* test_path = lilv_realpath(LILV_TEST_DIR);
- char* lv2_path = lilv_strjoin(test_path, "/test_lv2_path", NULL);
- LilvNode* path = lilv_new_string(world, lv2_path);
- lilv_world_set_option(world, LILV_OPTION_LV2_PATH, path);
- free(lv2_path);
- free(test_path);
- lilv_node_free(path);
-
- return world != NULL;
-}
-
-static int
-load_all_bundles(void)
-{
- if (!init_world()) {
- return 0;
- }
- lilv_world_load_all(world);
- return 1;
-}
-
-static void
-create_bundle(const char* manifest, const char* content)
-{
- if (mkdir(test_bundle_path, 0700) && errno != EEXIST) {
- fatal_error("Failed to create directory '%s' (%s)\n",
- test_bundle_path, strerror(errno));
- }
- write_file(test_manifest_path, manifest);
- write_file(test_content_path, content);
-}
-
-static int
-start_bundle(const char* manifest, const char* content)
-{
- create_bundle(manifest, content);
- return load_all_bundles();
-}
-
-static void
-unload_bundle(void)
-{
- if (world) {
- lilv_world_free(world);
- }
- world = NULL;
-}
-
-static void
-cleanup(void)
-{
- delete_bundle();
-}
-
-static void
-set_env(const char* name, const char* value)
-{
-#ifdef _WIN32
- // setenv on Windows does not modify the current process' environment
- const size_t len = strlen(name) + 1 + strlen(value) + 1;
- char* str = (char*)calloc(1, len);
- snprintf(str, len, "%s=%s", name, value);
- putenv(str);
- free(str);
-#else
- setenv(name, value, 1);
-#endif
-}
-
-/*****************************************************************************/
-
#define TEST_CASE(name) { #name, test_##name }
#define TEST_ASSERT(check) do {\
- test_count++;\
if (!(check)) {\
- error_count++;\
fprintf(stderr, "lilv_test.c:%d: error: test `%s' failed\n", __LINE__, #check);\
abort();\
}\
} while (0)
-typedef int (*TestFunc)(void);
+typedef int (*TestFunc)(LilvTestEnv*);
struct TestCase {
const char* title;
TestFunc func;
};
-#define PREFIX_ATOM "@prefix atom: <http://lv2plug.in/ns/ext/atom#> . \n"
-#define PREFIX_LINE "@prefix : <http://example.org/> .\n"
-#define PREFIX_LV2 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
-#define PREFIX_LV2EV "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n"
-#define PREFIX_LV2UI "@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n"
-#define PREFIX_RDF "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
-#define PREFIX_RDFS "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
-#define PREFIX_FOAF "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
-#define PREFIX_DOAP "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
-#define PREFIX_PSET "@prefix pset: <http://lv2plug.in/ns/ext/presets#> .\n"
-
-#define MANIFEST_PREFIXES PREFIX_LINE PREFIX_LV2 PREFIX_RDFS
-#define BUNDLE_PREFIXES PREFIX_ATOM PREFIX_LINE PREFIX_LV2 PREFIX_RDF PREFIX_RDFS PREFIX_FOAF PREFIX_DOAP PREFIX_PSET
-#define PLUGIN_NAME(name) "doap:name \"" name "\""
-#define LICENSE_GPL "doap:license <http://usefulinc.com/doap/licenses/gpl>"
-
-static const char* uris_plugin = "http://example.org/plug";
-static LilvNode* plugin_uri_value;
-static LilvNode* plugin2_uri_value;
-
-/*****************************************************************************/
-
-static void
-init_uris(void)
-{
- plugin_uri_value = lilv_new_uri(world, uris_plugin);
- plugin2_uri_value = lilv_new_uri(world, "http://example.org/foobar");
- TEST_ASSERT(plugin_uri_value);
- TEST_ASSERT(plugin2_uri_value);
-}
-
-static void
-cleanup_uris(void)
-{
- lilv_node_free(plugin2_uri_value);
- lilv_node_free(plugin_uri_value);
- plugin2_uri_value = NULL;
- plugin_uri_value = NULL;
-}
-
-/*****************************************************************************/
-
static int
-test_value(void)
+test_value(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:port [ "
" a lv2:ControlPort ; a lv2:InputPort ; "
" lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
"] .")) {
- return 0;
+ return 1;
}
- init_uris();
-
LilvNode* uval = lilv_new_uri(world, "http://example.org");
LilvNode* sval = lilv_new_string(world, "Foo");
LilvNode* ival = lilv_new_int(world, 42);
@@ -400,14 +214,14 @@ test_value(void)
lilv_node_free(uval_dup);
lilv_node_free(nil2);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_util(void)
+test_util(LilvTestEnv* env)
{
TEST_ASSERT(!lilv_realpath(NULL));
@@ -434,7 +248,7 @@ test_util(void)
TEST_ASSERT(!lilv_file_equals("does/not/exist", b_path));
TEST_ASSERT(!lilv_file_equals(a_path, "does/not/exist"));
TEST_ASSERT(!lilv_file_equals("does/not/exist", "/does/not/either"));
- return 1;
+ return 0;
}
/*****************************************************************************/
@@ -442,12 +256,12 @@ test_util(void)
static int discovery_plugin_found = 0;
static void
-discovery_verify_plugin(const LilvPlugin* plugin)
+discovery_verify_plugin(const LilvTestEnv* env, const LilvPlugin* plugin)
{
const LilvNode* value = lilv_plugin_get_uri(plugin);
- if (lilv_node_equals(value, plugin_uri_value)) {
+ if (lilv_node_equals(value, env->plugin1_uri)) {
const LilvNode* lib_uri = NULL;
- TEST_ASSERT(!lilv_node_equals(value, plugin2_uri_value));
+ TEST_ASSERT(!lilv_node_equals(value, env->plugin2_uri));
discovery_plugin_found = 1;
lib_uri = lilv_plugin_get_library_uri(plugin);
TEST_ASSERT(lib_uri);
@@ -459,27 +273,26 @@ discovery_verify_plugin(const LilvPlugin* plugin)
}
static int
-test_discovery(void)
+test_discovery(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ;"
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
" lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; ] .")) {
- return 0;
+ return 1;
}
- init_uris();
-
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
TEST_ASSERT(lilv_plugins_size(plugins) > 0);
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(explug != NULL);
- const LilvPlugin* explug2 = lilv_plugins_get_by_uri(plugins, plugin2_uri_value);
+ const LilvPlugin* explug2 = lilv_plugins_get_by_uri(plugins, env->plugin2_uri);
TEST_ASSERT(explug2 == NULL);
if (explug) {
@@ -490,81 +303,82 @@ test_discovery(void)
discovery_plugin_found = 0;
LILV_FOREACH(plugins, i, plugins)
- discovery_verify_plugin(lilv_plugins_get(plugins, i));
+ discovery_verify_plugin(env, lilv_plugins_get(plugins, i));
TEST_ASSERT(discovery_plugin_found);
plugins = NULL;
- cleanup_uris();
-
- return 1;
+ return 0;
}
/*****************************************************************************/
static int
-test_verify(void)
+test_verify(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
" lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ] .")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(explug);
TEST_ASSERT(lilv_plugin_verify(explug));
- cleanup_uris();
- return 1;
+
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_no_verify(void)
+test_no_verify(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin . ")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(explug);
TEST_ASSERT(!lilv_plugin_verify(explug));
- cleanup_uris();
- return 1;
+
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_classes(void)
+test_classes(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:port [ "
" a lv2:ControlPort ; a lv2:InputPort ; "
" lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
"] .")) {
- return 0;
+ return 1;
}
- init_uris();
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);
@@ -589,21 +403,22 @@ test_classes(void)
lilv_plugin_class_free(NULL);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_plugin(void)
+test_plugin(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:optionalFeature lv2:hardRTCapable ; "
"lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
"lv2:extensionData <http://example.org/extdata> ;"
@@ -628,12 +443,11 @@ test_plugin(void)
" lv2:designation lv2:latency "
"] . \n"
":thing doap:name \"Something else\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
const LilvPluginClass* klass = lilv_plugin_get_class(plug);
@@ -653,7 +467,7 @@ test_plugin(void)
TEST_ASSERT(!lilv_plugin_get_related(plug, NULL));
const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
- TEST_ASSERT(!strcmp(lilv_node_as_string(plug_bundle_uri), test_bundle_uri));
+ TEST_ASSERT(!strcmp(lilv_node_as_string(plug_bundle_uri), env->test_bundle_uri));
const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
TEST_ASSERT(lilv_nodes_size(data_uris) == 2);
@@ -827,21 +641,23 @@ test_plugin(void)
lilv_node_free(audio_class);
lilv_node_free(in_class);
lilv_node_free(out_class);
- cleanup_uris();
- return 1;
+
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_project(void)
+test_project(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin with project") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin with project\" ;"
"lv2:project [ "
" doap:maintainer [ "
" foaf:name \"David Robillard\" ; "
@@ -862,12 +678,11 @@ test_project(void)
" lv2:designation lv2:latency "
"] . \n"
":thing doap:name \"Something else\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvNode* author_name = lilv_plugin_get_author_name(plug);
@@ -882,21 +697,22 @@ test_project(void)
TEST_ASSERT(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
lilv_node_free(author_homepage);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_no_author(void)
+test_no_author(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin with project") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin with project\" ;"
"lv2:port [ "
" a lv2:ControlPort ; a lv2:InputPort ; "
" lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
@@ -912,12 +728,12 @@ test_no_author(void)
" lv2:designation lv2:latency "
"] . \n"
":thing doap:name \"Something else\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
+
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvNode* author_name = lilv_plugin_get_author_name(plug);
@@ -929,21 +745,22 @@ test_no_author(void)
LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
TEST_ASSERT(!author_homepage);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_project_no_author(void)
+test_project_no_author(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin with project") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin with project\" ;"
"lv2:project [ "
" doap:name \"Fake project\" ;"
"] ; "
@@ -962,12 +779,11 @@ test_project_no_author(void)
" lv2:designation lv2:latency "
"] . \n"
":thing doap:name \"Something else\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvNode* author_name = lilv_plugin_get_author_name(plug);
@@ -979,21 +795,22 @@ test_project_no_author(void)
LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
TEST_ASSERT(!author_homepage);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_preset(void)
+test_preset(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin with project") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin with project\" ;"
"lv2:project [ "
" doap:name \"Fake project\" ;"
"] ; "
@@ -1014,12 +831,11 @@ test_preset(void)
"<http://example.org/preset> a pset:Preset ;"
" lv2:appliesTo :plug ;"
" rdfs:label \"some preset\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
@@ -1029,21 +845,23 @@ test_preset(void)
lilv_node_free(pset_Preset);
lilv_nodes_free(related);
- cleanup_uris();
- return 1;
+
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_prototype(void)
+test_prototype(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":prot a lv2:PluginBase ; rdfs:seeAlso <plugin.ttl> .\n"
":plug a lv2:Plugin ; lv2:binary <inst" SHLIB_EXT "> ; lv2:prototype :prot .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":prot a lv2:Plugin ; a lv2:CompressorPlugin ; "
- LICENSE_GPL " ; "
"lv2:project [ "
" doap:name \"Fake project\" ;"
"] ; "
@@ -1062,12 +880,11 @@ test_prototype(void)
" lv2:designation lv2:latency "
"] . \n"
":plug doap:name \"Instance\" .\n")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
// Test non-inherited property
@@ -1079,21 +896,23 @@ test_prototype(void)
const LilvNode* binary = lilv_plugin_get_library_uri(plug);
TEST_ASSERT(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_port(void)
+test_port(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES PREFIX_LV2EV
+ PLUGIN_PREFIXES
+ "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n"
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"doap:homepage <http://example.org/someplug> ; "
"lv2:port [ "
" a lv2:ControlPort ; a lv2:InputPort ; "
@@ -1121,12 +940,11 @@ test_port(void)
" lv2:index 3 ; lv2:symbol \"audio_out\" ; "
" lv2:name \"Audio Output\" ; "
"] .")) {
- return 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvNode* psym = lilv_new_string(world, "foo");
@@ -1357,8 +1175,9 @@ test_port(void)
lilv_node_free(audio_class);
lilv_node_free(out_class);
lilv_node_free(in_class);
- cleanup_uris();
- return 1;
+
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
@@ -1371,14 +1190,16 @@ ui_supported(const char* container_type_uri,
}
static int
-test_ui(void)
+test_ui(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES PREFIX_LV2UI
+ PLUGIN_PREFIXES
+ "@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n"
":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:optionalFeature lv2:hardRTCapable ; "
"lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
"lv2ui:ui :ui , :ui2 , :ui3 , :ui4 ; "
@@ -1404,12 +1225,11 @@ test_ui(void)
":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 0;
+ return 1;
}
- init_uris();
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
LilvUIs* uis = lilv_plugin_get_uis(plug);
@@ -1476,8 +1296,8 @@ test_ui(void)
lilv_node_free(expected_uri);
lilv_uis_free(uis);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
@@ -1579,9 +1399,9 @@ lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
}
static int
-test_state(void)
+test_state(LilvTestEnv* env)
{
- init_world();
+ 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);
@@ -1794,9 +1614,10 @@ test_state(void)
// Test instantiating twice
LilvInstance* instance2 = lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
if (!instance2) {
- fatal_error("Failed to create multiple instances of <%s>\n",
- lilv_node_as_uri(state_plugin_uri));
- return 0;
+ fprintf(stderr,
+ "Failed to create multiple instances of <%s>\n",
+ lilv_node_as_uri(state_plugin_uri));
+ return 1;
}
lilv_instance_free(instance2);
@@ -1940,79 +1761,76 @@ test_state(void)
free(copy_dir);
free(temp_dir);
- cleanup_uris();
- return 1;
+ return 0;
}
#endif
/*****************************************************************************/
static int
-test_bad_port_symbol(void)
+test_bad_port_symbol(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES PREFIX_LV2EV
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "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 0;
+ return 1;
}
- init_uris();
-
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
uint32_t n_ports = lilv_plugin_get_num_ports(plug);
TEST_ASSERT(n_ports == 0);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_bad_port_index(void)
+test_bad_port_index(LilvTestEnv* env)
{
- if (!start_bundle(MANIFEST_PREFIXES
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES PREFIX_LV2EV
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Test plugin") " ; "
- LICENSE_GPL " ; "
+ "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 0;
+ return 1;
}
- init_uris();
-
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
uint32_t n_ports = lilv_plugin_get_num_ports(plug);
TEST_ASSERT(n_ports == 0);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
static int
-test_string(void)
+test_string(LilvTestEnv* env)
{
char* s = NULL;
@@ -2047,20 +1865,18 @@ test_string(void)
unsetenv("LILV_TEST_1");
#endif
- return 1;
+ return 0;
}
/*****************************************************************************/
static int
-test_world(void)
+test_world(LilvTestEnv* env)
{
- if (!init_world()) {
- return 0;
- }
+ LilvWorld* const world = env->world;
- LilvNode* num = lilv_new_int(world, 4);
- LilvNode* uri = lilv_new_uri(world, "http://example.org/object");
+ 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);
TEST_ASSERT(!matches);
@@ -2076,35 +1892,32 @@ test_world(void)
lilv_world_unload_bundle(world, NULL);
- return 1;
+ return 0;
}
/*****************************************************************************/
static int
-test_reload_bundle(void)
+test_reload_bundle(LilvTestEnv* env)
{
+ LilvWorld* const world = env->world;
+
// Create a simple plugin bundle
- create_bundle(MANIFEST_PREFIXES
+ create_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("First name") " .");
+ "doap:name \"First name\" .");
- if (!init_world()) {
- return 0;
- }
-
- init_uris();
lilv_world_load_specifications(world);
// Load bundle
- LilvNode* bundle_uri = lilv_new_uri(world, test_bundle_uri);
+ 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, plugin_uri_value);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug);
// Check that plugin name is correct
@@ -2114,14 +1927,14 @@ test_reload_bundle(void)
// Unload bundle from world and delete it
lilv_world_unload_bundle(world, bundle_uri);
- delete_bundle();
+ delete_bundle(env);
// Create a new version of the same bundle, but with a different name
- create_bundle(MANIFEST_PREFIXES
+ create_bundle(env, MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Second name") " .");
+ "doap:name \"Second name\" .");
// Check that plugin is no longer in the world's plugin list
TEST_ASSERT(lilv_plugins_size(plugins) == 0);
@@ -2130,7 +1943,7 @@ test_reload_bundle(void)
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, plugin_uri_value);
+ const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
TEST_ASSERT(plug2);
TEST_ASSERT(plug2 == plug);
@@ -2143,22 +1956,18 @@ test_reload_bundle(void)
// Load new bundle again (noop)
lilv_world_load_bundle(world, bundle_uri);
- cleanup_uris();
lilv_node_free(bundle_uri);
- lilv_world_free(world);
- world = NULL;
+ delete_bundle(env);
- return 1;
+ return 0;
}
/*****************************************************************************/
static int
-test_replace_version(void)
+test_replace_version(LilvTestEnv* env)
{
- if (!init_world()) {
- return 0;
- }
+ 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);
@@ -2225,27 +2034,27 @@ test_replace_version(void)
lilv_node_free(plug_uri);
lilv_node_free(lv2_minorVersion);
lilv_node_free(lv2_microVersion);
- return 1;
+ return 0;
}
/*****************************************************************************/
static int
-test_get_symbol(void)
+test_get_symbol(LilvTestEnv* env)
{
- if (!start_bundle(
+ LilvWorld* const world = env->world;
+
+ if (start_bundle(env,
MANIFEST_PREFIXES
":plug a lv2:Plugin ; lv2:symbol \"plugsym\" ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
- BUNDLE_PREFIXES PREFIX_LV2EV
+ PLUGIN_PREFIXES
":plug a lv2:Plugin ; "
- PLUGIN_NAME("Test plugin") " ; "
+ "doap:name \"Test plugin\" ;"
"lv2:symbol \"plugsym\" .")) {
- return 0;
+ return 1;
}
- init_uris();
-
- LilvNode* plug_sym = lilv_world_get_symbol(world, plugin_uri_value);
+ 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");
@@ -2273,9 +2082,9 @@ test_get_symbol(void)
lilv_node_free(path_sym);
lilv_node_free(path);
lilv_node_free(plug_sym);
- cleanup_uris();
- return 1;
+ delete_bundle(env);
+ return 0;
}
/*****************************************************************************/
@@ -2311,34 +2120,41 @@ static struct TestCase tests[] = {
{ NULL, NULL }
};
-static void
+static unsigned
run_tests(void)
{
- int i;
- for (i = 0; tests[i].title; i++) {
+ unsigned n_failures = 0;
+
+ for (int i = 0; tests[i].title; ++i) {
printf("*** Test %s\n", tests[i].title);
- if (!tests[i].func()) {
- printf("\nTest failed\n");
- /* test case that wasn't able to be executed at all counts as 1 test + 1 error */
- error_count++;
- test_count++;
+ LilvTestEnv* env = lilv_test_env_new();
+ if (tests[i].func(env)) {
+ fprintf(stderr, "\nTest %s failed\n", tests[i].title);
+ ++n_failures;
}
- unload_bundle();
- cleanup();
+ lilv_test_env_free(env);
}
+
+ return n_failures;
}
int
main(int argc, char* argv[])
{
if (argc != 1) {
- printf("Syntax: %s\n", argv[0]);
- return 0;
+ printf("Usage: %s\n", argv[0]);
+ return 1;
}
+
set_env("LANG", "C");
- init_tests();
- run_tests();
- cleanup();
- printf("\n*** Test Results: %d tests, %d errors\n\n", test_count, error_count);
- return error_count ? 1 : 0;
+
+ 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.c b/test/lilv_test_utils.c
new file mode 100644
index 0000000..6137c27
--- /dev/null
+++ b/test/lilv_test_utils.c
@@ -0,0 +1,184 @@
+/*
+ Copyright 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 */
+
+#include "lilv_test_utils.h"
+
+#include "../src/lilv_internal.h"
+
+#include "lilv/lilv.h"
+
+#ifdef _WIN32
+# include <direct.h>
+# include <io.h>
+# define mkdir(path, flags) _mkdir(path)
+#else
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+LilvTestEnv*
+lilv_test_env_new(void)
+{
+ LilvWorld* world = lilv_world_new();
+ if (!world) {
+ return NULL;
+ }
+
+ LilvTestEnv* env = (LilvTestEnv*)calloc(1, sizeof(LilvTestEnv));
+
+ env->world = world;
+ env->plugin1_uri = lilv_new_uri(world, "http://example.org/plug");
+ env->plugin2_uri = lilv_new_uri(world, "http://example.org/foobar");
+
+ // Set custom LV2_PATH in build directory to only use test data
+ char* test_path = lilv_realpath(LILV_TEST_DIR);
+ char* lv2_path = lilv_strjoin(test_path, "/test_lv2_path", NULL);
+ LilvNode* path = lilv_new_string(world, lv2_path);
+ lilv_world_set_option(world, LILV_OPTION_LV2_PATH, path);
+ free(lv2_path);
+ free(test_path);
+ lilv_node_free(path);
+
+ return env;
+}
+
+void
+lilv_test_env_free(LilvTestEnv* env)
+{
+ free(env->test_content_path);
+ free(env->test_manifest_path);
+ free(env->test_bundle_uri);
+ free(env->test_bundle_path);
+ lilv_node_free(env->plugin2_uri);
+ lilv_node_free(env->plugin1_uri);
+ lilv_world_free(env->world);
+ free(env);
+}
+
+int
+create_bundle(LilvTestEnv* env, const char* manifest, const char* plugin)
+{
+ {
+ static const char* const bundle_path = "/test_lv2_path/lilv-test.lv2";
+
+ char* const test_path = lilv_realpath(LILV_TEST_DIR);
+ env->test_bundle_path = lilv_strjoin(test_path, bundle_path, NULL);
+ lilv_free(test_path);
+ }
+
+ if (lilv_mkdir_p(env->test_bundle_path)) {
+ fprintf(stderr,
+ "Failed to create directory '%s' (%s)\n",
+ env->test_bundle_path,
+ strerror(errno));
+ return 1;
+ }
+
+ SerdNode s = serd_node_new_file_uri((const uint8_t*)env->test_bundle_path,
+ NULL,
+ NULL,
+ true);
+
+ env->test_bundle_uri = lilv_strjoin((const char*)s.buf, "/", NULL);
+ env->test_manifest_path =
+ lilv_strjoin(env->test_bundle_path, "/manifest.ttl", NULL);
+ env->test_content_path =
+ lilv_strjoin(env->test_bundle_path, "/plugin.ttl", NULL);
+
+ serd_node_free(&s);
+
+ FILE* const manifest_file = fopen(env->test_manifest_path, "w");
+ if (!manifest_file) {
+ return 2;
+ }
+
+ FILE* const plugin_file = fopen(env->test_content_path, "w");
+ if (!plugin_file) {
+ fclose(manifest_file);
+ return 3;
+ }
+
+ const size_t manifest_len = strlen(manifest);
+ const size_t plugin_len = strlen(plugin);
+ size_t n_written = 0;
+
+ n_written += fwrite(manifest, 1, manifest_len, manifest_file);
+ n_written += fwrite(plugin, 1, plugin_len, plugin_file);
+
+ fclose(manifest_file);
+ fclose(plugin_file);
+
+ return n_written == manifest_len + plugin_len ? 0 : 4;
+}
+
+int
+start_bundle(LilvTestEnv* env, const char* manifest, const char* content)
+{
+ if (create_bundle(env, manifest, content)) {
+ return 1;
+ }
+
+ lilv_world_load_all(env->world);
+ return 0;
+}
+
+void
+delete_bundle(LilvTestEnv* env)
+{
+ if (env->test_content_path) {
+ unlink(env->test_content_path);
+ }
+
+ if (env->test_manifest_path) {
+ unlink(env->test_manifest_path);
+ }
+
+ if (env->test_bundle_path) {
+ remove(env->test_bundle_path);
+ }
+
+ free(env->test_content_path);
+ free(env->test_manifest_path);
+ free(env->test_bundle_uri);
+ free(env->test_bundle_path);
+
+ env->test_content_path = NULL;
+ env->test_manifest_path = NULL;
+ env->test_bundle_uri = NULL;
+ env->test_bundle_path = NULL;
+}
+
+void
+set_env(const char* name, const char* value)
+{
+#ifdef _WIN32
+ // setenv on Windows does not modify the current process' environment
+ const size_t len = strlen(name) + 1 + strlen(value) + 1;
+ char* str = (char*)calloc(1, len);
+ snprintf(str, len, "%s=%s", name, value);
+ putenv(str);
+ free(str);
+#else
+ setenv(name, value, 1);
+#endif
+}
diff --git a/test/lilv_test_utils.h b/test/lilv_test_utils.h
new file mode 100644
index 0000000..88e1fcd
--- /dev/null
+++ b/test/lilv_test_utils.h
@@ -0,0 +1,71 @@
+/*
+ Copyright 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.
+*/
+
+#include "lilv/lilv.h"
+
+#define MANIFEST_PREFIXES \
+ "\
+@prefix : <http://example.org/> .\n\
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
+
+#define PLUGIN_PREFIXES \
+ "\
+@prefix : <http://example.org/> .\n\
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> . \n\
+@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
+@prefix pset: <http://lv2plug.in/ns/ext/presets#> .\n\
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
+
+typedef struct
+{
+ LilvWorld* world;
+ LilvNode* plugin1_uri;
+ LilvNode* plugin2_uri;
+ char* test_bundle_path;
+ char* test_bundle_uri;
+ char* test_manifest_path;
+ char* test_content_path;
+ int test_count;
+ int error_count;
+} LilvTestEnv;
+
+// Create a new test environment with a world, common values, and test LV2_PATH
+LilvTestEnv*
+lilv_test_env_new(void);
+
+// Free environment created with lilv_test_env_new()
+void
+lilv_test_env_free(LilvTestEnv* env);
+
+// Create a bundle with a manifest and plugin files, without loading anything
+int
+create_bundle(LilvTestEnv* env, const char* manifest, const char* plugin);
+
+// Create a bundle with a manifest and plugin files, then load everything
+int
+start_bundle(LilvTestEnv* env, const char* manifest, const char* plugin);
+
+// Remove the created bundle from the file system and free its paths in `env`
+void
+delete_bundle(LilvTestEnv* env);
+
+// Set an environment variable so it is immediately visible in this process
+void
+set_env(const char* name, const char* value);