From a79fe5a88d0ef9f440fd6b8330a82fb67839fabd Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Jan 2012 03:13:15 +0000 Subject: Add file support to state implementation. Use cleaner and more consistent names for world URIs. git-svn-id: http://svn.drobilla.net/lad/trunk/lilv@3918 a436a847-0d15-0410-975c-d299462d15a1 --- test/lilv_test.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++------ test/test_plugin.c | 115 +++++++++++++++++++++++++++++++++++--- 2 files changed, 251 insertions(+), 23 deletions(-) (limited to 'test') diff --git a/test/lilv_test.c b/test/lilv_test.c index 44596f0..0591d20 100644 --- a/test/lilv_test.c +++ b/test/lilv_test.c @@ -30,6 +30,7 @@ #include "lilv/lilv.h" #include "../src/lilv_internal.h" +#include "lv2/lv2plug.in/ns/ext/state/state.h" #include "lv2/lv2plug.in/ns/ext/urid/urid.h" #define TEST_PATH_MAX 1024 @@ -1074,6 +1075,15 @@ unmap_uri(LV2_URID_Map_Handle handle, return NULL; } +static const char* file_dir = "files"; + +char* +lilv_make_path(LV2_State_Make_Path_Handle handle, + const char* path) +{ + return lilv_strjoin(file_dir, "/", path, NULL); +} + int test_state(void) { @@ -1093,23 +1103,28 @@ test_state(void) LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap }; const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL }; + LilvNode* num = lilv_new_int(world, 5); + LilvState* nostate = lilv_state_new_from_file(world, &map, num, "/junk"); + TEST_ASSERT(!nostate); + LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, features); TEST_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); TEST_ASSERT(in == 1.0); TEST_ASSERT(out == 1.0); + const char* tmpdir = NULL; + // Get instance state state LilvState* state = lilv_state_new_from_instance( - plugin, instance, get_port_value, world, 0, NULL); + plugin, instance, &map, tmpdir, 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); + plugin, instance, &map, tmpdir, get_port_value, world, 0, NULL); // Ensure they are equal TEST_ASSERT(lilv_state_equals(state, state2)); @@ -1129,7 +1144,7 @@ test_state(void) // 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); + plugin, instance, &map, tmpdir, get_port_value, world, 0, NULL); TEST_ASSERT(!lilv_state_equals(state2, state3)); // num_runs changed // Restore instance state to original state @@ -1137,22 +1152,23 @@ test_state(void) // 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); + plugin, instance, &map, tmpdir, get_port_value, world, 0, NULL); TEST_ASSERT(lilv_state_equals(state2, state4)); - // Save state to a file + // Save state to a directory int ret = lilv_state_save(world, &unmap, state, NULL, - "state.ttl", "manifest.ttl"); + "./state.lv2", "state", NULL); TEST_ASSERT(!ret); - // Load state from file - LilvState* state5 = lilv_state_new_from_file(world, &map, NULL, "state.ttl"); + // Load state from directory + LilvState* state5 = lilv_state_new_from_file(world, &map, NULL, + "./state.lv2/state.ttl"); TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy // Save state to default bundle setenv("LV2_STATE_BUNDLE", "lv2/lilv-test-state.lv2", 1); const char* state_uri = "http://example.org/test-state"; - ret = lilv_state_save(world, &unmap, state, state_uri, NULL, NULL); + ret = lilv_state_save(world, &unmap, state, state_uri, NULL, NULL, NULL); TEST_ASSERT(!ret); // Load default bundle into world and load state from it @@ -1166,9 +1182,92 @@ test_state(void) unsetenv("LV2_STATE_BUNDLE"); - LilvNode* num = lilv_new_int(world, 5); - LilvState* nostate = lilv_state_new_from_file(world, &map, num, "/junk"); - TEST_ASSERT(!nostate); + // Make a temporary directory and test files support + tmpdir = file_dir; + mkdir(tmpdir, 0700); + + LV2_State_Make_Path make_path = { NULL, lilv_make_path }; + LV2_Feature make_path_feature = { LV2_STATE_MAKE_PATH_URI, &make_path }; + const LV2_Feature* ffeatures[] = { &make_path_feature, &map_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); + + // Get instance state state + LilvState* fstate = lilv_state_new_from_instance( + plugin, instance, &map, tmpdir, get_port_value, world, 0, ffeatures); + + // Get another instance state + LilvState* fstate2 = lilv_state_new_from_instance( + plugin, instance, &map, tmpdir, get_port_value, world, 0, ffeatures); + + // Should be identical + TEST_ASSERT(lilv_state_equals(fstate, 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, tmpdir, get_port_value, world, 0, ffeatures); + + // Should be different + TEST_ASSERT(!lilv_state_equals(fstate, fstate3)); + + // Save state to a directory + ret = lilv_state_save(world, &unmap, fstate, NULL, + "./fstate.lv2", "fstate", ffeatures); + TEST_ASSERT(!ret); + + // Load state from directory + LilvState* fstate4 = lilv_state_new_from_file(world, &map, NULL, + "./fstate.lv2/fstate.ttl"); + TEST_ASSERT(lilv_state_equals(fstate, fstate4)); // Round trip accuracy + + // Restore instance state to loaded state + lilv_state_restore(fstate, 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, tmpdir, get_port_value, world, 0, ffeatures); + TEST_ASSERT(lilv_state_equals(fstate3, fstate5)); + + // Save state to a directory again + ret = lilv_state_save(world, &unmap, fstate, NULL, + "./fstate6.lv2", "fstate6", ffeatures); + TEST_ASSERT(!ret); + + // Reload it and ensure it's identical to the other loaded version + LilvState* fstate6 = lilv_state_new_from_file(world, &map, NULL, + "./fstate6.lv2/fstate6.ttl"); + TEST_ASSERT(lilv_state_equals(fstate4, fstate6)); + + // Run, writing more to rec file + lilv_instance_run(instance, 2); + + // Take a new snapshot + LilvState* fstate7 = lilv_state_new_from_instance( + plugin, instance, &map, tmpdir, get_port_value, world, 0, ffeatures); + TEST_ASSERT(lilv_state_equals(fstate3, fstate5)); + + // Save the changed state to a directory again + ret = lilv_state_save(world, &unmap, fstate7, NULL, + "./fstate7.lv2", "fstate7", ffeatures); + TEST_ASSERT(!ret); + + // Reload it and ensure it's changed + LilvState* fstate72 = lilv_state_new_from_file(world, &map, NULL, + "./fstate7.lv2/fstate7.ttl"); + TEST_ASSERT(lilv_state_equals(fstate72, fstate7)); + TEST_ASSERT(!lilv_state_equals(fstate6, fstate72)); + + lilv_instance_deactivate(instance); + lilv_instance_free(instance); lilv_node_free(num); lilv_node_free(test_state_bundle); @@ -1180,6 +1279,11 @@ test_state(void) lilv_state_free(state4); lilv_state_free(state5); lilv_state_free(state6); + lilv_state_free(fstate); + lilv_state_free(fstate2); + lilv_state_free(fstate3); + lilv_state_free(fstate4); + lilv_state_free(fstate5); // Free URI map for (size_t i = 0; i < n_uris; ++i) { @@ -1188,8 +1292,6 @@ test_state(void) free(uris); n_uris = 0; - lilv_instance_free(instance); - lilv_node_free(plugin_uri); lilv_node_free(bundle_uri); lilv_world_free(world); @@ -1262,6 +1364,29 @@ test_bad_port_index(void) /*****************************************************************************/ +int +test_string(void) +{ + char* s = NULL; + + TEST_ASSERT(!strcmp((s = lilv_dirname("/foo/bar")), "/foo")); + TEST_ASSERT(!strcmp((s = lilv_dirname("/foo/bar/")), "/foo")); + TEST_ASSERT(!strcmp((s = lilv_dirname("/foo///bar/")), "/foo")); + TEST_ASSERT(!strcmp((s = lilv_dirname("/foo///bar//")), "/foo")); + TEST_ASSERT(!strcmp((s = lilv_dirname("foo")), ".")); + TEST_ASSERT(!strcmp((s = lilv_dirname("/foo")), "/")); + TEST_ASSERT(!strcmp((s = lilv_dirname("/")), "/")); + TEST_ASSERT(!strcmp((s = lilv_dirname("//")), "/")); + TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b", "/a/")), "b")); + TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a", "/b/c/")), "/a")); + TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/")), "../c")); + TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/e/")), "../../c")); + + return 1; +} + +/*****************************************************************************/ + /* add tests here */ static struct TestCase tests[] = { TEST_CASE(utils), @@ -1276,6 +1401,8 @@ static struct TestCase tests[] = { TEST_CASE(state), TEST_CASE(bad_port_symbol), TEST_CASE(bad_port_index), + TEST_CASE(bad_port_index), + TEST_CASE(string), { NULL, NULL } }; diff --git a/test/test_plugin.c b/test/test_plugin.c index 0ef76f2..55df26c 100644 --- a/test/test_plugin.c +++ b/test/test_plugin.c @@ -15,6 +15,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _BSD_SOURCE /* for realpath */ + +#include #include #include #include @@ -39,6 +42,10 @@ typedef struct { LV2_URID atom_Float; } uris; + char* tmp_file_path; + char* rec_file_path; + FILE* rec_file; + float* input; float* output; unsigned num_runs; @@ -47,6 +54,10 @@ typedef struct { static void cleanup(LV2_Handle instance) { + Test* test = (Test*)instance; + if (test->rec_file) { + fclose(test->rec_file); + } free(instance); } @@ -79,26 +90,43 @@ instantiate(const LV2_Descriptor* descriptor, return NULL; } - test->map = NULL; - test->input = NULL; - test->output = NULL; - test->num_runs = 0; + test->map = NULL; + test->input = NULL; + test->output = NULL; + test->num_runs = 0; + test->tmp_file_path = malloc(L_tmpnam); + test->rec_file_path = NULL; + test->rec_file = NULL; + + tmpnam(test->tmp_file_path); + + LV2_State_Make_Path* make_path = NULL; - /* 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"); + } else if (!strcmp(features[i]->URI, LV2_STATE_MAKE_PATH_URI)) { + make_path = (LV2_State_Make_Path*)features[i]->data; } } if (!test->map) { - fprintf(stderr, "Host does not support urid:map.\n"); + fprintf(stderr, "Host does not support urid:map\n"); free(test); return NULL; } + if (make_path) { + test->rec_file_path = make_path->path(make_path->handle, "recfile"); + if (!(test->rec_file = fopen(test->rec_file_path, "w"))) { + fprintf(stderr, "ERROR: Failed to open rec file\n"); + } + fprintf(test->rec_file, "instantiate\n"); + + } + return (LV2_Handle)test; } @@ -108,7 +136,11 @@ run(LV2_Handle instance, { Test* test = (Test*)instance; *test->output = *test->input; - ++test->num_runs; + if (sample_count == 1) { + ++test->num_runs; + } else if (sample_count == 2 && test->rec_file) { + fprintf(test->rec_file, "run\n"); + } } static uint32_t @@ -126,6 +158,16 @@ save(LV2_Handle instance, { Test* plugin = (Test*)instance; + LV2_State_Map_Path* map_path = NULL; + //LV2_State_Make_Path* make_path = NULL; + for (int i = 0; features && features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_STATE_MAP_PATH_URI)) { + map_path = (LV2_State_Map_Path*)features[i]->data; + }/* else if (!strcmp(features[i]->URI, LV2_STATE_MAKE_PATH_URI)) { + make_path = (LV2_State_Make_Path*)features[i]->data; + }*/ + } + store(callback_data, map_uri(plugin, "http://example.org/greeting"), "hello", @@ -181,6 +223,44 @@ save(LV2_Handle instance, sizeof(blob), map_uri(plugin, "http://example.org/SomeUnknownType"), LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + if (map_path) { + FILE* file = fopen(plugin->tmp_file_path, "w"); + fprintf(file, "Hello\n"); + fclose(file); + char* apath = map_path->abstract_path(map_path->handle, + plugin->tmp_file_path); + char* apath2 = map_path->abstract_path(map_path->handle, + plugin->tmp_file_path); + if (strcmp(apath, apath2)) { + fprintf(stderr, "ERROR: Path %s != %s\n", apath, apath2); + } + + store(callback_data, + map_uri(plugin, "http://example.org/extfile"), + apath, + strlen(apath) + 1, + map_uri(plugin, LV2_STATE_PATH_URI), + LV2_STATE_IS_PORTABLE); + + free(apath); + free(apath2); + + if (plugin->rec_file) { + fflush(plugin->rec_file); + apath = map_path->abstract_path(map_path->handle, + plugin->rec_file_path); + + store(callback_data, + map_uri(plugin, "http://example.org/recfile"), + apath, + strlen(apath) + 1, + map_uri(plugin, LV2_STATE_PATH_URI), + LV2_STATE_IS_PORTABLE); + + free(apath); + } + } } static void @@ -192,6 +272,13 @@ restore(LV2_Handle instance, { Test* plugin = (Test*)instance; + LV2_State_Map_Path* map_path = NULL; + for (int i = 0; features && features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_STATE_MAP_PATH_URI)) { + map_path = (LV2_State_Map_Path*)features[i]->data; + } + } + size_t size; uint32_t type; uint32_t valflags; @@ -200,6 +287,20 @@ restore(LV2_Handle instance, callback_data, map_uri(plugin, "http://example.org/num-runs"), &size, &type, &valflags); + + char* apath = (char*)retrieve( + callback_data, + map_uri(plugin, "http://example.org/extfile"), + &size, &type, &valflags); + + if (map_path && apath) { + char* path = map_path->absolute_path(map_path->handle, apath); + char* real_path = realpath(path, NULL); + if (strcmp(real_path, plugin->tmp_file_path)) { + fprintf(stderr, "ERROR: Restored bad path `%s' != `%s'\n", + real_path, plugin->tmp_file_path); + } + } } const void* -- cgit v1.2.1