diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lilv_test.c | 154 | ||||
-rw-r--r-- | test/manifest.ttl | 7 | ||||
-rw-r--r-- | test/test_plugin.c | 235 | ||||
-rw-r--r-- | test/test_plugin.ttl | 40 |
4 files changed, 436 insertions, 0 deletions
diff --git a/test/lilv_test.c b/test/lilv_test.c index b5c5302..1994832 100644 --- a/test/lilv_test.c +++ b/test/lilv_test.c @@ -28,6 +28,9 @@ #include <math.h> #include "lilv/lilv.h" +#include "../src/lilv_internal.h" + +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" #define TEST_PATH_MAX 1024 @@ -972,6 +975,156 @@ test_ui(void) /*****************************************************************************/ +float in = 1.0; +float out = 42.0; + +LilvNode* +get_port_value(const char* port_symbol, void* user_data) +{ + if (!strcmp(port_symbol, "input")) { + return lilv_new_float((LilvWorld*)user_data, in); + } else if (!strcmp(port_symbol, "output")) { + return lilv_new_float((LilvWorld*)user_data, out); + } else { + fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n", + port_symbol); + return NULL; + } +} + +void +set_port_value(const char* port_symbol, + const LilvNode* value, + void* user_data) +{ + if (!strcmp(port_symbol, "input")) { + in = lilv_node_as_float(value); + } else if (!strcmp(port_symbol, "output")) { + out = lilv_node_as_float(value); + } else { + fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n", + port_symbol); + } +} + +char** uris = NULL; +size_t n_uris = 0; + +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; + } + } + + uris = realloc(uris, ++n_uris * sizeof(char*)); + uris[n_uris - 1] = lilv_strdup(uri); + return n_uris; +} + +const char* +unmap_uri(LV2_URID_Map_Handle handle, + LV2_URID urid) +{ + if (urid > 0 && urid <= n_uris) { + return uris[urid - 1]; + } + return NULL; +} + +int +test_state(void) +{ + LilvWorld* world = lilv_world_new(); + LilvNode* bundle_uri = lilv_new_uri(world, LILV_TEST_BUNDLE); + LilvNode* plugin_uri = lilv_new_uri(world, + "http://example.org/lilv-test-plugin"); + lilv_world_load_bundle(world, bundle_uri); + + const LilvPlugins* plugins = lilv_world_get_all_plugins(world); + const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri); + TEST_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 }; + + LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, features); + TEST_ASSERT(instance); + + lilv_instance_connect_port(instance, 0, &in); + lilv_instance_connect_port(instance, 1, &out); + + lilv_instance_run(instance, 1); + TEST_ASSERT(in == 1.0); + TEST_ASSERT(out == 1.0); + + // Get instance state state + LilvState* state = lilv_state_new_from_instance( + plugin, instance, get_port_value, world, 0, NULL); + + // Get another instance state + LilvState* state2 = lilv_state_new_from_instance( + plugin, instance, get_port_value, world, 0, NULL); + + // Ensure they are equal + TEST_ASSERT(lilv_state_equals(state, state2)); + + const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(state); + TEST_ASSERT(lilv_node_equals(state_plugin_uri, plugin_uri)); + + // Tinker with the label of the first state + TEST_ASSERT(lilv_state_get_label(state) == NULL); + lilv_state_set_label(state, "Test State Old Label"); + TEST_ASSERT(!strcmp(lilv_state_get_label(state), "Test State Old Label")); + lilv_state_set_label(state, "Test State"); + TEST_ASSERT(!strcmp(lilv_state_get_label(state), "Test State")); + + TEST_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, get_port_value, world, 0, NULL); + TEST_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, get_port_value, world, 0, NULL); + TEST_ASSERT(lilv_state_equals(state2, state4)); + + // Save state to a file + int ret = lilv_state_save(world, &unmap, state, NULL, + "state.ttl", "manifest.ttl"); + TEST_ASSERT(!ret); + + // Load state from file + LilvState* state5 = lilv_state_new_from_file(world, &map, NULL, "state.ttl"); + TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy + + lilv_state_free(state); + lilv_state_free(state2); + lilv_state_free(state3); + lilv_state_free(state4); + lilv_state_free(state5); + + lilv_instance_free(instance); + + lilv_node_free(bundle_uri); + lilv_world_free(world); + return 1; +} + +/*****************************************************************************/ + /* add tests here */ static struct TestCase tests[] = { TEST_CASE(utils), @@ -983,6 +1136,7 @@ static struct TestCase tests[] = { TEST_CASE(plugin), TEST_CASE(port), TEST_CASE(ui), + TEST_CASE(state), { NULL, NULL } }; diff --git a/test/manifest.ttl b/test/manifest.ttl new file mode 100644 index 0000000..5af7e88 --- /dev/null +++ b/test/manifest.ttl @@ -0,0 +1,7 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://example.org/lilv-test-plugin> + a lv2:Plugin ; + lv2:binary <test_plugin.so> ; + rdfs:seeAlso <test_plugin.ttl> . diff --git a/test/test_plugin.c b/test/test_plugin.c new file mode 100644 index 0000000..0ef76f2 --- /dev/null +++ b/test/test_plugin.c @@ -0,0 +1,235 @@ +/* + Lilv Test Plugin + Copyright 2011 David Robillard <d@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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lv2/lv2plug.in/ns/ext/state/state.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" + +#define TEST_URI "http://example.org/lilv-test-plugin" + +#define NS_ATOM "http://lv2plug.in/ns/ext/atom#" + +enum { + TEST_INPUT = 0, + TEST_OUTPUT = 1 +}; + +typedef struct { + LV2_URID_Map* map; + + struct { + LV2_URID atom_Float; + } uris; + + float* input; + float* output; + unsigned num_runs; +} Test; + +static void +cleanup(LV2_Handle instance) +{ + free(instance); +} + +static void +connect_port(LV2_Handle instance, + uint32_t port, + void* data) +{ + Test* test = (Test*)instance; + switch (port) { + case TEST_INPUT: + test->input = (float*)data; + break; + case TEST_OUTPUT: + test->output = (float*)data; + break; + default: + break; + } +} + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, + double rate, + const char* path, + const LV2_Feature* const* features) +{ + Test* test = (Test*)malloc(sizeof(Test)); + if (!test) { + return NULL; + } + + test->map = NULL; + test->input = NULL; + test->output = NULL; + test->num_runs = 0; + + /* Scan host features for URID map */ + for (int i = 0; features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) { + test->map = (LV2_URID_Map*)features[i]->data; + test->uris.atom_Float = test->map->map( + test->map->handle, NS_ATOM "Float"); + } + } + + if (!test->map) { + fprintf(stderr, "Host does not support urid:map.\n"); + free(test); + return NULL; + } + + return (LV2_Handle)test; +} + +static void +run(LV2_Handle instance, + uint32_t sample_count) +{ + Test* test = (Test*)instance; + *test->output = *test->input; + ++test->num_runs; +} + +static uint32_t +map_uri(Test* plugin, const char* uri) +{ + return plugin->map->map(plugin->map->handle, uri); +} + +static void +save(LV2_Handle instance, + LV2_State_Store_Function store, + void* callback_data, + uint32_t flags, + const LV2_Feature* const* features) +{ + Test* plugin = (Test*)instance; + + store(callback_data, + map_uri(plugin, "http://example.org/greeting"), + "hello", + strlen("hello") + 1, + map_uri(plugin, NS_ATOM "String"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + const uint32_t urid = map_uri(plugin, "http://example.org/urivalue"); + store(callback_data, + map_uri(plugin, "http://example.org/uri"), + &urid, + sizeof(uint32_t), + map_uri(plugin, NS_ATOM "URID"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + store(callback_data, + map_uri(plugin, "http://example.org/num-runs"), + &plugin->num_runs, + sizeof(plugin->num_runs), + map_uri(plugin, NS_ATOM "Int32"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + const float two = 2.0f; + store(callback_data, + map_uri(plugin, "http://example.org/two"), + &two, + sizeof(two), + map_uri(plugin, NS_ATOM "Float"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + const uint32_t affirmative = 1; + store(callback_data, + map_uri(plugin, "http://example.org/true"), + &affirmative, + sizeof(affirmative), + map_uri(plugin, NS_ATOM "Bool"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + const uint32_t negative = 0; + store(callback_data, + map_uri(plugin, "http://example.org/false"), + &negative, + sizeof(negative), + map_uri(plugin, NS_ATOM "Bool"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + const uint8_t blob[] = "This is a bunch of data that happens to be text" + " but could really be anything at all, lest you feel like cramming" + " all sorts of ridiculous binary stuff in Turtle"; + store(callback_data, + map_uri(plugin, "http://example.org/blob"), + blob, + sizeof(blob), + map_uri(plugin, "http://example.org/SomeUnknownType"), + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); +} + +static void +restore(LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + void* callback_data, + uint32_t flags, + const LV2_Feature* const* features) +{ + Test* plugin = (Test*)instance; + + size_t size; + uint32_t type; + uint32_t valflags; + + plugin->num_runs = *(int32_t*)retrieve( + callback_data, + map_uri(plugin, "http://example.org/num-runs"), + &size, &type, &valflags); +} + +const void* +extension_data(const char* uri) +{ + static const LV2_State_Interface state = { save, restore }; + if (!strcmp(uri, LV2_STATE_INTERFACE_URI)) { + return &state; + } + return NULL; +} + +static const LV2_Descriptor descriptor = { + TEST_URI, + instantiate, + connect_port, + NULL, // activate, + run, + NULL, // deactivate, + cleanup, + extension_data +}; + +LV2_SYMBOL_EXPORT +const LV2_Descriptor* lv2_descriptor(uint32_t index) +{ + switch (index) { + case 0: + return &descriptor; + default: + return NULL; + } +} diff --git a/test/test_plugin.ttl b/test/test_plugin.ttl new file mode 100644 index 0000000..ec16d00 --- /dev/null +++ b/test/test_plugin.ttl @@ -0,0 +1,40 @@ +# Lilv Test Plugin +# Copyright 2011 David Robillard <d@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. + +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . + +<http://example.org/lilv-test-plugin> + a lv2:Plugin ; + doap:name "Lilv Test" ; + doap:license <http://opensource.org/licenses/isc> ; + lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#Mapper> ; + lv2:optionalFeature lv2:hardRtCapable ; + lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ; + lv2:port [ + a lv2:InputPort , + lv2:ControlPort ; + lv2:index 0 ; + lv2:symbol "input" ; + lv2:name "Input" + ] , [ + a lv2:OutputPort , + lv2:ControlPort ; + lv2:index 1 ; + lv2:symbol "output" ; + lv2:name "Output" + ] . |