Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lilv_test.c 63KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922
  1. /*
  2. Copyright 2007-2014 David Robillard <http://drobilla.net>
  3. Copyright 2008 Krzysztof Foltman
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted, provided that the above
  6. copyright notice and this permission notice appear in all copies.
  7. THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #define _POSIX_C_SOURCE 200112L /* for setenv */
  16. #include <assert.h>
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <float.h>
  20. #include <limits.h>
  21. #include <math.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #ifdef _WIN32
  27. # include <direct.h>
  28. # define mkdir(path, flags) _mkdir(path)
  29. # define setenv(n, v, r) SetEnvironmentVariable((n), (v))
  30. # define unsetenv(n) SetEnvironmentVariable((n), NULL)
  31. #else
  32. # include <dirent.h>
  33. # include <unistd.h>
  34. #endif
  35. #include "lilv/lilv.h"
  36. #include "../src/lilv_internal.h"
  37. #include "lv2/lv2plug.in/ns/ext/presets/presets.h"
  38. #include "lv2/lv2plug.in/ns/ext/state/state.h"
  39. #include "lv2/lv2plug.in/ns/ext/urid/urid.h"
  40. #define TEST_PATH_MAX 1024
  41. #if defined(__APPLE__)
  42. # define SHLIB_EXT ".dylib"
  43. #elif defined(_WIN32)
  44. # define SHLIB_EXT ".dll"
  45. #else
  46. # define SHLIB_EXT ".so"
  47. #endif
  48. static char bundle_dir_name[TEST_PATH_MAX];
  49. static char bundle_dir_uri[TEST_PATH_MAX];
  50. static char manifest_name[TEST_PATH_MAX];
  51. static char content_name[TEST_PATH_MAX];
  52. static LilvWorld* world;
  53. int test_count = 0;
  54. int error_count = 0;
  55. static void
  56. delete_bundle(void)
  57. {
  58. unlink(content_name);
  59. unlink(manifest_name);
  60. remove(bundle_dir_name);
  61. }
  62. static void
  63. init_tests(void)
  64. {
  65. strncpy(bundle_dir_name, getenv("HOME"), 900);
  66. strcat(bundle_dir_name, "/.lv2");
  67. mkdir(bundle_dir_name, 0700);
  68. strcat(bundle_dir_name, "/lilv-test.lv2");
  69. sprintf(bundle_dir_uri, "file://%s/", bundle_dir_name);
  70. sprintf(manifest_name, "%s/manifest.ttl", bundle_dir_name);
  71. sprintf(content_name, "%s/plugin.ttl", bundle_dir_name);
  72. delete_bundle();
  73. }
  74. static void
  75. fatal_error(const char* err, const char* arg)
  76. {
  77. /* TODO: possibly change to vfprintf later */
  78. fprintf(stderr, err, arg);
  79. /* IMHO, the bundle should be left in place after an error, for possible investigation */
  80. /* delete_bundle(); */
  81. exit(1);
  82. }
  83. static void
  84. write_file(const char* name, const char* content)
  85. {
  86. FILE* f = fopen(name, "w");
  87. size_t len = strlen(content);
  88. if (fwrite(content, 1, len, f) != len)
  89. fatal_error("Cannot write file %s\n", name);
  90. fclose(f);
  91. }
  92. static int
  93. init_world(void)
  94. {
  95. world = lilv_world_new();
  96. return world != NULL;
  97. }
  98. static int
  99. load_all_bundles(void)
  100. {
  101. if (!init_world())
  102. return 0;
  103. lilv_world_load_all(world);
  104. return 1;
  105. }
  106. static void
  107. create_bundle(const char* manifest, const char* content)
  108. {
  109. if (mkdir(bundle_dir_name, 0700) && errno != EEXIST)
  110. fatal_error("Cannot create directory %s\n", bundle_dir_name);
  111. write_file(manifest_name, manifest);
  112. write_file(content_name, content);
  113. }
  114. static int
  115. start_bundle(const char* manifest, const char* content)
  116. {
  117. create_bundle(manifest, content);
  118. return load_all_bundles();
  119. }
  120. static void
  121. unload_bundle(void)
  122. {
  123. if (world)
  124. lilv_world_free(world);
  125. world = NULL;
  126. }
  127. static void
  128. cleanup(void)
  129. {
  130. delete_bundle();
  131. }
  132. /*****************************************************************************/
  133. #define TEST_CASE(name) { #name, test_##name }
  134. #define TEST_ASSERT(check) do {\
  135. test_count++;\
  136. if (!(check)) {\
  137. error_count++;\
  138. fprintf(stderr, "lilv_test.c:%d: error: %s\n", __LINE__, #check);\
  139. }\
  140. } while (0)
  141. typedef int (*TestFunc)(void);
  142. struct TestCase {
  143. const char* title;
  144. TestFunc func;
  145. };
  146. #define PREFIX_ATOM "@prefix atom: <http://lv2plug.in/ns/ext/atom#> . \n"
  147. #define PREFIX_LINE "@prefix : <http://example.org/> .\n"
  148. #define PREFIX_LV2 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
  149. #define PREFIX_LV2EV "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n"
  150. #define PREFIX_LV2UI "@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n"
  151. #define PREFIX_RDF "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
  152. #define PREFIX_RDFS "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
  153. #define PREFIX_FOAF "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
  154. #define PREFIX_DOAP "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
  155. #define PREFIX_PSET "@prefix pset: <http://lv2plug.in/ns/ext/presets#> .\n"
  156. #define MANIFEST_PREFIXES PREFIX_LINE PREFIX_LV2 PREFIX_RDFS
  157. #define BUNDLE_PREFIXES PREFIX_ATOM PREFIX_LINE PREFIX_LV2 PREFIX_RDF PREFIX_RDFS PREFIX_FOAF PREFIX_DOAP PREFIX_PSET
  158. #define PLUGIN_NAME(name) "doap:name \"" name "\""
  159. #define LICENSE_GPL "doap:license <http://usefulinc.com/doap/licenses/gpl>"
  160. static const char* uris_plugin = "http://example.org/plug";
  161. static LilvNode* plugin_uri_value;
  162. static LilvNode* plugin2_uri_value;
  163. /*****************************************************************************/
  164. static void
  165. init_uris(void)
  166. {
  167. plugin_uri_value = lilv_new_uri(world, uris_plugin);
  168. plugin2_uri_value = lilv_new_uri(world, "http://example.org/foobar");
  169. TEST_ASSERT(plugin_uri_value);
  170. TEST_ASSERT(plugin2_uri_value);
  171. }
  172. static void
  173. cleanup_uris(void)
  174. {
  175. lilv_node_free(plugin2_uri_value);
  176. lilv_node_free(plugin_uri_value);
  177. plugin2_uri_value = NULL;
  178. plugin_uri_value = NULL;
  179. }
  180. /*****************************************************************************/
  181. static int
  182. test_utils(void)
  183. {
  184. TEST_ASSERT(!strcmp(lilv_uri_to_path("file:///tmp/blah"), "/tmp/blah"));
  185. TEST_ASSERT(!lilv_uri_to_path("file:/example.org/blah"));
  186. TEST_ASSERT(!lilv_uri_to_path("http://example.org/blah"));
  187. return 1;
  188. }
  189. /*****************************************************************************/
  190. static int
  191. test_value(void)
  192. {
  193. if (!start_bundle(MANIFEST_PREFIXES
  194. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  195. BUNDLE_PREFIXES
  196. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  197. PLUGIN_NAME("Test plugin") " ; "
  198. LICENSE_GPL " ; "
  199. "lv2:port [ "
  200. " a lv2:ControlPort ; a lv2:InputPort ; "
  201. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
  202. "] ."))
  203. return 0;
  204. init_uris();
  205. LilvNode* uval = lilv_new_uri(world, "http://example.org");
  206. LilvNode* sval = lilv_new_string(world, "Foo");
  207. LilvNode* ival = lilv_new_int(world, 42);
  208. LilvNode* fval = lilv_new_float(world, 1.6180);
  209. TEST_ASSERT(lilv_node_is_uri(uval));
  210. TEST_ASSERT(lilv_node_is_string(sval));
  211. TEST_ASSERT(lilv_node_is_int(ival));
  212. TEST_ASSERT(lilv_node_is_float(fval));
  213. TEST_ASSERT(!lilv_node_is_literal(uval));
  214. TEST_ASSERT(lilv_node_is_literal(sval));
  215. TEST_ASSERT(lilv_node_is_literal(ival));
  216. TEST_ASSERT(lilv_node_is_literal(fval));
  217. TEST_ASSERT(!strcmp(lilv_node_as_uri(uval), "http://example.org"));
  218. TEST_ASSERT(!strcmp(lilv_node_as_string(sval), "Foo"));
  219. TEST_ASSERT(lilv_node_as_int(ival) == 42);
  220. TEST_ASSERT(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON);
  221. LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar");
  222. LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo");
  223. LilvNode* host_abs = lilv_new_file_uri(world, "host", "/foo/bar");
  224. LilvNode* host_rel = lilv_new_file_uri(world, "host", "foo");
  225. TEST_ASSERT(!strcmp(lilv_node_as_uri(loc_abs), "file:///foo/bar"));
  226. TEST_ASSERT(!strncmp(lilv_node_as_uri(loc_rel), "file:///", 8));
  227. TEST_ASSERT(!strcmp(lilv_node_as_uri(host_abs), "file://host/foo/bar"));
  228. TEST_ASSERT(!strncmp(lilv_node_as_uri(host_rel), "file://host/", 12));
  229. lilv_node_free(host_rel);
  230. lilv_node_free(host_abs);
  231. lilv_node_free(loc_rel);
  232. lilv_node_free(loc_abs);
  233. char* tok = lilv_node_get_turtle_token(uval);
  234. TEST_ASSERT(!strcmp(tok, "<http://example.org>"));
  235. free(tok);
  236. tok = lilv_node_get_turtle_token(sval);
  237. TEST_ASSERT(!strcmp(tok, "Foo"));
  238. free(tok);
  239. tok = lilv_node_get_turtle_token(ival);
  240. TEST_ASSERT(!strcmp(tok, "42"));
  241. free(tok);
  242. tok = lilv_node_get_turtle_token(fval);
  243. TEST_ASSERT(!strncmp(tok, "1.6180", 6));
  244. free(tok);
  245. LilvNode* uval_e = lilv_new_uri(world, "http://example.org");
  246. LilvNode* sval_e = lilv_new_string(world, "Foo");
  247. LilvNode* ival_e = lilv_new_int(world, 42);
  248. LilvNode* fval_e = lilv_new_float(world, 1.6180);
  249. LilvNode* uval_ne = lilv_new_uri(world, "http://no-example.org");
  250. LilvNode* sval_ne = lilv_new_string(world, "Bar");
  251. LilvNode* ival_ne = lilv_new_int(world, 24);
  252. LilvNode* fval_ne = lilv_new_float(world, 3.14159);
  253. TEST_ASSERT(lilv_node_equals(uval, uval_e));
  254. TEST_ASSERT(lilv_node_equals(sval, sval_e));
  255. TEST_ASSERT(lilv_node_equals(ival, ival_e));
  256. TEST_ASSERT(lilv_node_equals(fval, fval_e));
  257. TEST_ASSERT(!lilv_node_equals(uval, uval_ne));
  258. TEST_ASSERT(!lilv_node_equals(sval, sval_ne));
  259. TEST_ASSERT(!lilv_node_equals(ival, ival_ne));
  260. TEST_ASSERT(!lilv_node_equals(fval, fval_ne));
  261. TEST_ASSERT(!lilv_node_equals(uval, sval));
  262. TEST_ASSERT(!lilv_node_equals(sval, ival));
  263. TEST_ASSERT(!lilv_node_equals(ival, fval));
  264. LilvNode* uval_dup = lilv_node_duplicate(uval);
  265. TEST_ASSERT(lilv_node_equals(uval, uval_dup));
  266. LilvNode* ifval = lilv_new_float(world, 42.0);
  267. TEST_ASSERT(!lilv_node_equals(ival, ifval));
  268. lilv_node_free(ifval);
  269. LilvNode* nil = NULL;
  270. TEST_ASSERT(!lilv_node_equals(uval, nil));
  271. TEST_ASSERT(!lilv_node_equals(nil, uval));
  272. TEST_ASSERT(lilv_node_equals(nil, nil));
  273. LilvNode* nil2 = lilv_node_duplicate(nil);
  274. TEST_ASSERT(lilv_node_equals(nil, nil2));
  275. lilv_node_free(uval);
  276. lilv_node_free(sval);
  277. lilv_node_free(ival);
  278. lilv_node_free(fval);
  279. lilv_node_free(uval_e);
  280. lilv_node_free(sval_e);
  281. lilv_node_free(ival_e);
  282. lilv_node_free(fval_e);
  283. lilv_node_free(uval_ne);
  284. lilv_node_free(sval_ne);
  285. lilv_node_free(ival_ne);
  286. lilv_node_free(fval_ne);
  287. lilv_node_free(uval_dup);
  288. lilv_node_free(nil2);
  289. cleanup_uris();
  290. return 1;
  291. }
  292. /*****************************************************************************/
  293. static int discovery_plugin_found = 0;
  294. static void
  295. discovery_verify_plugin(const LilvPlugin* plugin)
  296. {
  297. const LilvNode* value = lilv_plugin_get_uri(plugin);
  298. if (lilv_node_equals(value, plugin_uri_value)) {
  299. const LilvNode* lib_uri = NULL;
  300. TEST_ASSERT(!lilv_node_equals(value, plugin2_uri_value));
  301. discovery_plugin_found = 1;
  302. lib_uri = lilv_plugin_get_library_uri(plugin);
  303. TEST_ASSERT(lib_uri);
  304. TEST_ASSERT(lilv_node_is_uri(lib_uri));
  305. TEST_ASSERT(lilv_node_as_uri(lib_uri));
  306. TEST_ASSERT(strstr(lilv_node_as_uri(lib_uri), "foo" SHLIB_EXT));
  307. TEST_ASSERT(lilv_plugin_verify(plugin));
  308. }
  309. }
  310. static int
  311. test_discovery(void)
  312. {
  313. if (!start_bundle(MANIFEST_PREFIXES
  314. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  315. BUNDLE_PREFIXES
  316. ":plug a lv2:Plugin ;"
  317. PLUGIN_NAME("Test plugin") " ; "
  318. LICENSE_GPL " ; "
  319. "lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
  320. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; ] ."))
  321. return 0;
  322. init_uris();
  323. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  324. TEST_ASSERT(lilv_plugins_size(plugins) > 0);
  325. const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  326. TEST_ASSERT(explug != NULL);
  327. const LilvPlugin* explug2 = lilv_plugins_get_by_uri(plugins, plugin2_uri_value);
  328. TEST_ASSERT(explug2 == NULL);
  329. if (explug) {
  330. LilvNode* name = lilv_plugin_get_name(explug);
  331. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "Test plugin"));
  332. lilv_node_free(name);
  333. }
  334. discovery_plugin_found = 0;
  335. LILV_FOREACH(plugins, i, plugins)
  336. discovery_verify_plugin(lilv_plugins_get(plugins, i));
  337. TEST_ASSERT(discovery_plugin_found);
  338. plugins = NULL;
  339. cleanup_uris();
  340. return 1;
  341. }
  342. /*****************************************************************************/
  343. static int
  344. test_lv2_path(void)
  345. {
  346. #ifndef _WIN32
  347. char* orig_lv2_path = lilv_strdup(getenv("LV2_PATH"));
  348. setenv("LV2_PATH", "~/.lv2:/usr/local/lib/lv2:/usr/lib/lv2", 1);
  349. world = lilv_world_new();
  350. lilv_world_load_all(world);
  351. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  352. const size_t n_plugins = lilv_plugins_size(plugins);
  353. lilv_world_free(world);
  354. setenv("LV2_PATH", "$HOME/.lv2:/usr/local/lib/lv2:/usr/lib/lv2", 1);
  355. world = lilv_world_new();
  356. lilv_world_load_all(world);
  357. plugins = lilv_world_get_all_plugins(world);
  358. TEST_ASSERT(lilv_plugins_size(plugins) == n_plugins);
  359. lilv_world_free(world);
  360. world = NULL;
  361. if (orig_lv2_path) {
  362. setenv("LV2_PATH", orig_lv2_path, 1);
  363. } else {
  364. unsetenv("LV2_PATH");
  365. }
  366. free(orig_lv2_path);
  367. #endif
  368. return 1;
  369. }
  370. /*****************************************************************************/
  371. static int
  372. test_verify(void)
  373. {
  374. if (!start_bundle(MANIFEST_PREFIXES
  375. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  376. BUNDLE_PREFIXES
  377. ":plug a lv2:Plugin ; "
  378. PLUGIN_NAME("Test plugin") " ; "
  379. LICENSE_GPL " ; "
  380. "lv2:port [ a lv2:ControlPort ; a lv2:InputPort ;"
  381. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ] ."))
  382. return 0;
  383. init_uris();
  384. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  385. const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  386. TEST_ASSERT(explug);
  387. TEST_ASSERT(lilv_plugin_verify(explug));
  388. cleanup_uris();
  389. return 1;
  390. }
  391. /*****************************************************************************/
  392. static int
  393. test_no_verify(void)
  394. {
  395. if (!start_bundle(MANIFEST_PREFIXES
  396. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  397. BUNDLE_PREFIXES
  398. ":plug a lv2:Plugin . "))
  399. return 0;
  400. init_uris();
  401. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  402. const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  403. TEST_ASSERT(explug);
  404. TEST_ASSERT(!lilv_plugin_verify(explug));
  405. cleanup_uris();
  406. return 1;
  407. }
  408. /*****************************************************************************/
  409. static int
  410. test_classes(void)
  411. {
  412. if (!start_bundle(MANIFEST_PREFIXES
  413. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  414. BUNDLE_PREFIXES
  415. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  416. PLUGIN_NAME("Test plugin") " ; "
  417. LICENSE_GPL " ; "
  418. "lv2:port [ "
  419. " a lv2:ControlPort ; a lv2:InputPort ; "
  420. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"Foo\" ; "
  421. "] ."))
  422. return 0;
  423. init_uris();
  424. const LilvPluginClass* plugin = lilv_world_get_plugin_class(world);
  425. const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world);
  426. LilvPluginClasses* children = lilv_plugin_class_get_children(plugin);
  427. TEST_ASSERT(lilv_plugin_class_get_parent_uri(plugin) == NULL);
  428. TEST_ASSERT(lilv_plugin_classes_size(classes) > lilv_plugin_classes_size(children));
  429. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_plugin_class_get_label(plugin)), "Plugin"));
  430. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_plugin_class_get_uri(plugin)),
  431. "http://lv2plug.in/ns/lv2core#Plugin"));
  432. LILV_FOREACH(plugin_classes, i, children) {
  433. TEST_ASSERT(lilv_node_equals(
  434. lilv_plugin_class_get_parent_uri(lilv_plugin_classes_get(children, i)),
  435. lilv_plugin_class_get_uri(plugin)));
  436. }
  437. LilvNode* some_uri = lilv_new_uri(world, "http://example.org/whatever");
  438. TEST_ASSERT(lilv_plugin_classes_get_by_uri(classes, some_uri) == NULL);
  439. lilv_node_free(some_uri);
  440. lilv_plugin_classes_free(children);
  441. cleanup_uris();
  442. return 1;
  443. }
  444. /*****************************************************************************/
  445. static int
  446. test_plugin(void)
  447. {
  448. if (!start_bundle(MANIFEST_PREFIXES
  449. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  450. BUNDLE_PREFIXES
  451. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  452. PLUGIN_NAME("Test plugin") " ; "
  453. LICENSE_GPL " ; "
  454. "lv2:optionalFeature lv2:hardRTCapable ; "
  455. "lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
  456. "lv2:extensionData <http://example.org/extdata> ;"
  457. ":foo 1.6180 ; "
  458. ":bar true ; "
  459. ":baz false ; "
  460. ":blank [ a <http://example.org/blank> ] ; "
  461. "doap:maintainer [ foaf:name \"David Robillard\" ; "
  462. " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
  463. "lv2:port [ "
  464. " a lv2:ControlPort ; a lv2:InputPort ; "
  465. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  466. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  467. "] , [ "
  468. " a lv2:ControlPort ; a lv2:InputPort ; "
  469. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  470. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  471. "] , [ "
  472. " a lv2:ControlPort ; a lv2:OutputPort ; "
  473. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  474. " lv2:portProperty lv2:reportsLatency ; "
  475. " lv2:designation lv2:latency "
  476. "] . \n"
  477. ":thing doap:name \"Something else\" .\n"))
  478. return 0;
  479. init_uris();
  480. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  481. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  482. TEST_ASSERT(plug);
  483. const LilvPluginClass* klass = lilv_plugin_get_class(plug);
  484. const LilvNode* klass_uri = lilv_plugin_class_get_uri(klass);
  485. TEST_ASSERT(!strcmp(lilv_node_as_string(klass_uri),
  486. "http://lv2plug.in/ns/lv2core#CompressorPlugin"));
  487. LilvNode* rdf_type = lilv_new_uri(
  488. world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
  489. TEST_ASSERT(lilv_world_ask(world,
  490. lilv_plugin_get_uri(plug),
  491. rdf_type,
  492. klass_uri));
  493. lilv_node_free(rdf_type);
  494. TEST_ASSERT(!lilv_plugin_is_replaced(plug));
  495. TEST_ASSERT(!lilv_plugin_get_related(plug, NULL));
  496. const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
  497. TEST_ASSERT(!strcmp(lilv_node_as_string(plug_bundle_uri), bundle_dir_uri));
  498. const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
  499. TEST_ASSERT(lilv_nodes_size(data_uris) == 2);
  500. LilvNode* project = lilv_plugin_get_project(plug);
  501. TEST_ASSERT(!project);
  502. char* manifest_uri = (char*)malloc(TEST_PATH_MAX);
  503. char* data_uri = (char*)malloc(TEST_PATH_MAX);
  504. snprintf(manifest_uri, TEST_PATH_MAX, "%s%s",
  505. lilv_node_as_string(plug_bundle_uri), "manifest.ttl");
  506. snprintf(data_uri, TEST_PATH_MAX, "%s%s",
  507. lilv_node_as_string(plug_bundle_uri), "plugin.ttl");
  508. LilvNode* manifest_uri_val = lilv_new_uri(world, manifest_uri);
  509. TEST_ASSERT(lilv_nodes_contains(data_uris, manifest_uri_val));
  510. lilv_node_free(manifest_uri_val);
  511. LilvNode* data_uri_val = lilv_new_uri(world, data_uri);
  512. TEST_ASSERT(lilv_nodes_contains(data_uris, data_uri_val));
  513. lilv_node_free(data_uri_val);
  514. free(manifest_uri);
  515. free(data_uri);
  516. float mins[3];
  517. float maxs[3];
  518. float defs[3];
  519. lilv_plugin_get_port_ranges_float(plug, mins, maxs, defs);
  520. TEST_ASSERT(mins[0] == -1.0f);
  521. TEST_ASSERT(maxs[0] == 1.0f);
  522. TEST_ASSERT(defs[0] == 0.5f);
  523. LilvNode* audio_class = lilv_new_uri(world,
  524. "http://lv2plug.in/ns/lv2core#AudioPort");
  525. LilvNode* control_class = lilv_new_uri(world,
  526. "http://lv2plug.in/ns/lv2core#ControlPort");
  527. LilvNode* in_class = lilv_new_uri(world,
  528. "http://lv2plug.in/ns/lv2core#InputPort");
  529. LilvNode* out_class = lilv_new_uri(world,
  530. "http://lv2plug.in/ns/lv2core#OutputPort");
  531. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, control_class, NULL) == 3);
  532. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, audio_class, NULL) == 0);
  533. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, in_class, NULL) == 2);
  534. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, out_class, NULL) == 1);
  535. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, control_class, in_class, NULL) == 2);
  536. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, control_class, out_class, NULL) == 1);
  537. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) == 0);
  538. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, audio_class, out_class, NULL) == 0);
  539. TEST_ASSERT(lilv_plugin_has_latency(plug));
  540. TEST_ASSERT(lilv_plugin_get_latency_port_index(plug) == 2);
  541. LilvNode* lv2_latency = lilv_new_uri(world,
  542. "http://lv2plug.in/ns/lv2core#latency");
  543. const LilvPort* latency_port = lilv_plugin_get_port_by_designation(
  544. plug, out_class, lv2_latency);
  545. lilv_node_free(lv2_latency);
  546. TEST_ASSERT(latency_port);
  547. TEST_ASSERT(lilv_port_get_index(plug, latency_port) == 2);
  548. LilvNode* rt_feature = lilv_new_uri(world,
  549. "http://lv2plug.in/ns/lv2core#hardRTCapable");
  550. LilvNode* event_feature = lilv_new_uri(world,
  551. "http://lv2plug.in/ns/ext/event");
  552. LilvNode* pretend_feature = lilv_new_uri(world,
  553. "http://example.org/solvesWorldHunger");
  554. TEST_ASSERT(lilv_plugin_has_feature(plug, rt_feature));
  555. TEST_ASSERT(lilv_plugin_has_feature(plug, event_feature));
  556. TEST_ASSERT(!lilv_plugin_has_feature(plug, pretend_feature));
  557. lilv_node_free(rt_feature);
  558. lilv_node_free(event_feature);
  559. lilv_node_free(pretend_feature);
  560. LilvNodes* supported = lilv_plugin_get_supported_features(plug);
  561. LilvNodes* required = lilv_plugin_get_required_features(plug);
  562. LilvNodes* optional = lilv_plugin_get_optional_features(plug);
  563. TEST_ASSERT(lilv_nodes_size(supported) == 2);
  564. TEST_ASSERT(lilv_nodes_size(required) == 1);
  565. TEST_ASSERT(lilv_nodes_size(optional) == 1);
  566. lilv_nodes_free(supported);
  567. lilv_nodes_free(required);
  568. lilv_nodes_free(optional);
  569. LilvNode* foo_p = lilv_new_uri(world, "http://example.org/foo");
  570. LilvNodes* foos = lilv_plugin_get_value(plug, foo_p);
  571. TEST_ASSERT(lilv_nodes_size(foos) == 1);
  572. TEST_ASSERT(fabs(lilv_node_as_float(lilv_nodes_get_first(foos)) - 1.6180) < FLT_EPSILON);
  573. lilv_node_free(foo_p);
  574. lilv_nodes_free(foos);
  575. LilvNode* bar_p = lilv_new_uri(world, "http://example.org/bar");
  576. LilvNodes* bars = lilv_plugin_get_value(plug, bar_p);
  577. TEST_ASSERT(lilv_nodes_size(bars) == 1);
  578. TEST_ASSERT(lilv_node_as_bool(lilv_nodes_get_first(bars)) == true);
  579. lilv_node_free(bar_p);
  580. lilv_nodes_free(bars);
  581. LilvNode* baz_p = lilv_new_uri(world, "http://example.org/baz");
  582. LilvNodes* bazs = lilv_plugin_get_value(plug, baz_p);
  583. TEST_ASSERT(lilv_nodes_size(bazs) == 1);
  584. TEST_ASSERT(lilv_node_as_bool(lilv_nodes_get_first(bazs)) == false);
  585. lilv_node_free(baz_p);
  586. lilv_nodes_free(bazs);
  587. LilvNode* blank_p = lilv_new_uri(world, "http://example.org/blank");
  588. LilvNodes* blanks = lilv_plugin_get_value(plug, blank_p);
  589. TEST_ASSERT(lilv_nodes_size(blanks) == 1);
  590. LilvNode* blank = lilv_nodes_get_first(blanks);
  591. TEST_ASSERT(lilv_node_is_blank(blank));
  592. const char* blank_str = lilv_node_as_blank(blank);
  593. char* blank_tok = lilv_node_get_turtle_token(blank);
  594. TEST_ASSERT(!strncmp(blank_tok, "_:", 2));
  595. TEST_ASSERT(!strcmp(blank_tok + 2, blank_str));
  596. free(blank_tok);
  597. lilv_node_free(blank_p);
  598. lilv_nodes_free(blanks);
  599. LilvNode* author_name = lilv_plugin_get_author_name(plug);
  600. TEST_ASSERT(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
  601. lilv_node_free(author_name);
  602. LilvNode* author_email = lilv_plugin_get_author_email(plug);
  603. TEST_ASSERT(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
  604. lilv_node_free(author_email);
  605. LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
  606. TEST_ASSERT(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
  607. lilv_node_free(author_homepage);
  608. LilvNode* thing_uri = lilv_new_uri(world, "http://example.org/thing");
  609. LilvNode* name_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
  610. LilvNodes* thing_names = lilv_world_find_nodes(world, thing_uri, name_p, NULL);
  611. TEST_ASSERT(lilv_nodes_size(thing_names) == 1);
  612. LilvNode* thing_name = lilv_nodes_get_first(thing_names);
  613. TEST_ASSERT(thing_name);
  614. TEST_ASSERT(lilv_node_is_string(thing_name));
  615. TEST_ASSERT(!strcmp(lilv_node_as_string(thing_name), "Something else"));
  616. LilvNode* thing_name2 = lilv_world_get(world, thing_uri, name_p, NULL);
  617. TEST_ASSERT(lilv_node_equals(thing_name, thing_name2));
  618. LilvUIs* uis = lilv_plugin_get_uis(plug);
  619. TEST_ASSERT(lilv_uis_size(uis) == 0);
  620. lilv_uis_free(uis);
  621. LilvNode* extdata = lilv_new_uri(world, "http://example.org/extdata");
  622. LilvNode* noextdata = lilv_new_uri(world, "http://example.org/noextdata");
  623. LilvNodes* extdatas = lilv_plugin_get_extension_data(plug);
  624. TEST_ASSERT(lilv_plugin_has_extension_data(plug, extdata));
  625. TEST_ASSERT(!lilv_plugin_has_extension_data(plug, noextdata));
  626. TEST_ASSERT(lilv_nodes_size(extdatas) == 1);
  627. TEST_ASSERT(lilv_node_equals(lilv_nodes_get_first(extdatas), extdata));
  628. lilv_node_free(noextdata);
  629. lilv_node_free(extdata);
  630. lilv_nodes_free(extdatas);
  631. lilv_nodes_free(thing_names);
  632. lilv_node_free(thing_uri);
  633. lilv_node_free(thing_name2);
  634. lilv_node_free(name_p);
  635. lilv_node_free(control_class);
  636. lilv_node_free(audio_class);
  637. lilv_node_free(in_class);
  638. lilv_node_free(out_class);
  639. cleanup_uris();
  640. return 1;
  641. }
  642. /*****************************************************************************/
  643. static int
  644. test_project(void)
  645. {
  646. if (!start_bundle(MANIFEST_PREFIXES
  647. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  648. BUNDLE_PREFIXES
  649. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  650. PLUGIN_NAME("Test plugin with project") " ; "
  651. LICENSE_GPL " ; "
  652. "lv2:project [ "
  653. " doap:maintainer [ "
  654. " foaf:name \"David Robillard\" ; "
  655. " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
  656. "] ; "
  657. "lv2:port [ "
  658. " a lv2:ControlPort ; a lv2:InputPort ; "
  659. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  660. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  661. "] , [ "
  662. " a lv2:ControlPort ; a lv2:InputPort ; "
  663. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  664. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  665. "] , [ "
  666. " a lv2:ControlPort ; a lv2:OutputPort ; "
  667. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  668. " lv2:portProperty lv2:reportsLatency ; "
  669. " lv2:designation lv2:latency "
  670. "] . \n"
  671. ":thing doap:name \"Something else\" .\n"))
  672. return 0;
  673. init_uris();
  674. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  675. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  676. TEST_ASSERT(plug);
  677. LilvNode* author_name = lilv_plugin_get_author_name(plug);
  678. TEST_ASSERT(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
  679. lilv_node_free(author_name);
  680. LilvNode* author_email = lilv_plugin_get_author_email(plug);
  681. TEST_ASSERT(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
  682. lilv_node_free(author_email);
  683. LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
  684. TEST_ASSERT(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
  685. lilv_node_free(author_homepage);
  686. cleanup_uris();
  687. return 1;
  688. }
  689. /*****************************************************************************/
  690. static int
  691. test_no_author(void)
  692. {
  693. if (!start_bundle(MANIFEST_PREFIXES
  694. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  695. BUNDLE_PREFIXES
  696. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  697. PLUGIN_NAME("Test plugin with project") " ; "
  698. LICENSE_GPL " ; "
  699. "lv2:port [ "
  700. " a lv2:ControlPort ; a lv2:InputPort ; "
  701. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  702. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  703. "] , [ "
  704. " a lv2:ControlPort ; a lv2:InputPort ; "
  705. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  706. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  707. "] , [ "
  708. " a lv2:ControlPort ; a lv2:OutputPort ; "
  709. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  710. " lv2:portProperty lv2:reportsLatency ; "
  711. " lv2:designation lv2:latency "
  712. "] . \n"
  713. ":thing doap:name \"Something else\" .\n"))
  714. return 0;
  715. init_uris();
  716. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  717. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  718. TEST_ASSERT(plug);
  719. LilvNode* author_name = lilv_plugin_get_author_name(plug);
  720. TEST_ASSERT(!author_name);
  721. LilvNode* author_email = lilv_plugin_get_author_email(plug);
  722. TEST_ASSERT(!author_email);
  723. LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
  724. TEST_ASSERT(!author_homepage);
  725. cleanup_uris();
  726. return 1;
  727. }
  728. /*****************************************************************************/
  729. static int
  730. test_project_no_author(void)
  731. {
  732. if (!start_bundle(MANIFEST_PREFIXES
  733. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  734. BUNDLE_PREFIXES
  735. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  736. PLUGIN_NAME("Test plugin with project") " ; "
  737. LICENSE_GPL " ; "
  738. "lv2:project [ "
  739. " doap:name \"Fake project\" ;"
  740. "] ; "
  741. "lv2:port [ "
  742. " a lv2:ControlPort ; a lv2:InputPort ; "
  743. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  744. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  745. "] , [ "
  746. " a lv2:ControlPort ; a lv2:InputPort ; "
  747. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  748. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  749. "] , [ "
  750. " a lv2:ControlPort ; a lv2:OutputPort ; "
  751. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  752. " lv2:portProperty lv2:reportsLatency ; "
  753. " lv2:designation lv2:latency "
  754. "] . \n"
  755. ":thing doap:name \"Something else\" .\n"))
  756. return 0;
  757. init_uris();
  758. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  759. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  760. TEST_ASSERT(plug);
  761. LilvNode* author_name = lilv_plugin_get_author_name(plug);
  762. TEST_ASSERT(!author_name);
  763. LilvNode* author_email = lilv_plugin_get_author_email(plug);
  764. TEST_ASSERT(!author_email);
  765. LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
  766. TEST_ASSERT(!author_homepage);
  767. cleanup_uris();
  768. return 1;
  769. }
  770. /*****************************************************************************/
  771. static int
  772. test_preset(void)
  773. {
  774. if (!start_bundle(MANIFEST_PREFIXES
  775. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  776. BUNDLE_PREFIXES
  777. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  778. PLUGIN_NAME("Test plugin with project") " ; "
  779. LICENSE_GPL " ; "
  780. "lv2:project [ "
  781. " doap:name \"Fake project\" ;"
  782. "] ; "
  783. "lv2:port [ "
  784. " a lv2:ControlPort ; a lv2:InputPort ; "
  785. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  786. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  787. "] , [ "
  788. " a lv2:ControlPort ; a lv2:InputPort ; "
  789. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  790. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  791. "] , [ "
  792. " a lv2:ControlPort ; a lv2:OutputPort ; "
  793. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  794. " lv2:portProperty lv2:reportsLatency ; "
  795. " lv2:designation lv2:latency "
  796. "] . \n"
  797. "<http://example.org/preset> a pset:Preset ;"
  798. " lv2:appliesTo :plug ;"
  799. " rdfs:label \"some preset\" .\n"))
  800. return 0;
  801. init_uris();
  802. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  803. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  804. TEST_ASSERT(plug);
  805. LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
  806. LilvNodes* related = lilv_plugin_get_related(plug, pset_Preset);
  807. TEST_ASSERT(lilv_nodes_size(related) == 1);
  808. lilv_node_free(pset_Preset);
  809. lilv_nodes_free(related);
  810. cleanup_uris();
  811. return 1;
  812. }
  813. /*****************************************************************************/
  814. static int
  815. test_prototype(void)
  816. {
  817. if (!start_bundle(MANIFEST_PREFIXES
  818. ":prot a lv2:PluginBase ; rdfs:seeAlso <plugin.ttl> .\n"
  819. ":plug a lv2:Plugin ; lv2:binary <inst" SHLIB_EXT "> ; lv2:prototype :prot .\n",
  820. BUNDLE_PREFIXES
  821. ":prot a lv2:Plugin ; a lv2:CompressorPlugin ; "
  822. LICENSE_GPL " ; "
  823. "lv2:project [ "
  824. " doap:name \"Fake project\" ;"
  825. "] ; "
  826. "lv2:port [ "
  827. " a lv2:ControlPort ; a lv2:InputPort ; "
  828. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  829. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  830. "] , [ "
  831. " a lv2:ControlPort ; a lv2:InputPort ; "
  832. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  833. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  834. "] , [ "
  835. " a lv2:ControlPort ; a lv2:OutputPort ; "
  836. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  837. " lv2:portProperty lv2:reportsLatency ; "
  838. " lv2:designation lv2:latency "
  839. "] . \n"
  840. ":plug doap:name \"Instance\" .\n"))
  841. return 0;
  842. init_uris();
  843. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  844. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  845. TEST_ASSERT(plug);
  846. // Test non-inherited property
  847. LilvNode* name = lilv_plugin_get_name(plug);
  848. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "Instance"));
  849. lilv_node_free(name);
  850. // Test inherited property
  851. const LilvNode* binary = lilv_plugin_get_library_uri(plug);
  852. TEST_ASSERT(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
  853. cleanup_uris();
  854. return 1;
  855. }
  856. /*****************************************************************************/
  857. static int
  858. test_port(void)
  859. {
  860. if (!start_bundle(MANIFEST_PREFIXES
  861. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  862. BUNDLE_PREFIXES PREFIX_LV2EV
  863. ":plug a lv2:Plugin ; "
  864. PLUGIN_NAME("Test plugin") " ; "
  865. LICENSE_GPL " ; "
  866. "doap:homepage <http://example.org/someplug> ; "
  867. "lv2:port [ "
  868. " a lv2:ControlPort ; a lv2:InputPort ; "
  869. " lv2:index 0 ; lv2:symbol \"foo\" ; "
  870. " lv2:name \"store\" ; "
  871. " lv2:name \"dépanneur\"@fr-ca ; lv2:name \"épicerie\"@fr-fr ; "
  872. " lv2:name \"tienda\"@es ; "
  873. " rdfs:comment \"comment\"@en , \"commentaires\"@fr ; "
  874. " lv2:portProperty lv2:integer ; "
  875. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 ; "
  876. " lv2:scalePoint [ rdfs:label \"Sin\"; rdf:value 3 ] ; "
  877. " lv2:scalePoint [ rdfs:label \"Cos\"; rdf:value 4 ] "
  878. "] , [\n"
  879. " a lv2:EventPort ; a lv2:InputPort ; "
  880. " lv2:index 1 ; lv2:symbol \"event_in\" ; "
  881. " lv2:name \"Event Input\" ; "
  882. " lv2ev:supportsEvent <http://example.org/event> ;"
  883. " atom:supports <http://example.org/atomEvent> "
  884. "] , [\n"
  885. " a lv2:AudioPort ; a lv2:InputPort ; "
  886. " lv2:index 2 ; lv2:symbol \"audio_in\" ; "
  887. " lv2:name \"Audio Input\" ; "
  888. "] , [\n"
  889. " a lv2:AudioPort ; a lv2:OutputPort ; "
  890. " lv2:index 3 ; lv2:symbol \"audio_out\" ; "
  891. " lv2:name \"Audio Output\" ; "
  892. "] ."))
  893. return 0;
  894. init_uris();
  895. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  896. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  897. TEST_ASSERT(plug);
  898. LilvNode* psym = lilv_new_string(world, "foo");
  899. const LilvPort* p = lilv_plugin_get_port_by_index(plug, 0);
  900. const LilvPort* p2 = lilv_plugin_get_port_by_symbol(plug, psym);
  901. lilv_node_free(psym);
  902. TEST_ASSERT(p != NULL);
  903. TEST_ASSERT(p2 != NULL);
  904. TEST_ASSERT(p == p2);
  905. LilvNode* nopsym = lilv_new_string(world, "thisaintnoportfoo");
  906. const LilvPort* p3 = lilv_plugin_get_port_by_symbol(plug, nopsym);
  907. TEST_ASSERT(p3 == NULL);
  908. lilv_node_free(nopsym);
  909. LilvNode* audio_class = lilv_new_uri(world,
  910. "http://lv2plug.in/ns/lv2core#AudioPort");
  911. LilvNode* control_class = lilv_new_uri(world,
  912. "http://lv2plug.in/ns/lv2core#ControlPort");
  913. LilvNode* in_class = lilv_new_uri(world,
  914. "http://lv2plug.in/ns/lv2core#InputPort");
  915. LilvNode* out_class = lilv_new_uri(world,
  916. "http://lv2plug.in/ns/lv2core#OutputPort");
  917. TEST_ASSERT(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
  918. TEST_ASSERT(lilv_plugin_get_num_ports(plug) == 4);
  919. TEST_ASSERT(lilv_port_is_a(plug, p, control_class));
  920. TEST_ASSERT(lilv_port_is_a(plug, p, in_class));
  921. TEST_ASSERT(!lilv_port_is_a(plug, p, audio_class));
  922. LilvNodes* port_properties = lilv_port_get_properties(plug, p);
  923. TEST_ASSERT(lilv_nodes_size(port_properties) == 1);
  924. lilv_nodes_free(port_properties);
  925. // Untranslated name (current locale is set to "C" in main)
  926. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
  927. LilvNode* name = lilv_port_get_name(plug, p);
  928. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "store"));
  929. lilv_node_free(name);
  930. // Exact language match
  931. setenv("LANG", "fr_FR", 1);
  932. name = lilv_port_get_name(plug, p);
  933. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "épicerie"));
  934. lilv_node_free(name);
  935. // Exact language match (with charset suffix)
  936. setenv("LANG", "fr_CA.utf8", 1);
  937. name = lilv_port_get_name(plug, p);
  938. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "dépanneur"));
  939. lilv_node_free(name);
  940. // Partial language match (choose value translated for different country)
  941. setenv("LANG", "fr_BE", 1);
  942. name = lilv_port_get_name(plug, p);
  943. TEST_ASSERT((!strcmp(lilv_node_as_string(name), "dépanneur"))
  944. ||(!strcmp(lilv_node_as_string(name), "épicerie")));
  945. lilv_node_free(name);
  946. // Partial language match (choose country-less language tagged value)
  947. setenv("LANG", "es_MX", 1);
  948. name = lilv_port_get_name(plug, p);
  949. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "tienda"));
  950. lilv_node_free(name);
  951. // No language match (choose untranslated value)
  952. setenv("LANG", "cn", 1);
  953. name = lilv_port_get_name(plug, p);
  954. TEST_ASSERT(!strcmp(lilv_node_as_string(name), "store"));
  955. lilv_node_free(name);
  956. setenv("LANG", "en_CA.utf-8", 1);
  957. // Language tagged value with no untranslated values
  958. LilvNode* rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
  959. LilvNodes* comments = lilv_port_get_value(plug, p, rdfs_comment);
  960. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
  961. "comment"));
  962. LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
  963. TEST_ASSERT(!strcmp(lilv_node_as_string(comment), "comment"));
  964. lilv_node_free(comment);
  965. lilv_nodes_free(comments);
  966. setenv("LANG", "fr", 1);
  967. comments = lilv_port_get_value(plug, p, rdfs_comment);
  968. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
  969. "commentaires"));
  970. lilv_nodes_free(comments);
  971. setenv("LANG", "cn", 1);
  972. comments = lilv_port_get_value(plug, p, rdfs_comment);
  973. TEST_ASSERT(!comments);
  974. lilv_nodes_free(comments);
  975. lilv_node_free(rdfs_comment);
  976. setenv("LANG", "C", 1); // Reset locale
  977. LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
  978. TEST_ASSERT(lilv_scale_points_size(points) == 2);
  979. LilvIter* sp_iter = lilv_scale_points_begin(points);
  980. const LilvScalePoint* sp0 = lilv_scale_points_get(points, sp_iter);
  981. TEST_ASSERT(sp0);
  982. sp_iter = lilv_scale_points_next(points, sp_iter);
  983. const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
  984. TEST_ASSERT(sp1);
  985. TEST_ASSERT(
  986. ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Sin")
  987. && lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3)
  988. &&
  989. (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Cos")
  990. && lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4))
  991. ||
  992. ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Cos")
  993. && lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4)
  994. &&
  995. (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Sin")
  996. && lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
  997. LilvNode* homepage_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
  998. LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
  999. TEST_ASSERT(lilv_nodes_size(homepages) == 1);
  1000. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
  1001. "http://example.org/someplug"));
  1002. LilvNode *min, *max, *def;
  1003. lilv_port_get_range(plug, p, &def, &min, &max);
  1004. TEST_ASSERT(def);
  1005. TEST_ASSERT(min);
  1006. TEST_ASSERT(max);
  1007. TEST_ASSERT(lilv_node_as_float(def) == 0.5);
  1008. TEST_ASSERT(lilv_node_as_float(min) == -1.0);
  1009. TEST_ASSERT(lilv_node_as_float(max) == 1.0);
  1010. LilvNode* integer_prop = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
  1011. LilvNode* toggled_prop = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
  1012. TEST_ASSERT(lilv_port_has_property(plug, p, integer_prop));
  1013. TEST_ASSERT(!lilv_port_has_property(plug, p, toggled_prop));
  1014. const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
  1015. LilvNode* event_type = lilv_new_uri(world, "http://example.org/event");
  1016. LilvNode* event_type_2 = lilv_new_uri(world, "http://example.org/otherEvent");
  1017. LilvNode* atom_event = lilv_new_uri(world, "http://example.org/atomEvent");
  1018. TEST_ASSERT(lilv_port_supports_event(plug, ep, event_type));
  1019. TEST_ASSERT(!lilv_port_supports_event(plug, ep, event_type_2));
  1020. TEST_ASSERT(lilv_port_supports_event(plug, ep, atom_event));
  1021. LilvNode* name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
  1022. LilvNodes* names = lilv_port_get_value(plug, p, name_p);
  1023. TEST_ASSERT(lilv_nodes_size(names) == 1);
  1024. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
  1025. "store"));
  1026. lilv_nodes_free(names);
  1027. LilvNode* true_val = lilv_new_bool(world, true);
  1028. LilvNode* false_val = lilv_new_bool(world, false);
  1029. TEST_ASSERT(!lilv_node_equals(true_val, false_val));
  1030. lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
  1031. names = lilv_port_get_value(plug, p, name_p);
  1032. TEST_ASSERT(lilv_nodes_size(names) == 4);
  1033. lilv_nodes_free(names);
  1034. lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
  1035. lilv_node_free(false_val);
  1036. lilv_node_free(true_val);
  1037. names = lilv_port_get_value(plug, ep, name_p);
  1038. TEST_ASSERT(lilv_nodes_size(names) == 1);
  1039. TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
  1040. "Event Input"));
  1041. const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
  1042. TEST_ASSERT(lilv_port_is_a(plug, ap_in, in_class));
  1043. TEST_ASSERT(!lilv_port_is_a(plug, ap_in, out_class));
  1044. TEST_ASSERT(lilv_port_is_a(plug, ap_in, audio_class));
  1045. TEST_ASSERT(!lilv_port_is_a(plug, ap_in, control_class));
  1046. const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
  1047. TEST_ASSERT(lilv_port_is_a(plug, ap_out, out_class));
  1048. TEST_ASSERT(!lilv_port_is_a(plug, ap_out, in_class));
  1049. TEST_ASSERT(lilv_port_is_a(plug, ap_out, audio_class));
  1050. TEST_ASSERT(!lilv_port_is_a(plug, ap_out, control_class));
  1051. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, control_class, in_class , NULL) == 1);
  1052. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, audio_class , in_class , NULL) == 1);
  1053. TEST_ASSERT(lilv_plugin_get_num_ports_of_class(plug, audio_class , out_class, NULL) == 1);
  1054. lilv_nodes_free(names);
  1055. lilv_node_free(name_p);
  1056. lilv_node_free(integer_prop);
  1057. lilv_node_free(toggled_prop);
  1058. lilv_node_free(event_type);
  1059. lilv_node_free(event_type_2);
  1060. lilv_node_free(atom_event);
  1061. lilv_node_free(min);
  1062. lilv_node_free(max);
  1063. lilv_node_free(def);
  1064. lilv_node_free(homepage_p);
  1065. lilv_nodes_free(homepages);
  1066. lilv_scale_points_free(points);
  1067. lilv_node_free(control_class);
  1068. lilv_node_free(audio_class);
  1069. lilv_node_free(out_class);
  1070. lilv_node_free(in_class);
  1071. cleanup_uris();
  1072. return 1;
  1073. }
  1074. /*****************************************************************************/
  1075. static unsigned
  1076. ui_supported(const char* container_type_uri,
  1077. const char* ui_type_uri)
  1078. {
  1079. return !strcmp(container_type_uri, ui_type_uri);
  1080. }
  1081. static int
  1082. test_ui(void)
  1083. {
  1084. if (!start_bundle(MANIFEST_PREFIXES
  1085. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  1086. BUNDLE_PREFIXES PREFIX_LV2UI
  1087. ":plug a lv2:Plugin ; a lv2:CompressorPlugin ; "
  1088. PLUGIN_NAME("Test plugin") " ; "
  1089. LICENSE_GPL " ; "
  1090. "lv2:optionalFeature lv2:hardRTCapable ; "
  1091. "lv2:requiredFeature <http://lv2plug.in/ns/ext/event> ; "
  1092. "lv2ui:ui :ui , :ui2 , :ui3 , :ui4 ; "
  1093. "doap:maintainer [ foaf:name \"David Robillard\" ; "
  1094. " foaf:homepage <http://drobilla.net> ; foaf:mbox <mailto:d@drobilla.net> ] ; "
  1095. "lv2:port [ "
  1096. " a lv2:ControlPort ; a lv2:InputPort ; "
  1097. " lv2:index 0 ; lv2:symbol \"foo\" ; lv2:name \"bar\" ; "
  1098. " lv2:minimum -1.0 ; lv2:maximum 1.0 ; lv2:default 0.5 "
  1099. "] , [ "
  1100. " a lv2:ControlPort ; a lv2:InputPort ; "
  1101. " lv2:index 1 ; lv2:symbol \"bar\" ; lv2:name \"Baz\" ; "
  1102. " lv2:minimum -2.0 ; lv2:maximum 2.0 ; lv2:default 1.0 "
  1103. "] , [ "
  1104. " a lv2:ControlPort ; a lv2:OutputPort ; "
  1105. " lv2:index 2 ; lv2:symbol \"latency\" ; lv2:name \"Latency\" ; "
  1106. " lv2:portProperty lv2:reportsLatency "
  1107. "] .\n"
  1108. ":ui a lv2ui:GtkUI ; "
  1109. " lv2ui:requiredFeature lv2ui:makeResident ; "
  1110. " lv2ui:binary <ui" SHLIB_EXT "> ; "
  1111. " lv2ui:optionalFeature lv2ui:ext_presets . "
  1112. ":ui2 a lv2ui:GtkUI ; lv2ui:binary <ui2" SHLIB_EXT "> . "
  1113. ":ui3 a lv2ui:GtkUI ; lv2ui:binary <ui3" SHLIB_EXT "> . "
  1114. ":ui4 a lv2ui:GtkUI ; lv2ui:binary <ui4" SHLIB_EXT "> . "))
  1115. return 0;
  1116. init_uris();
  1117. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  1118. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  1119. TEST_ASSERT(plug);
  1120. LilvUIs* uis = lilv_plugin_get_uis(plug);
  1121. TEST_ASSERT(lilv_uis_size(uis) == 4);
  1122. const LilvUI* ui0 = lilv_uis_get(uis, lilv_uis_begin(uis));
  1123. TEST_ASSERT(ui0);
  1124. LilvNode* ui_uri = lilv_new_uri(world, "http://example.org/ui");
  1125. LilvNode* ui2_uri = lilv_new_uri(world, "http://example.org/ui3");
  1126. LilvNode* ui3_uri = lilv_new_uri(world, "http://example.org/ui4");
  1127. LilvNode* noui_uri = lilv_new_uri(world, "http://example.org/notaui");
  1128. const LilvUI* ui0_2 = lilv_uis_get_by_uri(uis, ui_uri);
  1129. TEST_ASSERT(ui0 == ui0_2);
  1130. TEST_ASSERT(lilv_node_equals(lilv_ui_get_uri(ui0_2), ui_uri));
  1131. const LilvUI* ui2 = lilv_uis_get_by_uri(uis, ui2_uri);
  1132. TEST_ASSERT(ui2 != ui0);
  1133. const LilvUI* ui3 = lilv_uis_get_by_uri(uis, ui3_uri);
  1134. TEST_ASSERT(ui3 != ui0);
  1135. const LilvUI* noui = lilv_uis_get_by_uri(uis, noui_uri);
  1136. TEST_ASSERT(noui == NULL);
  1137. const LilvNodes* classes = lilv_ui_get_classes(ui0);
  1138. TEST_ASSERT(lilv_nodes_size(classes) == 1);
  1139. LilvNode* ui_class_uri = lilv_new_uri(world,
  1140. "http://lv2plug.in/ns/extensions/ui#GtkUI");
  1141. TEST_ASSERT(lilv_node_equals(lilv_nodes_get_first(classes), ui_class_uri));
  1142. TEST_ASSERT(lilv_ui_is_a(ui0, ui_class_uri));
  1143. const LilvNode* ui_type = NULL;
  1144. TEST_ASSERT(lilv_ui_is_supported(ui0, ui_supported, ui_class_uri, &ui_type));
  1145. TEST_ASSERT(lilv_node_equals(ui_type, ui_class_uri));
  1146. const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
  1147. const LilvNode* ui_bundle_uri = lilv_ui_get_bundle_uri(ui0);
  1148. TEST_ASSERT(lilv_node_equals(plug_bundle_uri, ui_bundle_uri));
  1149. char* ui_binary_uri_str = (char*)malloc(TEST_PATH_MAX);
  1150. snprintf(ui_binary_uri_str, TEST_PATH_MAX, "%s%s",
  1151. lilv_node_as_string(plug_bundle_uri), "ui" SHLIB_EXT);
  1152. const LilvNode* ui_binary_uri = lilv_ui_get_binary_uri(ui0);
  1153. LilvNode* expected_uri = lilv_new_uri(world, ui_binary_uri_str);
  1154. TEST_ASSERT(lilv_node_equals(expected_uri, ui_binary_uri));
  1155. free(ui_binary_uri_str);
  1156. lilv_node_free(ui_class_uri);
  1157. lilv_node_free(ui_uri);
  1158. lilv_node_free(ui2_uri);
  1159. lilv_node_free(ui3_uri);
  1160. lilv_node_free(noui_uri);
  1161. lilv_node_free(expected_uri);
  1162. lilv_uis_free(uis);
  1163. cleanup_uris();
  1164. return 1;
  1165. }
  1166. /*****************************************************************************/
  1167. uint32_t atom_Float = 0;
  1168. float in = 1.0;
  1169. float out = 42.0;
  1170. static const void*
  1171. get_port_value(const char* port_symbol,
  1172. void* user_data,
  1173. uint32_t* size,
  1174. uint32_t* type)
  1175. {
  1176. if (!strcmp(port_symbol, "input")) {
  1177. *size = sizeof(float);
  1178. *type = atom_Float;
  1179. return &in;
  1180. } else if (!strcmp(port_symbol, "output")) {
  1181. *size = sizeof(float);
  1182. *type = atom_Float;
  1183. return &out;
  1184. } else {
  1185. fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n",
  1186. port_symbol);
  1187. *size = *type = 0;
  1188. return NULL;
  1189. }
  1190. }
  1191. static void
  1192. set_port_value(const char* port_symbol,
  1193. void* user_data,
  1194. const void* value,
  1195. uint32_t size,
  1196. uint32_t type)
  1197. {
  1198. if (!strcmp(port_symbol, "input")) {
  1199. in = *(const float*)value;
  1200. } else if (!strcmp(port_symbol, "output")) {
  1201. out = *(const float*)value;
  1202. } else {
  1203. fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n",
  1204. port_symbol);
  1205. }
  1206. }
  1207. char** uris = NULL;
  1208. size_t n_uris = 0;
  1209. static LV2_URID
  1210. map_uri(LV2_URID_Map_Handle handle,
  1211. const char* uri)
  1212. {
  1213. for (size_t i = 0; i < n_uris; ++i) {
  1214. if (!strcmp(uris[i], uri)) {
  1215. return i + 1;
  1216. }
  1217. }
  1218. assert(serd_uri_string_has_scheme((const uint8_t*)uri));
  1219. uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
  1220. uris[n_uris - 1] = lilv_strdup(uri);
  1221. return n_uris;
  1222. }
  1223. static const char*
  1224. unmap_uri(LV2_URID_Map_Handle handle,
  1225. LV2_URID urid)
  1226. {
  1227. if (urid > 0 && urid <= n_uris) {
  1228. return uris[urid - 1];
  1229. }
  1230. return NULL;
  1231. }
  1232. static char* temp_dir = NULL;
  1233. static char*
  1234. lilv_make_path(LV2_State_Make_Path_Handle handle,
  1235. const char* path)
  1236. {
  1237. return lilv_path_join(temp_dir, path);
  1238. }
  1239. static int
  1240. test_state(void)
  1241. {
  1242. init_world();
  1243. uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(LILV_TEST_BUNDLE);
  1244. SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true);
  1245. LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf);
  1246. LilvNode* plugin_uri = lilv_new_uri(world,
  1247. "http://example.org/lilv-test-plugin");
  1248. lilv_world_load_bundle(world, bundle_uri);
  1249. free(abs_bundle);
  1250. serd_node_free(&bundle);
  1251. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  1252. const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
  1253. TEST_ASSERT(plugin);
  1254. LV2_URID_Map map = { NULL, map_uri };
  1255. LV2_Feature map_feature = { LV2_URID_MAP_URI, &map };
  1256. LV2_URID_Unmap unmap = { NULL, unmap_uri };
  1257. LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap };
  1258. const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL };
  1259. atom_Float = map.map(map.handle, "http://lv2plug.in/ns/ext/atom#Float");
  1260. LilvNode* num = lilv_new_int(world, 5);
  1261. LilvState* nostate = lilv_state_new_from_file(world, &map, num, "/junk");
  1262. TEST_ASSERT(!nostate);
  1263. LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, features);
  1264. TEST_ASSERT(instance);
  1265. lilv_instance_activate(instance);
  1266. lilv_instance_connect_port(instance, 0, &in);
  1267. lilv_instance_connect_port(instance, 1, &out);
  1268. lilv_instance_run(instance, 1);
  1269. TEST_ASSERT(in == 1.0);
  1270. TEST_ASSERT(out == 1.0);
  1271. temp_dir = lilv_realpath("temp");
  1272. const char* file_dir = NULL;
  1273. char* copy_dir = NULL;
  1274. char* link_dir = NULL;
  1275. char* save_dir = NULL;
  1276. // Get instance state state
  1277. LilvState* state = lilv_state_new_from_instance(
  1278. plugin, instance, &map,
  1279. file_dir, copy_dir, link_dir, save_dir,
  1280. get_port_value, world, 0, NULL);
  1281. // Get another instance state
  1282. LilvState* state2 = lilv_state_new_from_instance(
  1283. plugin, instance, &map,
  1284. file_dir, copy_dir, link_dir, save_dir,
  1285. get_port_value, world, 0, NULL);
  1286. // Ensure they are equal
  1287. TEST_ASSERT(lilv_state_equals(state, state2));
  1288. // Check that we can't save a state with no URI
  1289. char* bad_state_str = lilv_state_to_string(
  1290. world, &map, &unmap, state, NULL, NULL);
  1291. TEST_ASSERT(!bad_state_str);
  1292. // Check that we can't restore the NULL string (and it doesn't crash)
  1293. LilvState* bad_state = lilv_state_new_from_string(world, &map, NULL);
  1294. TEST_ASSERT(!bad_state);
  1295. // Save state to a string
  1296. char* state1_str = lilv_state_to_string(
  1297. world, &map, &unmap, state, "http://example.org/state1", NULL);
  1298. // Restore from string
  1299. LilvState* from_str = lilv_state_new_from_string(world, &map, state1_str);
  1300. // Ensure they are equal
  1301. TEST_ASSERT(lilv_state_equals(state, from_str));
  1302. free(state1_str);
  1303. const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(state);
  1304. TEST_ASSERT(lilv_node_equals(state_plugin_uri, plugin_uri));
  1305. // Tinker with the label of the first state
  1306. TEST_ASSERT(lilv_state_get_label(state) == NULL);
  1307. lilv_state_set_label(state, "Test State Old Label");
  1308. TEST_ASSERT(!strcmp(lilv_state_get_label(state), "Test State Old Label"));
  1309. lilv_state_set_label(state, "Test State");
  1310. TEST_ASSERT(!strcmp(lilv_state_get_label(state), "Test State"));
  1311. TEST_ASSERT(!lilv_state_equals(state, state2)); // Label changed
  1312. // Run and get a new instance state (which should now differ)
  1313. lilv_instance_run(instance, 1);
  1314. LilvState* state3 = lilv_state_new_from_instance(
  1315. plugin, instance, &map,
  1316. file_dir, copy_dir, link_dir, save_dir,
  1317. get_port_value, world, 0, NULL);
  1318. TEST_ASSERT(!lilv_state_equals(state2, state3)); // num_runs changed
  1319. // Restore instance state to original state
  1320. lilv_state_restore(state2, instance, set_port_value, NULL, 0, NULL);
  1321. // Take a new snapshot and ensure it matches the set state
  1322. LilvState* state4 = lilv_state_new_from_instance(
  1323. plugin, instance, &map,
  1324. file_dir, copy_dir, link_dir, save_dir,
  1325. get_port_value, world, 0, NULL);
  1326. TEST_ASSERT(lilv_state_equals(state2, state4));
  1327. // Save state to a directory
  1328. int ret = lilv_state_save(world, &map, &unmap, state, NULL,
  1329. "state/state.lv2", "state.ttl");
  1330. TEST_ASSERT(!ret);
  1331. // Load state from directory
  1332. LilvState* state5 = lilv_state_new_from_file(world, &map, NULL,
  1333. "state/state.lv2/state.ttl");
  1334. TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy
  1335. // Save state with URI to a directory
  1336. const char* state_uri = "http://example.org/state";
  1337. ret = lilv_state_save(world, &map, &unmap, state, state_uri,
  1338. "state/state6.lv2", "state6.ttl");
  1339. TEST_ASSERT(!ret);
  1340. // Load default bundle into world and load state from it
  1341. uint8_t* state6_path = (uint8_t*)lilv_path_absolute("state/state6.lv2/");
  1342. SerdNode state6_uri = serd_node_new_file_uri(state6_path, 0, 0, true);
  1343. LilvNode* test_state_bundle = lilv_new_uri(world, (const char*)state6_uri.buf);
  1344. LilvNode* test_state_node = lilv_new_uri(world, state_uri);
  1345. lilv_world_load_bundle(world, test_state_bundle);
  1346. lilv_world_load_resource(world, test_state_node);
  1347. serd_node_free(&state6_uri);
  1348. free(state6_path);
  1349. LilvState* state6 = lilv_state_new_from_world(world, &map, test_state_node);
  1350. TEST_ASSERT(lilv_state_equals(state, state6)); // Round trip accuracy
  1351. lilv_world_unload_resource(world, test_state_node);
  1352. lilv_world_unload_bundle(world, test_state_bundle);
  1353. LilvState* state6_2 = lilv_state_new_from_world(world, &map, test_state_node);
  1354. TEST_ASSERT(!state6_2); // No longer present
  1355. lilv_state_free(state6_2);
  1356. lilv_node_free(test_state_bundle);
  1357. lilv_node_free(test_state_node);
  1358. unsetenv("LV2_STATE_BUNDLE");
  1359. // Make directories and test files support
  1360. mkdir("temp", 0700);
  1361. file_dir = temp_dir;
  1362. mkdir("files", 0700);
  1363. copy_dir = lilv_realpath("files");
  1364. mkdir("links", 0700);
  1365. link_dir = lilv_realpath("links");
  1366. LV2_State_Make_Path make_path = { NULL, lilv_make_path };
  1367. LV2_Feature make_path_feature = { LV2_STATE__makePath, &make_path };
  1368. const LV2_Feature* ffeatures[] = { &make_path_feature, &map_feature, NULL };
  1369. lilv_instance_deactivate(instance);
  1370. lilv_instance_free(instance);
  1371. instance = lilv_plugin_instantiate(plugin, 48000.0, ffeatures);
  1372. lilv_instance_activate(instance);
  1373. lilv_instance_connect_port(instance, 0, &in);
  1374. lilv_instance_connect_port(instance, 1, &out);
  1375. lilv_instance_run(instance, 1);
  1376. // Get instance state state
  1377. LilvState* fstate = lilv_state_new_from_instance(
  1378. plugin, instance, &map,
  1379. file_dir, copy_dir, link_dir, "state/fstate.lv2",
  1380. get_port_value, world, 0, ffeatures);
  1381. // Get another instance state
  1382. LilvState* fstate2 = lilv_state_new_from_instance(
  1383. plugin, instance, &map,
  1384. file_dir, copy_dir, link_dir, "state/fstate2.lv2",
  1385. get_port_value, world, 0, ffeatures);
  1386. // Should be identical
  1387. TEST_ASSERT(lilv_state_equals(fstate, fstate2));
  1388. // Run, writing more to rec file
  1389. lilv_instance_run(instance, 2);
  1390. // Get yet another instance state
  1391. LilvState* fstate3 = lilv_state_new_from_instance(
  1392. plugin, instance, &map, file_dir, copy_dir, link_dir, "state/fstate3.lv2",
  1393. get_port_value, world, 0, ffeatures);
  1394. // Should be different
  1395. TEST_ASSERT(!lilv_state_equals(fstate, fstate3));
  1396. // Save state to a directory
  1397. ret = lilv_state_save(world, &map, &unmap, fstate, NULL,
  1398. "state/fstate.lv2", "fstate.ttl");
  1399. TEST_ASSERT(!ret);
  1400. // Load state from directory
  1401. LilvState* fstate4 = lilv_state_new_from_file(world, &map, NULL,
  1402. "state/fstate.lv2/fstate.ttl");
  1403. TEST_ASSERT(lilv_state_equals(fstate, fstate4)); // Round trip accuracy
  1404. // Restore instance state to loaded state
  1405. lilv_state_restore(fstate4, instance, set_port_value, NULL, 0, ffeatures);
  1406. // Take a new snapshot and ensure it matches
  1407. LilvState* fstate5 = lilv_state_new_from_instance(
  1408. plugin, instance, &map,
  1409. file_dir, copy_dir, link_dir, "state/fstate5.lv2",
  1410. get_port_value, world, 0, ffeatures);
  1411. TEST_ASSERT(lilv_state_equals(fstate3, fstate5));
  1412. // Save state to a (different) directory again
  1413. ret = lilv_state_save(world, &map, &unmap, fstate, NULL,
  1414. "state/fstate6.lv2", "fstate6.ttl");
  1415. TEST_ASSERT(!ret);
  1416. // Reload it and ensure it's identical to the other loaded version
  1417. LilvState* fstate6 = lilv_state_new_from_file(world, &map, NULL,
  1418. "state/fstate6.lv2/fstate6.ttl");
  1419. TEST_ASSERT(lilv_state_equals(fstate4, fstate6));
  1420. // Run, changing rec file (without changing size)
  1421. lilv_instance_run(instance, 3);
  1422. // Take a new snapshot
  1423. LilvState* fstate7 = lilv_state_new_from_instance(
  1424. plugin, instance, &map,
  1425. file_dir, copy_dir, link_dir, "state/fstate7.lv2",
  1426. get_port_value, world, 0, ffeatures);
  1427. TEST_ASSERT(!lilv_state_equals(fstate6, fstate7));
  1428. // Save the changed state to a (different) directory again
  1429. ret = lilv_state_save(world, &map, &unmap, fstate7, NULL,
  1430. "state/fstate7.lv2", "fstate7.ttl");
  1431. TEST_ASSERT(!ret);
  1432. // Reload it and ensure it's changed
  1433. LilvState* fstate72 = lilv_state_new_from_file(world, &map, NULL,
  1434. "state/fstate7.lv2/fstate7.ttl");
  1435. TEST_ASSERT(lilv_state_equals(fstate72, fstate7));
  1436. TEST_ASSERT(!lilv_state_equals(fstate6, fstate72));
  1437. lilv_instance_deactivate(instance);
  1438. lilv_instance_free(instance);
  1439. lilv_node_free(num);
  1440. lilv_state_free(state);
  1441. lilv_state_free(from_str);
  1442. lilv_state_free(state2);
  1443. lilv_state_free(state3);
  1444. lilv_state_free(state4);
  1445. lilv_state_free(state5);
  1446. lilv_state_free(state6);
  1447. lilv_state_free(fstate);
  1448. lilv_state_free(fstate2);
  1449. lilv_state_free(fstate3);
  1450. lilv_state_free(fstate4);
  1451. lilv_state_free(fstate5);
  1452. lilv_state_free(fstate6);
  1453. lilv_state_free(fstate7);
  1454. lilv_state_free(fstate72);
  1455. // Free URI map
  1456. for (size_t i = 0; i < n_uris; ++i) {
  1457. free(uris[i]);
  1458. }
  1459. free(uris);
  1460. n_uris = 0;
  1461. lilv_node_free(plugin_uri);
  1462. lilv_node_free(bundle_uri);
  1463. free(link_dir);
  1464. free(copy_dir);
  1465. free(temp_dir);
  1466. cleanup_uris();
  1467. return 1;
  1468. }
  1469. /*****************************************************************************/
  1470. static int
  1471. test_bad_port_symbol(void)
  1472. {
  1473. if (!start_bundle(MANIFEST_PREFIXES
  1474. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  1475. BUNDLE_PREFIXES PREFIX_LV2EV
  1476. ":plug a lv2:Plugin ; "
  1477. PLUGIN_NAME("Test plugin") " ; "
  1478. LICENSE_GPL " ; "
  1479. "doap:homepage <http://example.org/someplug> ; "
  1480. "lv2:port [ "
  1481. " a lv2:ControlPort ; a lv2:InputPort ; "
  1482. " lv2:index 0 ; lv2:symbol \"0invalid\" ;"
  1483. " lv2:name \"Invalid\" ; "
  1484. "] ."))
  1485. return 0;
  1486. init_uris();
  1487. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  1488. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  1489. uint32_t n_ports = lilv_plugin_get_num_ports(plug);
  1490. TEST_ASSERT(n_ports == 0);
  1491. cleanup_uris();
  1492. return 1;
  1493. }
  1494. /*****************************************************************************/
  1495. static int
  1496. test_bad_port_index(void)
  1497. {
  1498. if (!start_bundle(MANIFEST_PREFIXES
  1499. ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
  1500. BUNDLE_PREFIXES PREFIX_LV2EV
  1501. ":plug a lv2:Plugin ; "
  1502. PLUGIN_NAME("Test plugin") " ; "
  1503. LICENSE_GPL " ; "
  1504. "doap:homepage <http://example.org/someplug> ; "
  1505. "lv2:port [ "
  1506. " a lv2:ControlPort ; a lv2:InputPort ; "
  1507. " lv2:index \"notaninteger\" ; lv2:symbol \"invalid\" ;"
  1508. " lv2:name \"Invalid\" ; "
  1509. "] ."))
  1510. return 0;
  1511. init_uris();
  1512. const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
  1513. const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
  1514. uint32_t n_ports = lilv_plugin_get_num_ports(plug);
  1515. TEST_ASSERT(n_ports == 0);
  1516. cleanup_uris();
  1517. return 1;
  1518. }
  1519. /*****************************************************************************/
  1520. static int
  1521. test_string(void)
  1522. {
  1523. char* s = NULL;
  1524. TEST_ASSERT(!strcmp((s = lilv_dirname("/foo/bar")), "/foo")); free(s);
  1525. TEST_ASSERT(!strcmp((s = lilv_dirname("/foo/bar/")), "/foo")); free(s);
  1526. TEST_ASSERT(!strcmp((s = lilv_dirname("/foo///bar/")), "/foo")); free(s);
  1527. TEST_ASSERT(!strcmp((s = lilv_dirname("/foo///bar//")), "/foo")); free(s);
  1528. TEST_ASSERT(!strcmp((s = lilv_dirname("foo")), ".")); free(s);
  1529. TEST_ASSERT(!strcmp((s = lilv_dirname("/foo")), "/")); free(s);
  1530. TEST_ASSERT(!strcmp((s = lilv_dirname("/")), "/")); free(s);
  1531. TEST_ASSERT(!strcmp((s = lilv_dirname("//")), "/")); free(s);
  1532. TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b", "/a/")), "b")); free(s);
  1533. TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a", "/b/c/")), "/a")); free(s);
  1534. TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/")), "../c")); free(s);
  1535. TEST_ASSERT(!strcmp((s = lilv_path_relative_to("/a/b/c", "/a/b/d/e/")), "../../c")); free(s);
  1536. TEST_ASSERT(!strcmp((s = lilv_path_join("/a", "b")), "/a/b")); free(s);
  1537. TEST_ASSERT(!strcmp((s = lilv_path_join("/a", "/b")), "/a/b")); free(s);
  1538. TEST_ASSERT(!strcmp((s = lilv_path_join("/a/", "/b")), "/a/b")); free(s);
  1539. TEST_ASSERT(!strcmp((s = lilv_path_join("/a/", "b")), "/a/b")); free(s);
  1540. TEST_ASSERT(!strcmp((s = lilv_path_join("/a", NULL)), "/a/")); free(s);
  1541. #ifndef _WIN32
  1542. setenv("LILV_TEST_1", "test", 1);
  1543. char* home_foo = lilv_strjoin(getenv("HOME"), "/foo", NULL);
  1544. TEST_ASSERT(!strcmp((s = lilv_expand("$LILV_TEST_1")), "test")); free(s);
  1545. TEST_ASSERT(!strcmp((s = lilv_expand("~")), getenv("HOME"))); free(s);
  1546. TEST_ASSERT(!strcmp((s = lilv_expand("~foo")), "~foo")); free(s);
  1547. TEST_ASSERT(!strcmp((s = lilv_expand("~/foo")), home_foo)); free(s);
  1548. TEST_ASSERT(!strcmp((s = lilv_expand("$NOT_A_VAR")), "$NOT_A_VAR")); free(s);
  1549. free(home_foo);
  1550. unsetenv("LILV_TEST_1");
  1551. #endif
  1552. return 1;
  1553. }
  1554. /*****************************************************************************/
  1555. /* add tests here */
  1556. static struct TestCase tests[] = {
  1557. TEST_CASE(utils),
  1558. TEST_CASE(value),
  1559. TEST_CASE(verify),
  1560. TEST_CASE(no_verify),
  1561. TEST_CASE(discovery),
  1562. TEST_CASE(lv2_path),
  1563. TEST_CASE(classes),
  1564. TEST_CASE(plugin),
  1565. TEST_CASE(project),
  1566. TEST_CASE(no_author),
  1567. TEST_CASE(project_no_author),
  1568. TEST_CASE(preset),
  1569. TEST_CASE(prototype),
  1570. TEST_CASE(port),
  1571. TEST_CASE(ui),
  1572. TEST_CASE(bad_port_symbol),
  1573. TEST_CASE(bad_port_index),
  1574. TEST_CASE(bad_port_index),
  1575. TEST_CASE(string),
  1576. TEST_CASE(state),
  1577. { NULL, NULL }
  1578. };
  1579. static void
  1580. run_tests(void)
  1581. {
  1582. int i;
  1583. for (i = 0; tests[i].title; i++) {
  1584. printf("*** Test %s\n", tests[i].title);
  1585. if (!tests[i].func()) {
  1586. printf("\nTest failed\n");
  1587. /* test case that wasn't able to be executed at all counts as 1 test + 1 error */
  1588. error_count++;
  1589. test_count++;
  1590. }
  1591. unload_bundle();
  1592. cleanup();
  1593. }
  1594. }
  1595. int
  1596. main(int argc, char* argv[])
  1597. {
  1598. if (argc != 1) {
  1599. printf("Syntax: %s\n", argv[0]);
  1600. return 0;
  1601. }
  1602. setenv("LANG", "C", 1);
  1603. init_tests();
  1604. run_tests();
  1605. cleanup();
  1606. printf("\n*** Test Results: %d tests, %d errors\n\n", test_count, error_count);
  1607. return error_count ? 1 : 0;
  1608. }