diff options
Diffstat (limited to 'bindings/test')
-rw-r--r-- | bindings/test/bindings_test_plugin.c | 196 | ||||
-rw-r--r-- | bindings/test/bindings_test_plugin.ttl.in | 62 | ||||
-rw-r--r-- | bindings/test/manifest.ttl.in | 7 | ||||
-rw-r--r-- | bindings/test/python/test_api.py | 290 |
4 files changed, 555 insertions, 0 deletions
diff --git a/bindings/test/bindings_test_plugin.c b/bindings/test/bindings_test_plugin.c new file mode 100644 index 0000000..3d6c763 --- /dev/null +++ b/bindings/test/bindings_test_plugin.c @@ -0,0 +1,196 @@ +/* + Copyright 2006-2011 David Robillard <d@drobilla.net> + Copyright 2006 Steve Harris <steve@plugin.org.uk> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** Include standard C headers */ +#include <math.h> +#include <stdlib.h> + +/** + LV2 headers are based on the URI of the specification they come from, so a + consistent convention can be used even for unofficial extensions. The URI + of the core LV2 specification is <http://lv2plug.in/ns/lv2core>, by + replacing `http:/` with `lv2` any header in the specification bundle can be + included, in this case `lv2.h`. +*/ +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" + +/** + The URI is the identifier for a plugin, and how the host associates this + implementation in code with its description in data. In this plugin it is + only used once in the code, but defining the plugin URI at the top of the + file is a good convention to follow. If this URI does not match that used + in the data files, the host will fail to load the plugin. +*/ +#define TEST_URI "http://example.org/lilv-bindings-test-plugin" + +/** + In code, ports are referred to by index. An enumeration of port indices + should be defined for readability. +*/ +typedef enum { + TEST_CONTROL_IN = 0, + TEST_CONTROL_OUT = 1, + TEST_AUDIO_IN = 2, + TEST_AUDIO_OUT = 3 +} PortIndex; + +/** + Every plugin defines a private structure for the plugin instance. All data + associated with a plugin instance is stored here, and is available to + every instance method. In this simple plugin, only port buffers need to be + stored, since there is no additional instance data. */ +typedef struct { + float* buf; +} Test; + +/** + The instantiate() function is called by the host to create a new plugin + instance. The host passes the plugin descriptor, sample rate, and bundle + path for plugins that need to load additional resources (e.g. waveforms). + The features parameter contains host-provided features defined in LV2 + extensions, but this simple plugin does not use any. + + This function is in the ``instantiation'' threading class, so no other + methods on this instance will be called concurrently with it. +*/ +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, + double rate, + const char* bundle_path, + const LV2_Feature* const* features) +{ + Test* test = (Test*)malloc(sizeof(Test)); + + return (LV2_Handle)test; +} + +/** + The connect_port() method is called by the host to connect a particular port + to a buffer. The plugin must store the data location, but data may not be + accessed except in run(). + + This method is in the ``audio'' threading class, and is called in the same + context as run(). +*/ +static void +connect_port(LV2_Handle instance, + uint32_t port, + void* data) +{ +} + +/** + The activate() method is called by the host to initialise and prepare the + plugin instance for running. The plugin must reset all internal state + except for buffer locations set by connect_port(). Since this plugin has + no other internal state, this method does nothing. + + This method is in the ``instantiation'' threading class, so no other + methods on this instance will be called concurrently with it. +*/ +static void +activate(LV2_Handle instance) +{ +} + +/** Process a block of audio (audio thread, must be RT safe). */ +static void +run(LV2_Handle instance, uint32_t n_samples) +{ +} + +/** + The deactivate() method is the counterpart to activate() called by the host + after running the plugin. It indicates that the host will not call run() + again until another call to activate() and is mainly useful for more + advanced plugins with ``live'' characteristics such as those with auxiliary + processing threads. As with activate(), this plugin has no use for this + information so this method does nothing. + + This method is in the ``instantiation'' threading class, so no other + methods on this instance will be called concurrently with it. +*/ +static void +deactivate(LV2_Handle instance) +{ +} + +/** + Destroy a plugin instance (counterpart to instantiate()). + + This method is in the ``instantiation'' threading class, so no other + methods on this instance will be called concurrently with it. +*/ +static void +cleanup(LV2_Handle instance) +{ + free(instance); +} + +/** + The extension_data function returns any extension data supported by the + plugin. Note that this is not an instance method, but a function on the + plugin descriptor. It is usually used by plugins to implement additional + interfaces. This plugin does not have any extension data, so this function + returns NULL. + + This method is in the ``discovery'' threading class, so no other functions + or methods in this plugin library will be called concurrently with it. +*/ +static const void* +extension_data(const char* uri) +{ + return NULL; +} + +/** + Define the LV2_Descriptor for this plugin. It is best to define descriptors + statically to avoid leaking memory and non-portable shared library + constructors and destructors to clean up properly. +*/ +static const LV2_Descriptor descriptor = { + TEST_URI, + instantiate, + connect_port, + activate, + run, + deactivate, + cleanup, + extension_data +}; + +/** + The lv2_descriptor() function is the entry point to the plugin library. The + host will load the library and call this function repeatedly with increasing + indices to find all the plugins defined in the library. The index is not an + indentifier, the URI of the returned descriptor is used to determine the + identify of the plugin. + + This method is in the ``discovery'' threading class, so no other functions + or methods in this plugin library will be called concurrently with it. +*/ +LV2_SYMBOL_EXPORT +const LV2_Descriptor* +lv2_descriptor(uint32_t index) +{ + switch (index) { + case 0: + return &descriptor; + default: + return NULL; + } +} diff --git a/bindings/test/bindings_test_plugin.ttl.in b/bindings/test/bindings_test_plugin.ttl.in new file mode 100644 index 0000000..e8323d5 --- /dev/null +++ b/bindings/test/bindings_test_plugin.ttl.in @@ -0,0 +1,62 @@ +# Lilv Bindings Test Plugin +# Copyright 2011 David Robillard <d@drobilla.net> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . + +<http://example.org/lilv-bindings-test-plugin> + a lv2:Plugin ; + doap:name "Lilv Bindings Test" ; + doap:license <http://opensource.org/licenses/isc> ; + lv2:optionalFeature lv2:hardRTCapable ; + ui:ui <http://example.org/lilv-bindings-test-plugin-ui> ; + lv2:port [ + a lv2:InputPort , + lv2:ControlPort ; + lv2:index 0 ; + lv2:symbol "input" ; + lv2:name "Input" ; + lv2:default 0.5 ; + lv2:minimum 0.0 ; + lv2:maximum 1.0 ; + lv2:scalePoint [ rdfs:label "off" ; rdf:value 0.0 ] ; + lv2:scalePoint [ rdfs:label "on" ; rdf:value 1.0 ] ; + ] , [ + a lv2:OutputPort , + lv2:ControlPort ; + lv2:index 1 ; + lv2:symbol "output" ; + lv2:name "Output" + ] , [ + a lv2:AudioPort , + lv2:InputPort ; + lv2:index 2 ; + lv2:symbol "audio_input" ; + lv2:name "Audio Input" ; + ] , [ + a lv2:AudioPort , + lv2:OutputPort ; + lv2:index 3 ; + lv2:symbol "audio_output" ; + lv2:name "Audio Output" ; + ] . + +<http://example.org/lilv-bindings-test-plugin-ui> + a ui:GtkUI ; + ui:binary <TODO> . diff --git a/bindings/test/manifest.ttl.in b/bindings/test/manifest.ttl.in new file mode 100644 index 0000000..9cc7fa8 --- /dev/null +++ b/bindings/test/manifest.ttl.in @@ -0,0 +1,7 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://example.org/lilv-bindings-test-plugin> + a lv2:Plugin ; + lv2:binary <bindings_test_plugin@SHLIB_EXT@> ; + rdfs:seeAlso <bindings_test_plugin.ttl> . diff --git a/bindings/test/python/test_api.py b/bindings/test/python/test_api.py new file mode 100644 index 0000000..f594013 --- /dev/null +++ b/bindings/test/python/test_api.py @@ -0,0 +1,290 @@ +# Copyright 2016 David Robillard <d@drobilla.net> +# Copyright 2013 Kaspar Emanuel <kaspar.emanuel@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import lilv +import unittest +import os + +location = "file://" + os.getcwd() + "/bindings/bindings_test_plugin.lv2/" + +class NodeTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + def testNodes(self): + aint = self.world.new_int(1) + aint2 = self.world.new_int(1) + aint3 = self.world.new_int(3) + afloat = self.world.new_float(2.0) + atrue = self.world.new_bool(True) + afalse = self.world.new_bool(False) + auri = self.world.new_uri("http://example.org") + afile = self.world.new_file_uri(None, "/foo/bar") + astring = self.world.new_string("hello") + self.assertEqual(auri.get_turtle_token(), '<http://example.org>') + self.assertTrue(aint.is_int()) + self.assertTrue(afloat.is_float()) + self.assertTrue(auri.is_uri()) + self.assertTrue(astring.is_string()) + self.assertTrue(astring.is_literal()) + self.assertFalse(auri.is_blank()) + self.assertTrue(int(aint) == 1) + self.assertTrue(float(afloat) == 2.0) + self.assertTrue(bool(atrue)) + self.assertFalse(bool(afalse)) + self.assertEqual(afile.get_path(), "/foo/bar") + self.assertTrue(aint == aint2) + self.assertTrue(aint != aint3) + self.assertTrue(aint != afloat) + with self.assertRaises(ValueError): + int(atrue) + with self.assertRaises(ValueError): + float(aint) + with self.assertRaises(ValueError): + bool(astring) + +class UriTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.world.load_all(); + def testInvalidURI(self): + self.plugin_uri = self.world.new_uri("invalid_uri") + self.assertIsNone(self.plugin_uri) + def testNonExistentURI(self): + self.plugin_uri = self.world.new_uri("exist:does_not") + self.plugin = self.world.get_all_plugins().get_by_uri(self.plugin_uri) + self.assertEqual(self.plugin, None) + def testPortTypes(self): + self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_INPUT_PORT)) + def testPortTypes2(self): + self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT)) + def testPortTypes3(self): + self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_AUDIO_PORT)) + def testPortTypes4(self): + self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_CONTROL_PORT)) + +class PluginClassTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + def testPluginClasses(self): + pclass = self.world.get_plugin_class() + self.assertIsNotNone(pclass) + self.assertIsNone(pclass.get_parent_uri()) + self.assertIsNotNone(pclass.get_uri()) + self.assertIsNotNone(pclass.get_label()) + self.assertEqual(str(pclass.get_uri()), str(pclass)) + for i in pclass.get_children(): + self.assertIsNotNone(i) + self.assertIsNotNone(i.get_uri()) + self.assertIsNotNone(i.get_label()) + +class PluginClassesTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.world.load_all() + def testPluginClasses(self): + classes = self.world.get_plugin_classes() + pclass = self.world.get_plugin_class() + self.assertIsNotNone(classes) + self.assertIsNotNone(pclass) + self.assertTrue(pclass in classes) + self.assertTrue(pclass.get_uri() in classes) + self.assertGreater(len(classes), 1) + self.assertIsNotNone(classes[0]) + self.assertIsNotNone(classes[pclass.get_uri()]) + +class LoadTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.bundle_uri = self.world.new_uri(location) + self.world.load_specifications() + self.world.load_plugin_classes() + def tearDown(self): + del self.world + def testLoadUnload(self): + self.world.load_bundle(self.bundle_uri) + plugins = self.world.get_all_plugins() + plugin = plugins.get(plugins.begin()) + self.world.load_resource(plugin) + self.world.unload_resource(plugin) + self.world.unload_bundle(self.bundle_uri) + +class PluginTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.world.set_option(lilv.OPTION_FILTER_LANG, self.world.new_bool(True)) + self.bundle_uri = self.world.new_uri(location) + self.assertIsNotNone(self.bundle_uri, "Invalid URI: '" + location + "'") + self.world.load_bundle(self.bundle_uri) + self.plugins = self.world.get_all_plugins() + self.plugin = self.plugins.get(self.plugins.begin()) + self.assertTrue(self.plugin.verify()) + self.assertTrue(self.plugin in self.plugins) + self.assertTrue(self.plugin.get_uri() in self.plugins) + self.assertEqual(self.plugins[self.plugin.get_uri()], self.plugin) + self.assertIsNotNone(self.plugin, msg="Test plugin not found at location: '" + location + "'") + self.assertEqual(location, str(self.plugin.get_bundle_uri())) + self.plugin_uri = self.plugin.get_uri() + self.assertEqual(self.plugin.get_uri(), self.plugin_uri, "URI equality broken") + self.instance = lilv.Instance(self.plugin, 48000, None) + self.assertIsNotNone(self.instance) + self.lv2_InputPort = self.world.new_uri(lilv.LILV_URI_INPUT_PORT) + self.lv2_OutputPort = self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT) + self.lv2_AudioPort = self.world.new_uri(lilv.LILV_URI_AUDIO_PORT) + self.lv2_ControlPort = self.world.new_uri(lilv.LILV_URI_CONTROL_PORT) + def testGetters(self): + self.assertIsNotNone(self.plugin.get_bundle_uri()) + self.assertGreater(len(self.plugin.get_data_uris()), 0) + self.assertIsNotNone(self.plugin.get_library_uri()) + self.assertTrue(self.plugin.get_name().is_string()) + self.assertTrue(self.plugin.get_class().get_uri().is_uri()) + self.assertEqual(len(self.plugin.get_value(self.world.ns.doap.license)), 1) + licenses = self.plugin.get_value(self.world.ns.doap.license) + features = self.plugin.get_value(self.world.ns.lv2.optionalFeature) + self.assertEqual(len(licenses), 1) + self.assertTrue(licenses[0] in licenses) + with self.assertRaises(IndexError): + self.assertIsNone(licenses[len(licenses)]) + self.assertEqual(len(licenses) + len(features), + len(licenses.merge(features))) + self.assertEqual(licenses.get(licenses.begin()), self.world.new_uri('http://opensource.org/licenses/isc')) + self.assertEqual(licenses[0], licenses.get(licenses.begin())) + self.assertTrue(self.plugin.has_feature(self.world.ns.lv2.hardRTCapable)) + self.assertEqual(len(self.plugin.get_supported_features()), 1) + self.assertEqual(len(self.plugin.get_optional_features()), 1) + self.assertEqual(len(self.plugin.get_required_features()), 0) + self.assertFalse(self.plugin.has_extension_data(self.world.new_uri('http://example.org/nope'))) + self.assertEqual(len(self.plugin.get_extension_data()), 0) + self.assertEqual(len(self.plugin.get_extension_data()), 0) + self.assertFalse(self.plugin.has_latency()) + self.assertIsNone(self.plugin.get_latency_port_index()) + def testPorts(self): + self.assertEqual(self.plugin.get_num_ports(), 4) + self.assertIsNotNone(self.plugin.get_port(0)) + self.assertIsNotNone(self.plugin.get_port(1)) + self.assertIsNotNone(self.plugin.get_port(2)) + self.assertIsNotNone(self.plugin.get_port(3)) + self.assertIsNone(self.plugin.get_port_by_index(4)) + self.assertIsNotNone(self.plugin.get_port("input")) + self.assertIsNotNone(self.plugin.get_port("output")) + self.assertIsNotNone(self.plugin.get_port("audio_input")) + self.assertIsNotNone(self.plugin.get_port("audio_output")) + self.assertIsNone(self.plugin.get_port_by_symbol("nonexistent")) + self.assertIsNone(self.plugin.get_port_by_designation(self.world.ns.lv2.InputPort, self.world.ns.lv2.control)) + self.assertIsNone(self.plugin.get_project()) + self.assertIsNone(self.plugin.get_author_name()) + self.assertIsNone(self.plugin.get_author_email()) + self.assertIsNone(self.plugin.get_author_homepage()) + self.assertFalse(self.plugin.is_replaced()) + self.assertEqual(0, len(self.plugin.get_related(self.world.new_uri("http://example.org/Type")))) + self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_AudioPort)) + port = self.plugin.get_port("input") + self.assertTrue(port.get_node().is_blank()) + self.assertEqual(0, port.get(self.world.ns.lv2.index)) + self.assertEqual(1, len(port.get_value(self.world.ns.lv2.symbol))) + self.assertEqual(port.get_value(self.world.ns.lv2.symbol)[0], "input") + self.assertFalse(port.has_property(self.world.ns.lv2.latency)) + self.assertFalse(port.supports_event(self.world.ns.midi.MidiEvent)) + self.assertEqual(0, port.get_index()) + self.assertEqual("input", port.get_symbol()) + self.assertEqual("Input", port.get_name()) + self.assertEqual([self.world.ns.lv2.ControlPort, self.world.ns.lv2.InputPort], + list(port.get_classes())) + self.assertTrue(port.is_a(self.world.ns.lv2.ControlPort)) + self.assertFalse(port.is_a(self.world.ns.lv2.AudioPort)) + self.assertEquals((0.5, 0.0, 1.0), port.get_range()) + self.assertEquals(0, len(port.get_properties())) + def testScalePoints(self): + port = self.plugin.get_port("input") + points = port.get_scale_points() + self.assertEqual(points[0].get_label(), "off") + self.assertEqual(points[0].get_value(), 0.0) + self.assertEqual(points[1].get_label(), "on") + self.assertEqual(points[1].get_value(), 1.0) + def testPortCount(self): + self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_AudioPort)) + self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_ControlPort)) + self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_AudioPort)) + self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_ControlPort)) + +class QueryTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.world.load_all() + self.bundle_uri = self.world.new_uri(location) + self.world.load_bundle(self.bundle_uri) + self.plugins = self.world.get_all_plugins() + self.plugin = self.plugins.get(self.plugins.begin()) + def testNamespaces(self): + self.assertEqual(self.world.ns.lv2, "http://lv2plug.in/ns/lv2core#") + self.assertEqual(self.world.ns.lv2.Plugin, "http://lv2plug.in/ns/lv2core#Plugin") + def testQuery(self): + self.assertTrue(self.world.ask(None, + self.world.ns.rdf.type, + self.world.ns.lv2.Plugin)) + self.assertLess(0, len(self.world.find_nodes(None, + self.world.ns.rdf.type, + self.world.ns.lv2.Plugin))) + self.assertEqual(self.plugin.get_uri(), self.world.get(None, + self.world.ns.rdf.type, + self.world.ns.lv2.Plugin)) + +class InstanceTests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.bundle_uri = self.world.new_uri(location) + self.world.load_bundle(self.bundle_uri) + self.plugins = self.world.get_all_plugins() + self.plugin = self.plugins[0] + self.instance = lilv.Instance(self.plugin, 48000) + self.assertEqual(self.plugin.get_uri(), self.instance.get_uri()) + self.assertIsNone(self.instance.get_extension_data(self.world.new_uri("http://example.org/ext"))) + self.assertIsNone(self.instance.get_extension_data("http://example.org/ext")) + def testRun(self): + import numpy + n_samples = 100 + buf = numpy.zeros(n_samples) + with self.assertRaises(Exception): + self.instance.connect_port(0, "hello") + self.instance.connect_port(0, None) + self.instance.connect_port(0, None) + self.instance.connect_port(2, buf) + self.instance.connect_port(3, buf) + self.instance.activate() + self.instance.run(n_samples) + self.instance.deactivate() + +class UITests(unittest.TestCase): + def setUp(self): + self.world = lilv.World() + self.bundle_uri = self.world.new_uri(location) + self.world.load_bundle(self.bundle_uri) + self.plugins = self.world.get_all_plugins() + self.plugin = self.plugins[0] + def testUI(self): + uis = self.plugin.get_uis() + ui_uri = self.world.new_uri('http://example.org/lilv-bindings-test-plugin-ui') + self.assertEqual(1, len(uis)) + self.assertEqual(str(uis[0]), str(ui_uri)) + self.assertEqual(uis[0], str(ui_uri)) + self.assertEqual(uis[0].get_uri(), ui_uri) + self.assertEqual(uis[0].get_bundle_uri(), self.bundle_uri) + self.assertEqual(uis[0].get_binary_uri(), str(self.bundle_uri) + "TODO") + self.assertEqual(uis[uis[0].get_uri()], uis[0]) + self.assertTrue(uis[0].is_a(self.world.ns.ui.GtkUI)) + self.assertTrue(uis[0] in uis) + self.assertTrue(uis[0].get_uri() in uis) + self.assertEqual([self.world.ns.ui.GtkUI], list(uis[0].get_classes())) + for ui in uis: + print(ui) |