1# Copyright 2016-2019 David Robillard <d@drobilla.net>
2# Copyright 2013 Kaspar Emanuel <kaspar.emanuel@gmail.com>
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
16import lilv
17import os
18import sys
19import unittest
20
21path = os.path.abspath("bindings/bindings_test_plugin.lv2/")
22
23if sys.version_info[0] == 2:
24    import urllib
25    import urlparse
26
27    location = urlparse.urljoin("file:", urllib.pathname2url(path) + "/")
28else:
29    from urllib.parse import urljoin
30    from urllib.request import pathname2url
31
32    location = urljoin("file:", pathname2url(path) + "/")
33
34
35class NodeTests(unittest.TestCase):
36    def setUp(self):
37        self.world = lilv.World()
38
39    def testNodes(self):
40        aint = self.world.new_int(1)
41        aint2 = self.world.new_int(1)
42        aint3 = self.world.new_int(3)
43        afloat = self.world.new_float(2.0)
44        atrue = self.world.new_bool(True)
45        afalse = self.world.new_bool(False)
46        auri = self.world.new_uri("http://example.org")
47        afile = self.world.new_file_uri(None, "/foo/bar")
48        astring = self.world.new_string("hello")
49        self.assertEqual(auri.get_turtle_token(), "<http://example.org>")
50        self.assertTrue(aint.is_int())
51        self.assertTrue(afloat.is_float())
52        self.assertTrue(auri.is_uri())
53        self.assertTrue(astring.is_string())
54        self.assertTrue(astring.is_literal())
55        self.assertFalse(auri.is_blank())
56        self.assertTrue(int(aint) == 1)
57        self.assertTrue(float(afloat) == 2.0)
58        self.assertTrue(bool(atrue))
59        self.assertFalse(bool(afalse))
60        self.assertEqual(afile.get_path(), "/foo/bar")
61        self.assertTrue(aint == aint2)
62        self.assertTrue(aint != aint3)
63        self.assertTrue(aint != afloat)
64        with self.assertRaises(ValueError):
65            int(atrue)
66        with self.assertRaises(ValueError):
67            float(aint)
68        with self.assertRaises(ValueError):
69            bool(astring)
70
71
72class UriTests(unittest.TestCase):
73    def setUp(self):
74        self.world = lilv.World()
75        self.world.load_all()
76
77    def testInvalidURI(self):
78        with self.assertRaises(ValueError):
79            self.plugin_uri = self.world.new_uri("invalid_uri")
80
81    def testNonExistentURI(self):
82        self.plugin_uri = self.world.new_uri("exist:does_not")
83        self.plugin = self.world.get_all_plugins().get_by_uri(self.plugin_uri)
84        self.assertEqual(self.plugin, None)
85
86    def testPortTypes(self):
87        self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_INPUT_PORT))
88
89    def testPortTypes2(self):
90        self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT))
91
92    def testPortTypes3(self):
93        self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_AUDIO_PORT))
94
95    def testPortTypes4(self):
96        self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_CONTROL_PORT))
97
98
99class PluginClassTests(unittest.TestCase):
100    def setUp(self):
101        self.world = lilv.World()
102
103    def testPluginClasses(self):
104        pclass = self.world.get_plugin_class()
105        self.assertIsNotNone(pclass)
106        self.assertIsNone(pclass.get_parent_uri())
107        self.assertIsNotNone(pclass.get_uri())
108        self.assertIsNotNone(pclass.get_label())
109        self.assertEqual(str(pclass.get_uri()), str(pclass))
110        for i in pclass.get_children():
111            self.assertIsNotNone(i)
112            self.assertIsNotNone(i.get_uri())
113            self.assertIsNotNone(i.get_label())
114
115
116class PluginClassesTests(unittest.TestCase):
117    def setUp(self):
118        self.world = lilv.World()
119        self.world.load_all()
120
121    def testPluginClasses(self):
122        classes = self.world.get_plugin_classes()
123        pclass = self.world.get_plugin_class()
124        self.assertIsNotNone(classes)
125        self.assertIsNotNone(pclass)
126        self.assertTrue(pclass in classes)
127        self.assertTrue(pclass.get_uri() in classes)
128        self.assertGreater(len(classes), 1)
129        self.assertIsNotNone(classes[0])
130        self.assertIsNotNone(classes[pclass.get_uri()])
131        with self.assertRaises(KeyError):
132            classes["http://example.org/notaclass"].get_uri()
133
134
135class LoadTests(unittest.TestCase):
136    def setUp(self):
137        self.world = lilv.World()
138        self.bundle_uri = self.world.new_uri(location)
139        self.world.load_specifications()
140        self.world.load_plugin_classes()
141
142    def testLoadUnload(self):
143        self.world.load_bundle(self.bundle_uri)
144        plugins = self.world.get_all_plugins()
145        plugin = plugins.get(plugins.begin())
146        self.world.load_resource(plugin)
147        self.world.unload_resource(plugin)
148        self.world.unload_bundle(self.bundle_uri)
149
150
151class PluginTests(unittest.TestCase):
152    def setUp(self):
153        self.world = lilv.World()
154        self.world.set_option(
155            lilv.OPTION_FILTER_LANG, self.world.new_bool(True)
156        )
157        self.bundle_uri = self.world.new_uri(location)
158        self.assertIsNotNone(
159            self.bundle_uri, "Invalid URI: '" + location + "'"
160        )
161        self.world.load_bundle(self.bundle_uri)
162        self.plugins = self.world.get_all_plugins()
163        self.plugin = self.plugins.get(self.plugins.begin())
164        self.assertTrue(self.plugin.verify())
165        self.assertTrue(self.plugin in self.plugins)
166        self.assertTrue(self.plugin.get_uri() in self.plugins)
167        self.assertEqual(self.plugins[self.plugin.get_uri()], self.plugin)
168        with self.assertRaises(KeyError):
169            self.plugins["http://example.org/notaplugin"].get_uri()
170
171        self.assertIsNotNone(
172            self.plugin,
173            msg="Test plugin not found at location: '" + location + "'",
174        )
175        self.assertEqual(location, str(self.plugin.get_bundle_uri()))
176        self.plugin_uri = self.plugin.get_uri()
177        self.assertEqual(
178            self.plugin.get_uri(), self.plugin_uri, "URI equality broken"
179        )
180        self.lv2_InputPort = self.world.new_uri(lilv.LILV_URI_INPUT_PORT)
181        self.lv2_OutputPort = self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT)
182        self.lv2_AudioPort = self.world.new_uri(lilv.LILV_URI_AUDIO_PORT)
183        self.lv2_ControlPort = self.world.new_uri(lilv.LILV_URI_CONTROL_PORT)
184
185    def testGetters(self):
186        self.assertEqual(
187            self.world.get_symbol(self.plugin), "lilv_bindings_test_plugin"
188        )
189        self.assertIsNotNone(self.plugin.get_bundle_uri())
190        self.assertGreater(len(self.plugin.get_data_uris()), 0)
191        self.assertIsNotNone(self.plugin.get_library_uri())
192        self.assertTrue(self.plugin.get_name().is_string())
193        self.assertTrue(self.plugin.get_class().get_uri().is_uri())
194        self.assertEqual(
195            len(self.plugin.get_value(self.world.ns.doap.license)), 1
196        )
197        licenses = self.plugin.get_value(self.world.ns.doap.license)
198        features = self.plugin.get_value(self.world.ns.lv2.optionalFeature)
199        self.assertEqual(len(licenses), 1)
200        self.assertTrue(licenses[0] in licenses)
201        with self.assertRaises(IndexError):
202            self.assertIsNone(licenses[len(licenses)])
203        self.assertEqual(
204            len(licenses) + len(features), len(licenses.merge(features))
205        )
206        self.assertEqual(
207            licenses.get(licenses.begin()),
208            self.world.new_uri("http://opensource.org/licenses/isc"),
209        )
210        self.assertEqual(licenses[0], licenses.get(licenses.begin()))
211        self.assertTrue(
212            self.plugin.has_feature(self.world.ns.lv2.hardRTCapable)
213        )
214        self.assertEqual(len(self.plugin.get_supported_features()), 1)
215        self.assertEqual(len(self.plugin.get_optional_features()), 1)
216        self.assertEqual(len(self.plugin.get_required_features()), 0)
217        self.assertFalse(
218            self.plugin.has_extension_data(
219                self.world.new_uri("http://example.org/nope")
220            )
221        )
222        self.assertEqual(len(self.plugin.get_extension_data()), 0)
223        self.assertEqual(len(self.plugin.get_extension_data()), 0)
224        self.assertFalse(self.plugin.has_latency())
225        self.assertIsNone(self.plugin.get_latency_port_index())
226
227    def testPorts(self):
228        self.assertEqual(self.plugin.get_num_ports(), 4)
229        self.assertIsNotNone(self.plugin.get_port(0))
230        self.assertIsNotNone(self.plugin.get_port(1))
231        self.assertIsNotNone(self.plugin.get_port(2))
232        self.assertIsNotNone(self.plugin.get_port(3))
233        self.assertIsNone(self.plugin.get_port_by_index(4))
234        self.assertIsNotNone(self.plugin.get_port("input"))
235        self.assertIsNotNone(self.plugin.get_port("output"))
236        self.assertIsNotNone(self.plugin.get_port("audio_input"))
237        self.assertIsNotNone(self.plugin.get_port("audio_output"))
238        self.assertIsNone(self.plugin.get_port_by_symbol("nonexistent"))
239        self.assertIsNone(
240            self.plugin.get_port_by_designation(
241                self.world.ns.lv2.InputPort, self.world.ns.lv2.control
242            )
243        )
244        self.assertIsNone(self.plugin.get_project())
245        self.assertIsNone(self.plugin.get_author_name())
246        self.assertIsNone(self.plugin.get_author_email())
247        self.assertIsNone(self.plugin.get_author_homepage())
248        self.assertFalse(self.plugin.is_replaced())
249        self.assertEqual(
250            0,
251            len(
252                self.plugin.get_related(
253                    self.world.new_uri("http://example.org/Type")
254                )
255            ),
256        )
257        self.assertEqual(
258            1,
259            self.plugin.get_num_ports_of_class(
260                self.lv2_InputPort, self.lv2_AudioPort
261            ),
262        )
263        port = self.plugin.get_port("input")
264        self.assertEqual(self.world.get_symbol(port), "input")
265        self.assertTrue(port.get_node().is_blank())
266        self.assertEqual(0, port.get(self.world.ns.lv2.index))
267        self.assertEqual(1, len(port.get_value(self.world.ns.lv2.symbol)))
268        self.assertEqual(port.get_value(self.world.ns.lv2.symbol)[0], "input")
269        self.assertFalse(port.has_property(self.world.ns.lv2.latency))
270        self.assertFalse(port.supports_event(self.world.ns.midi.MidiEvent))
271        self.assertEqual(0, port.get_index())
272        self.assertEqual("input", port.get_symbol())
273        self.assertEqual("Input", port.get_name())
274        self.assertEqual(
275            [
276                str(self.world.ns.lv2.ControlPort),
277                str(self.world.ns.lv2.InputPort),
278            ],
279            sorted(list(map(str, port.get_classes()))),
280        )
281        self.assertTrue(port.is_a(self.world.ns.lv2.ControlPort))
282        self.assertFalse(port.is_a(self.world.ns.lv2.AudioPort))
283        self.assertEqual((0.5, 0.0, 1.0), port.get_range())
284        self.assertEqual(0, len(port.get_properties()))
285
286    def testScalePoints(self):
287        port = self.plugin.get_port("input")
288        points = port.get_scale_points()
289        point_dict = {
290            float(points[0].get_value()): points[0].get_label(),
291            float(points[1].get_value()): points[1].get_label(),
292        }
293
294        self.assertEqual(point_dict, {0.0: "off", 1.0: "on"})
295
296    def testPortCount(self):
297        self.assertEqual(
298            1,
299            self.plugin.get_num_ports_of_class(
300                self.lv2_OutputPort, self.lv2_AudioPort
301            ),
302        )
303        self.assertEqual(
304            1,
305            self.plugin.get_num_ports_of_class(
306                self.lv2_OutputPort, self.lv2_ControlPort
307            ),
308        )
309        self.assertEqual(
310            1,
311            self.plugin.get_num_ports_of_class(
312                self.lv2_InputPort, self.lv2_AudioPort
313            ),
314        )
315        self.assertEqual(
316            1,
317            self.plugin.get_num_ports_of_class(
318                self.lv2_InputPort, self.lv2_ControlPort
319            ),
320        )
321
322
323class QueryTests(unittest.TestCase):
324    def setUp(self):
325        self.world = lilv.World()
326        self.world.load_all()
327        self.bundle_uri = self.world.new_uri(location)
328        self.world.load_bundle(self.bundle_uri)
329        self.plugins = self.world.get_all_plugins()
330        self.plugin = self.plugins.get(self.plugins.begin())
331
332    def testNamespaces(self):
333        self.assertEqual(self.world.ns.lv2, "http://lv2plug.in/ns/lv2core#")
334        self.assertEqual(
335            self.world.ns.lv2.Plugin, "http://lv2plug.in/ns/lv2core#Plugin"
336        )
337
338    def testQuery(self):
339        self.assertTrue(
340            self.world.ask(
341                None, self.world.ns.rdf.type, self.world.ns.lv2.Plugin
342            )
343        )
344        self.assertLess(
345            0,
346            len(
347                self.world.find_nodes(
348                    None, self.world.ns.rdf.type, self.world.ns.lv2.Plugin
349                )
350            ),
351        )
352        self.assertEqual(
353            self.plugin.get_uri(),
354            self.world.get(
355                None, self.world.ns.rdf.type, self.world.ns.lv2.Plugin
356            ),
357        )
358
359
360class InstanceTests(unittest.TestCase):
361    def setUp(self):
362        self.world = lilv.World()
363        self.bundle_uri = self.world.new_uri(location)
364        self.world.load_bundle(self.bundle_uri)
365        self.plugins = self.world.get_all_plugins()
366        self.plugin = self.plugins[0]
367        self.instance = lilv.Instance(self.plugin, 48000)
368        self.assertEqual(self.plugin.get_uri(), self.instance.get_uri())
369        self.assertIsNone(
370            self.instance.get_extension_data(
371                self.world.new_uri("http://example.org/ext")
372            )
373        )
374        self.assertIsNone(
375            self.instance.get_extension_data("http://example.org/ext")
376        )
377
378    def testRun(self):
379        try:
380            import numpy
381        except ImportError:
382            sys.stderr.write("warning: Missing numpy, not testing instance\n")
383            return
384
385        n_samples = 100
386        buf = numpy.zeros(n_samples)
387        with self.assertRaises(Exception):
388            self.instance.connect_port(0, "hello")
389        self.instance.connect_port(0, None)
390        self.instance.connect_port(0, None)
391        self.instance.connect_port(2, buf)
392        self.instance.connect_port(3, buf)
393        self.instance.activate()
394        self.instance.run(n_samples)
395        self.instance.deactivate()
396
397
398class UITests(unittest.TestCase):
399    def setUp(self):
400        self.world = lilv.World()
401        self.bundle_uri = self.world.new_uri(location)
402        self.world.load_bundle(self.bundle_uri)
403        self.plugins = self.world.get_all_plugins()
404        self.plugin = self.plugins[0]
405
406    def testUI(self):
407        uis = self.plugin.get_uis()
408        ui_uri = self.world.new_uri(
409            "http://example.org/lilv-bindings-test-plugin-ui"
410        )
411        self.assertEqual(1, len(uis))
412        self.assertEqual(str(uis[0]), str(ui_uri))
413        with self.assertRaises(KeyError):
414            uis["http://example.org/notaui"].get_uri()
415
416        self.assertEqual(uis[0], str(ui_uri))
417        self.assertEqual(uis[0].get_uri(), ui_uri)
418        self.assertEqual(uis[0].get_bundle_uri(), self.bundle_uri)
419        self.assertEqual(
420            uis[0].get_binary_uri(), str(self.bundle_uri) + "TODO"
421        )
422        self.assertEqual(uis[uis[0].get_uri()], uis[0])
423        self.assertTrue(uis[0].is_a(self.world.ns.ui.GtkUI))
424        self.assertTrue(uis[0] in uis)
425        self.assertTrue(uis[0].get_uri() in uis)
426        self.assertEqual([self.world.ns.ui.GtkUI], list(uis[0].get_classes()))
427