1 /*
2   Copyright 2007-2020 David Robillard <d@drobilla.net>
3 
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 
8   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 #undef NDEBUG
18 
19 #include "lilv_test_utils.h"
20 
21 #include "lilv/lilv.h"
22 
23 #include <assert.h>
24 #include <stdbool.h>
25 #include <string.h>
26 
27 static const char* const plugin_ttl = "\
28 @prefix lv2ev: <http://lv2plug.in/ns/ext/event#> . \n\
29 :plug\n\
30 	a lv2:Plugin ;\n\
31 	doap:name \"Test plugin\" ;\n\
32 	doap:homepage <http://example.org/someplug> ;\n\
33 	lv2:port [\n\
34 		a lv2:ControlPort ;\n\
35 		a lv2:InputPort ;\n\
36 		lv2:index 0 ;\n\
37 		lv2:symbol \"foo\" ;\n\
38 		lv2:name \"store\" ;\n\
39 		lv2:name \"Laden\"@de-de ;\n\
40 		lv2:name \"Geschaeft\"@de-at ;\n\
41 		lv2:name \"tienda\"@es ;\n\
42 		rdfs:comment \"comment\"@en , \"commentaires\"@fr ;\n\
43 		lv2:portProperty lv2:integer ;\n\
44 		lv2:minimum -1.0 ;\n\
45 		lv2:maximum 1.0 ;\n\
46 		lv2:default 0.5 ;\n\
47 		lv2:scalePoint [\n\
48 			rdfs:label \"Sin\";\n\
49 			rdf:value 3\n\
50 		] ;\n\
51 		lv2:scalePoint [\n\
52 			rdfs:label \"Cos\";\n\
53 			rdf:value 4\n\
54 		]\n\
55 	] , [\n\
56 		a lv2:EventPort ;\n\
57 		a lv2:InputPort ;\n\
58 		lv2:index 1 ;\n\
59 		lv2:symbol \"event_in\" ;\n\
60 		lv2:name \"Event Input\" ;\n\
61 		lv2ev:supportsEvent <http://example.org/event> ;\n\
62 		atom:supports <http://example.org/atomEvent>\n\
63 	] , [\n\
64 		a lv2:AudioPort ;\n\
65 		a lv2:InputPort ;\n\
66 		lv2:index 2 ;\n\
67 		lv2:symbol \"audio_in\" ;\n\
68 		lv2:name \"Audio Input\" ;\n\
69 	] , [\n\
70 		a lv2:AudioPort ;\n\
71 		a lv2:OutputPort ;\n\
72 		lv2:index 3 ;\n\
73 		lv2:symbol \"audio_out\" ;\n\
74 		lv2:name \"Audio Output\" ;\n\
75 	] .\n";
76 
77 int
main(void)78 main(void)
79 {
80   LilvTestEnv* const env   = lilv_test_env_new();
81   LilvWorld* const   world = env->world;
82 
83   if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
84     return 1;
85   }
86 
87   const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
88   const LilvPlugin*  plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
89   assert(plug);
90 
91   LilvNode*       psym = lilv_new_string(world, "foo");
92   const LilvPort* p    = lilv_plugin_get_port_by_index(plug, 0);
93   const LilvPort* p2   = lilv_plugin_get_port_by_symbol(plug, psym);
94   lilv_node_free(psym);
95   assert(p != NULL);
96   assert(p2 != NULL);
97   assert(p == p2);
98 
99   LilvNode*       nopsym = lilv_new_string(world, "thisaintnoportfoo");
100   const LilvPort* p3     = lilv_plugin_get_port_by_symbol(plug, nopsym);
101   assert(p3 == NULL);
102   lilv_node_free(nopsym);
103 
104   // Try getting an invalid property
105   LilvNode*  num     = lilv_new_int(world, 1);
106   LilvNodes* nothing = lilv_port_get_value(plug, p, num);
107   assert(!nothing);
108   lilv_node_free(num);
109 
110   LilvNode* audio_class =
111     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
112   LilvNode* control_class =
113     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
114   LilvNode* in_class =
115     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
116   LilvNode* out_class =
117     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
118 
119   assert(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
120   assert(lilv_plugin_get_num_ports(plug) == 4);
121   assert(lilv_port_is_a(plug, p, control_class));
122   assert(lilv_port_is_a(plug, p, in_class));
123   assert(!lilv_port_is_a(plug, p, audio_class));
124 
125   LilvNodes* port_properties = lilv_port_get_properties(plug, p);
126   assert(lilv_nodes_size(port_properties) == 1);
127   lilv_nodes_free(port_properties);
128 
129   // Untranslated name (current locale is set to "C" in main)
130   assert(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
131   LilvNode* name = lilv_port_get_name(plug, p);
132   assert(!strcmp(lilv_node_as_string(name), "store"));
133   lilv_node_free(name);
134 
135   // Exact language match
136   set_env("LANG", "de_DE");
137   name = lilv_port_get_name(plug, p);
138   assert(!strcmp(lilv_node_as_string(name), "Laden"));
139   lilv_node_free(name);
140 
141   // Exact language match (with charset suffix)
142   set_env("LANG", "de_AT.utf8");
143   name = lilv_port_get_name(plug, p);
144   assert(!strcmp(lilv_node_as_string(name), "Geschaeft"));
145   lilv_node_free(name);
146 
147   // Partial language match (choose value translated for different country)
148   set_env("LANG", "de_CH");
149   name = lilv_port_get_name(plug, p);
150   assert((!strcmp(lilv_node_as_string(name), "Laden")) ||
151          (!strcmp(lilv_node_as_string(name), "Geschaeft")));
152   lilv_node_free(name);
153 
154   // Partial language match (choose country-less language tagged value)
155   set_env("LANG", "es_MX");
156   name = lilv_port_get_name(plug, p);
157   assert(!strcmp(lilv_node_as_string(name), "tienda"));
158   lilv_node_free(name);
159 
160   // No language match (choose untranslated value)
161   set_env("LANG", "cn");
162   name = lilv_port_get_name(plug, p);
163   assert(!strcmp(lilv_node_as_string(name), "store"));
164   lilv_node_free(name);
165 
166   // Invalid language
167   set_env("LANG", "1!");
168   name = lilv_port_get_name(plug, p);
169   assert(!strcmp(lilv_node_as_string(name), "store"));
170   lilv_node_free(name);
171 
172   set_env("LANG", "en_CA.utf-8");
173 
174   // Language tagged value with no untranslated values
175   LilvNode*  rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
176   LilvNodes* comments     = lilv_port_get_value(plug, p, rdfs_comment);
177   assert(
178     !strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)), "comment"));
179   LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
180   assert(!strcmp(lilv_node_as_string(comment), "comment"));
181   lilv_node_free(comment);
182   lilv_nodes_free(comments);
183 
184   set_env("LANG", "fr");
185 
186   comments = lilv_port_get_value(plug, p, rdfs_comment);
187   assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
188                  "commentaires"));
189   lilv_nodes_free(comments);
190 
191   set_env("LANG", "cn");
192 
193   comments = lilv_port_get_value(plug, p, rdfs_comment);
194   assert(!comments);
195   lilv_nodes_free(comments);
196 
197   lilv_node_free(rdfs_comment);
198 
199   set_env("LANG", "C"); // Reset locale
200 
201   LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
202   assert(lilv_scale_points_size(points) == 2);
203 
204   LilvIter*             sp_iter = lilv_scale_points_begin(points);
205   const LilvScalePoint* sp0     = lilv_scale_points_get(points, sp_iter);
206   assert(sp0);
207   sp_iter                   = lilv_scale_points_next(points, sp_iter);
208   const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
209   assert(sp1);
210 
211   assert(
212     ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Sin") &&
213       lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3) &&
214      (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Cos") &&
215       lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4)) ||
216     ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Cos") &&
217       lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4) &&
218      (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Sin") &&
219       lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
220 
221   LilvNode* homepage_p =
222     lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
223   LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
224   assert(lilv_nodes_size(homepages) == 1);
225   assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
226                  "http://example.org/someplug"));
227 
228   LilvNode* min = NULL;
229   LilvNode* max = NULL;
230   LilvNode* def = NULL;
231   lilv_port_get_range(plug, p, &def, &min, &max);
232   assert(def);
233   assert(min);
234   assert(max);
235   assert(lilv_node_as_float(def) == 0.5);
236   assert(lilv_node_as_float(min) == -1.0);
237   assert(lilv_node_as_float(max) == 1.0);
238 
239   LilvNode* integer_prop =
240     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
241   LilvNode* toggled_prop =
242     lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
243 
244   assert(lilv_port_has_property(plug, p, integer_prop));
245   assert(!lilv_port_has_property(plug, p, toggled_prop));
246 
247   const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
248 
249   LilvNode* event_type   = lilv_new_uri(world, "http://example.org/event");
250   LilvNode* event_type_2 = lilv_new_uri(world, "http://example.org/otherEvent");
251   LilvNode* atom_event   = lilv_new_uri(world, "http://example.org/atomEvent");
252   assert(lilv_port_supports_event(plug, ep, event_type));
253   assert(!lilv_port_supports_event(plug, ep, event_type_2));
254   assert(lilv_port_supports_event(plug, ep, atom_event));
255 
256   LilvNode*  name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
257   LilvNodes* names  = lilv_port_get_value(plug, p, name_p);
258   assert(lilv_nodes_size(names) == 1);
259   assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "store"));
260   lilv_nodes_free(names);
261 
262   LilvNode* true_val  = lilv_new_bool(world, true);
263   LilvNode* false_val = lilv_new_bool(world, false);
264 
265   assert(!lilv_node_equals(true_val, false_val));
266 
267   lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
268   names = lilv_port_get_value(plug, p, name_p);
269   assert(lilv_nodes_size(names) == 4);
270   lilv_nodes_free(names);
271   lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
272 
273   lilv_node_free(false_val);
274   lilv_node_free(true_val);
275 
276   names = lilv_port_get_value(plug, ep, name_p);
277   assert(lilv_nodes_size(names) == 1);
278   assert(
279     !strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "Event Input"));
280 
281   const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
282 
283   assert(lilv_port_is_a(plug, ap_in, in_class));
284   assert(!lilv_port_is_a(plug, ap_in, out_class));
285   assert(lilv_port_is_a(plug, ap_in, audio_class));
286   assert(!lilv_port_is_a(plug, ap_in, control_class));
287 
288   const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
289 
290   assert(lilv_port_is_a(plug, ap_out, out_class));
291   assert(!lilv_port_is_a(plug, ap_out, in_class));
292   assert(lilv_port_is_a(plug, ap_out, audio_class));
293   assert(!lilv_port_is_a(plug, ap_out, control_class));
294 
295   assert(lilv_plugin_get_num_ports_of_class(
296            plug, control_class, in_class, NULL) == 1);
297   assert(
298     lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) == 1);
299   assert(lilv_plugin_get_num_ports_of_class(
300            plug, audio_class, out_class, NULL) == 1);
301 
302   lilv_nodes_free(names);
303   lilv_node_free(name_p);
304 
305   lilv_node_free(integer_prop);
306   lilv_node_free(toggled_prop);
307   lilv_node_free(event_type);
308   lilv_node_free(event_type_2);
309   lilv_node_free(atom_event);
310 
311   lilv_node_free(min);
312   lilv_node_free(max);
313   lilv_node_free(def);
314 
315   lilv_node_free(homepage_p);
316   lilv_nodes_free(homepages);
317 
318   lilv_scale_points_free(points);
319   lilv_node_free(control_class);
320   lilv_node_free(audio_class);
321   lilv_node_free(out_class);
322   lilv_node_free(in_class);
323 
324   delete_bundle(env);
325   lilv_test_env_free(env);
326 
327   return 0;
328 }
329