Esempio n. 1
0
 def setup(self):
     super(TestOntologyTool, self).setup()
     # ot => OntologyTool
     self.ot = OntologyTool(u"_sanity_check_ns")
     # Add a couple keywords to this other namespace in the
     # hope that this will make it easier to catch problems
     # involving code which ignores the namespace
     self.keyword_new(description=u"In the sanity check NS.")
     self.keyword_new(name=u"testKW2",
                      description=u"In the sanity check NS.")
     self.ot.namespace = u"testNS"
Esempio n. 2
0
 def setup(self):
     super(TestOntologyTool, self).setup()
     # ot => OntologyTool
     self.ot = OntologyTool(u"_sanity_check_ns")
     # Add a couple keywords to this other namespace in the
     # hope that this will make it easier to catch problems
     # involving code which ignores the namespace
     self.keyword_new(description=u"In the sanity check NS.")
     self.keyword_new(name=u"testKW2", description=u"In the sanity check NS.")
     self.ot.namespace = u"testNS"
Esempio n. 3
0
 def setup(self):
     super(TestDotTool, self).setup()
     self.ot = OntologyTool(u'gv_test_ns')
     self.gc = GraphChecker()
Esempio n. 4
0
class TestDotTool(PyolsDBTest):
    def setup(self):
        super(TestDotTool, self).setup()
        self.ot = OntologyTool(u'gv_test_ns')
        self.gc = GraphChecker()

    def testSimpleGraph(self):
        for kw in (u"kw0", u"kw1", u"kw2"):
            self.ot.addKeyword(kw)
            self.gc.addKeyword(kw)

        for rel in (u"rel0", u"rel1"):
            self.ot.addRelation(rel)

        db.flush()

        for kwr in ((u"kw0", u"rel0", u"kw1"),
                    (u"kw0", u"rel1", u"kw2"),
                    (u"kw2", u"rel0", u"kw0")):
            self.ot.addKeywordRelationship(*kwr)
            self.gc.addKeywordRelationship(*kwr)

        db.flush()

        dot = self.ot.getOntologyDotSource()
        self.gc.checkDot(dot)

    def testLongNames(self):
        long = u'this string has more than 30 characters'
        long_trunc = long[:27] + '...'
        short = u'this string has exactly 26'

        self.ot.addKeyword(long)
        self.gc.addKeyword(long_trunc)
        self.ot.addKeyword(short)
        self.gc.addKeyword(short)

        self.ot.addRelation(long)
        self.ot.addRelation(short)

        db.flush()

        self.ot.addKeywordRelationship(long, long, long)
        self.gc.addKeywordRelationship(long_trunc, long_trunc, long_trunc)

        self.ot.addKeywordRelationship(short, short, short)
        self.gc.addKeywordRelationship(short, short, short)

        self.ot.addKeywordRelationship(long, short, short)
        self.gc.addKeywordRelationship(long_trunc, short, short)

        self.ot.addKeywordRelationship(short, long, short)
        self.gc.addKeywordRelationship(short, long_trunc, short)

        db.flush()
        dot = self.ot.getOntologyDotSource()
        self.gc.checkDot(dot)
Esempio n. 5
0
class TestOntologyTool(PyolsDBTest):
    def setup(self):
        super(TestOntologyTool, self).setup()
        # ot => OntologyTool
        self.ot = OntologyTool(u"_sanity_check_ns")
        # Add a couple keywords to this other namespace in the
        # hope that this will make it easier to catch problems
        # involving code which ignores the namespace
        self.keyword_new(description=u"In the sanity check NS.")
        self.keyword_new(name=u"testKW2", description=u"In the sanity check NS.")
        self.ot.namespace = u"testNS"

    def addKeyword(self, name=u"testKW", disambiguation=u"dis", description=u"desc"):
        """ Add a keyword using a call to the OT. """
        kw = self.ot.addKeyword(name, disambiguation=disambiguation, description=description)
        db.flush()  # Mimic the flush that hapens at the end of each request
        return kw

    def keyword_new(self, name=u"testKW", disambiguation=u"dis", description=u"desc"):
        """ Add a keyword using Keyword.new. """
        kw = Keyword.new(
            namespace=self.ot._namespace, name=name, disambiguation=disambiguation, description=description
        )
        kw.flush()
        return kw

    def addRelation(self, name=u"testRel", weight=1.0, types=[], inverse=None):
        newRel = self.ot.addRelation(name=name, weight=weight, types=types, inverse=inverse)
        db.flush()  # Simulate a web request -- flush
        return newRel

    def relation_new(self, name=u"testRel", **kwargs):
        newRel = Relation.new(name=name, namespace=self.ot._namespace, **kwargs)
        db.flush()
        return newRel

    def checkKeyword(self, kw, name=u"testKW", disambiguation=u"dis", description=u"desc"):
        ok_(kw)
        assert_equal(kw.disambiguation, disambiguation)
        assert_equal(kw.description, description)
        assert_equal(kw.namespace.name, self.ot.namespace)

    def keyword_getby(self, name=u"testKW"):
        """ Query for a keyword using Keyword.get_by. """
        return Keyword.get_by(name=name, namespace=self.ot._namespace)

    def testChangeNamespace(self):
        nn = u"newNamespace"  # nn => newNamespace
        self.ot.namespace = nn
        ok_(Namespace.get_by(name=nn))
        assert_equal(self.ot.namespace, nn)

        # Keywords added should be part of the new namespace
        self.addKeyword()
        k = self.keyword_getby()
        assert_equal(k.namespace.name, nn)

        # And we should be able to go back to the old NS without an issue
        self.ot.namespace = u"testNS"
        assert_equal(self.ot.namespace, "testNS")

    def testCopyNamespace(self):
        # This test can be simple because the hard testing is done
        # on Namespace.copy_to
        nn = self.ot.copyNamespace(u"new_ns")
        assert_equal(nn.name, u"new_ns")

    def testAdd(self):
        kw0 = self.addKeyword(u"kw0")
        kw1 = self.addKeyword(u"kw1")
        rel = self.relation_new()
        self.ot.addKeywordRelationship(kw0.name, rel.name, kw1.name)
        db.flush()

        kwr = list(KeywordRelationship.query_by())[0]
        ok_(kwr)
        assert_equal(kwr.left.name, kw0.name)
        assert_equal(kwr.right.name, kw1.name)
        assert_equal(kwr.relation.name, rel.name)

        self.ot.namespace = u"new_ns"
        ok_(not self.keyword_getby(u"kw0"))
        self.addKeyword(name=u"kw0")
        ok_(self.keyword_getby(name=u"kw0"))

    def testAddDuplicateInstance(self):
        kw = self.addKeyword()
        kw = self.addKeyword()
        # These should both succeed

        self.ot.addKeywordAssociation(kw.name, u"0")
        db.flush()
        self.ot.addKeywordAssociation(kw.name, u"1")
        db.flush()

        # The original keyword association should have been updated.
        ka = KeywordAssociation.get_by(path=u"1")
        ok_(ka)
        assert_equal(ka.keyword.name, kw.name)

    def testAddRelation(self):
        for rel in self.ot.queryRelations():
            rel.remove()
        # Remove the default relations
        db.flush()

        relA = self.addRelation(name=u"relA")
        relB = self.addRelation(name=u"relB", inverse=relA.name)
        assert_equal(relA, relB.inverse)

        # Ensure that the inverse is properly created
        relC = self.addRelation(name=u"relC", types=["transitive"], weight=0.5, inverse=u"relD")
        relD = self.ot.getRelation(u"relD")
        ok_(relD)
        assert_equal(relD.inverse, relC)
        assert_equal(relD.types, ["transitive"])
        assert_equal(relD.weight, 0.5)

        # Test that adding a duplicate relation will cause an update.
        self.addRelation(name=u"relD", weight=0)
        relD = self.ot.getRelation(u"relD")
        assert_equal(relD.inverse, None)
        assert_equal(relD.types, [])
        assert_equal(relD.weight, 0)

        # Tests for removing and querying relations are also snuck in here
        self.ot.delRelation(u"relD")
        db.flush()
        assert_raises(PyolsNotFound, self.ot.getRelation, name=u"relD")

        assert_equal(set(["relA", "relB", "relC"]), set([r.name for r in self.ot.queryRelations()]))

    def testGetKeyword(self):
        self.keyword_new()
        k = self.ot.getKeyword(u"testKW")
        self.checkKeyword(k)

        self.ot.namespace = u"newNamespace"
        assert_raises(PyolsNotFound, self.ot.getKeyword, u"testKW")

    @raises(PyolsNotFound)
    def testGetInvalidKeyword(self):
        self.ot.getKeyword(u"bad keyword")

    def testDelKeyword(self):
        self.keyword_new()
        self.ot.delKeyword(u"testKW")
        db.flush()
        # The keyword should not exist
        assert_equal(self.keyword_getby(), None)

    def testUpdate(self):
        kw = rpcify(self.keyword_new())
        kw["name"] = u"new_name"
        self.ot.updateKeyword(kw)
        db.flush()
        ok_(self.keyword_getby(name=u"new_name"))

        rel = rpcify(self.relation_new())
        rel["inverse"] = rel["name"]
        rel["name"] = u"new_name"
        rel["bad_value"] = u"ohnoes!"
        self.ot.updateRelation(rel)
        db.flush()
        rel = Relation.get_by(name=u"new_name")
        ok_(rel)
        assert_equal(rel.inverse, rel)
        # It should be impossible to set "private" members this way
        ok_(not getattr(rel, "bad_value", None))

    @raises(PyolsException)
    def testUpdateWithoutID(self):
        rel = rpcify(self.relation_new())
        del rel["id"]
        self.ot.updateRelation(rel)

    @raises(PyolsNotFound)
    def testUpdateNonexistantRelation(self):
        self.ot.updateRelation({"id": -1})

    @raises(PyolsNotFound)
    def testUpdateInvalidInverse(self):
        rel = rpcify(self.relation_new())
        rel["inverse"] = u"bad"
        self.ot.updateRelation(rel)

    @raises(PyolsNotFound)
    def testDelKeywordDoesntExist(self):
        self.ot.delKeyword(u"IdontExist")

    def testDeletingThings(self):
        # These are not exhaustive tests -- see test_model.py for those
        kw0 = self.keyword_new(u"kw0")
        kw1 = self.keyword_new(u"kw1")
        kw2 = self.keyword_new(u"kw2")
        rel = self.relation_new()
        kwr = KeywordRelationship.new(left=kw0, relation=rel, right=kw1)
        kwa = KeywordAssociation.new(keyword=kw2, path=u"/asdf/123")
        db.flush()

        # Removing the keyword should kill the KWA
        self.ot.delKeyword(kw2.name)
        db.flush()
        assert_equal(KeywordAssociation.get_by(keyword=kw2), None)

        # Deleting the relationship should cause the KWR to be deleted
        # but the keywords should stick around
        self.ot.delRelation(rel.name)
        db.flush()
        ok_(self.keyword_getby(name=kw0.name))
        ok_(self.keyword_getby(name=kw1.name))
        assert_equal(KeywordRelationship.get_by(left=kw0), None)

    def testGenericQuery(self):
        # A simple little test
        assert_equal(list(self.ot.queryKeywords()), [])
        for x in range(3):
            self.keyword_new(name=u"testKW%d" % x, description=u"kwd%d" % x)
            kws = list(self.ot.queryKeywords())
            assert_equal(len(kws), x + 1)

        # Before we get any further, check that the definition
        # of Keyword has not changed
        assert_equal(Keyword.list_fields()[3].name, "description")

        assert_equal(len(list(self.ot.queryKeywords(None, None, u"kwd0"))), 1)
        assert_equal(len(list(self.ot.queryKeywords(u"testKW0"))), 1)

    def testGetRelatedKeywords(self):
        rs = {}
        rs["k"] = self.relation_new(u"kind of", weight=0.5, types=["symmetric"])
        rs["s"] = self.relation_new(u"synonym of", weight=1, types=["symmetric"])
        rs["b"] = self.relation_new(u"breed of", weight=0.75)
        kwrs = (
            ("animal", "kind of", "living thing"),
            ("dog", "kind of", "animal"),
            ("cat", "kind of", "animal"),
            ("cachorro", "synonym of", "dog"),
            ("egyptian", "breed of", "cat"),
            ("collie", "breed of", "dog"),
        )
        ks = {}
        for kwr in kwrs:
            for kw in (kwr[0], kwr[2]):
                if kw in ks:
                    continue
                ks[kw] = self.keyword_new(unicode(kw))
            KeywordRelationship.new(left=ks[kwr[0]], relation=rs[kwr[1][0]], right=ks[kwr[2]])
        db.flush()

        queries = (
            (("animal", 0.5, None), {"cat": 0.5, "living thing": 0.5, "dog": 0.5, "animal": 1, "cachorro": 0.5}),
            (("collie", 0.75, None), {"collie": 1, "dog": 0.75, "cachorro": 0.75}),
            (
                ("collie", 0, None),
                {
                    "collie": 1,
                    "living thing": 0.1875,
                    "egyptian": 0.140625,
                    "dog": 0.75,
                    "cat": 0.1875,
                    "animal": 0.375,
                    "cachorro": 0.75,
                },
            ),
            (("living thing", 0, [u"kind of"]), {"living thing": 1, "dog": 0.25, "animal": 0.5, "cat": 0.25}),
            (("dog", 0, [u"synonym of", u"breed of"]), {"collie": 0.75, "dog": 1, "cachorro": 1}),
        )

        for (query, expected) in queries:
            actual = self.ot.getRelatedKeywords(unicode(query[0]), cutoff=query[1], links=query[2])
            assert_equal(actual, expected)
Esempio n. 6
0
File: owl.py Progetto: nsi-iff/pyOLS
    for rel in oi.getRelations():
        ot.addRelation(**rel)
    db.flush()

    for kw in oi.getKeywords():
        ot.addKeyword(**kw)
    db.flush()

    for kwr in oi.getKeywordRelationshps():
        ot.addKeywordRelationship(*kwr)
    db.flush()

if __name__ == "__main__":
    # This is a bit of simple test code because I don't want to formalize
    # any unit tests before the input format is decided upon
    from pyols.tests import setup_test_db
    from pyols.api import OntologyTool
    from pyols import graphviz
    from pyols.model import *
    from pyols.config import config

    setup_test_db()
    ot = OntologyTool(u"foo")
    ot.importOWL(open("../doc/beer.owl").read())

    config['graphviz_path'] = '/usr/bin/'
    open("/tmp/x.png", "w").write(ot.getOntologyGraph().data)

    print ot.exportOWL()
Esempio n. 7
0
class TestOntologyTool(PyolsDBTest):
    def setup(self):
        super(TestOntologyTool, self).setup()
        # ot => OntologyTool
        self.ot = OntologyTool(u"_sanity_check_ns")
        # Add a couple keywords to this other namespace in the
        # hope that this will make it easier to catch problems
        # involving code which ignores the namespace
        self.keyword_new(description=u"In the sanity check NS.")
        self.keyword_new(name=u"testKW2",
                         description=u"In the sanity check NS.")
        self.ot.namespace = u"testNS"

    def addKeyword(self,
                   name=u"testKW",
                   disambiguation=u"dis",
                   description=u"desc"):
        """ Add a keyword using a call to the OT. """
        kw = self.ot.addKeyword(name,
                                disambiguation=disambiguation,
                                description=description)
        db.flush()  # Mimic the flush that hapens at the end of each request
        return kw

    def keyword_new(self,
                    name=u"testKW",
                    disambiguation=u"dis",
                    description=u"desc"):
        """ Add a keyword using Keyword.new. """
        kw = Keyword.new(namespace=self.ot._namespace,
                         name=name,
                         disambiguation=disambiguation,
                         description=description)
        kw.flush()
        return kw

    def addRelation(self, name=u"testRel", weight=1.0, types=[], inverse=None):
        newRel = self.ot.addRelation(name=name,
                                     weight=weight,
                                     types=types,
                                     inverse=inverse)
        db.flush()  # Simulate a web request -- flush
        return newRel

    def relation_new(self, name=u"testRel", **kwargs):
        newRel = Relation.new(name=name,
                              namespace=self.ot._namespace,
                              **kwargs)
        db.flush()
        return newRel

    def checkKeyword(self,
                     kw,
                     name=u"testKW",
                     disambiguation=u"dis",
                     description=u"desc"):
        ok_(kw)
        assert_equal(kw.disambiguation, disambiguation)
        assert_equal(kw.description, description)
        assert_equal(kw.namespace.name, self.ot.namespace)

    def keyword_getby(self, name=u"testKW"):
        """ Query for a keyword using Keyword.get_by. """
        return Keyword.get_by(name=name, namespace=self.ot._namespace)

    def testChangeNamespace(self):
        nn = u"newNamespace"  # nn => newNamespace
        self.ot.namespace = nn
        ok_(Namespace.get_by(name=nn))
        assert_equal(self.ot.namespace, nn)

        # Keywords added should be part of the new namespace
        self.addKeyword()
        k = self.keyword_getby()
        assert_equal(k.namespace.name, nn)

        # And we should be able to go back to the old NS without an issue
        self.ot.namespace = u"testNS"
        assert_equal(self.ot.namespace, "testNS")

    def testCopyNamespace(self):
        # This test can be simple because the hard testing is done
        # on Namespace.copy_to
        nn = self.ot.copyNamespace(u"new_ns")
        assert_equal(nn.name, u"new_ns")

    def testAdd(self):
        kw0 = self.addKeyword(u"kw0")
        kw1 = self.addKeyword(u"kw1")
        rel = self.relation_new()
        self.ot.addKeywordRelationship(kw0.name, rel.name, kw1.name)
        db.flush()

        kwr = list(KeywordRelationship.query_by())[0]
        ok_(kwr)
        assert_equal(kwr.left.name, kw0.name)
        assert_equal(kwr.right.name, kw1.name)
        assert_equal(kwr.relation.name, rel.name)

        self.ot.namespace = u"new_ns"
        ok_(not self.keyword_getby(u"kw0"))
        self.addKeyword(name=u"kw0")
        ok_(self.keyword_getby(name=u"kw0"))

    def testAddDuplicateInstance(self):
        kw = self.addKeyword()
        kw = self.addKeyword()
        # These should both succeed

        self.ot.addKeywordAssociation(kw.name, u'0')
        db.flush()
        self.ot.addKeywordAssociation(kw.name, u'1')
        db.flush()

        # The original keyword association should have been updated.
        ka = KeywordAssociation.get_by(path=u'1')
        ok_(ka)
        assert_equal(ka.keyword.name, kw.name)

    def testAddRelation(self):
        for rel in self.ot.queryRelations():
            rel.remove()
        # Remove the default relations
        db.flush()

        relA = self.addRelation(name=u"relA")
        relB = self.addRelation(name=u"relB", inverse=relA.name)
        assert_equal(relA, relB.inverse)

        # Ensure that the inverse is properly created
        relC = self.addRelation(name=u"relC",
                                types=['transitive'],
                                weight=0.5,
                                inverse=u"relD")
        relD = self.ot.getRelation(u"relD")
        ok_(relD)
        assert_equal(relD.inverse, relC)
        assert_equal(relD.types, ['transitive'])
        assert_equal(relD.weight, 0.5)

        # Test that adding a duplicate relation will cause an update.
        self.addRelation(name=u"relD", weight=0)
        relD = self.ot.getRelation(u"relD")
        assert_equal(relD.inverse, None)
        assert_equal(relD.types, [])
        assert_equal(relD.weight, 0)

        # Tests for removing and querying relations are also snuck in here
        self.ot.delRelation(u"relD")
        db.flush()
        assert_raises(PyolsNotFound, self.ot.getRelation, name=u"relD")

        assert_equal(set(["relA", "relB", "relC"]),
                     set([r.name for r in self.ot.queryRelations()]))

    def testGetKeyword(self):
        self.keyword_new()
        k = self.ot.getKeyword(u"testKW")
        self.checkKeyword(k)

        self.ot.namespace = u"newNamespace"
        assert_raises(PyolsNotFound, self.ot.getKeyword, u"testKW")

    @raises(PyolsNotFound)
    def testGetInvalidKeyword(self):
        self.ot.getKeyword(u"bad keyword")

    def testDelKeyword(self):
        self.keyword_new()
        self.ot.delKeyword(u"testKW")
        db.flush()
        # The keyword should not exist
        assert_equal(self.keyword_getby(), None)

    def testUpdate(self):
        kw = rpcify(self.keyword_new())
        kw['name'] = u'new_name'
        self.ot.updateKeyword(kw)
        db.flush()
        ok_(self.keyword_getby(name=u'new_name'))

        rel = rpcify(self.relation_new())
        rel['inverse'] = rel['name']
        rel['name'] = u'new_name'
        rel['bad_value'] = u'ohnoes!'
        self.ot.updateRelation(rel)
        db.flush()
        rel = Relation.get_by(name=u'new_name')
        ok_(rel)
        assert_equal(rel.inverse, rel)
        # It should be impossible to set "private" members this way
        ok_(not getattr(rel, 'bad_value', None))

    @raises(PyolsException)
    def testUpdateWithoutID(self):
        rel = rpcify(self.relation_new())
        del rel['id']
        self.ot.updateRelation(rel)

    @raises(PyolsNotFound)
    def testUpdateNonexistantRelation(self):
        self.ot.updateRelation({'id': -1})

    @raises(PyolsNotFound)
    def testUpdateInvalidInverse(self):
        rel = rpcify(self.relation_new())
        rel['inverse'] = u'bad'
        self.ot.updateRelation(rel)

    @raises(PyolsNotFound)
    def testDelKeywordDoesntExist(self):
        self.ot.delKeyword(u"IdontExist")

    def testDeletingThings(self):
        # These are not exhaustive tests -- see test_model.py for those
        kw0 = self.keyword_new(u"kw0")
        kw1 = self.keyword_new(u"kw1")
        kw2 = self.keyword_new(u"kw2")
        rel = self.relation_new()
        kwr = KeywordRelationship.new(left=kw0, relation=rel, right=kw1)
        kwa = KeywordAssociation.new(keyword=kw2, path=u"/asdf/123")
        db.flush()

        # Removing the keyword should kill the KWA
        self.ot.delKeyword(kw2.name)
        db.flush()
        assert_equal(KeywordAssociation.get_by(keyword=kw2), None)

        # Deleting the relationship should cause the KWR to be deleted
        # but the keywords should stick around
        self.ot.delRelation(rel.name)
        db.flush()
        ok_(self.keyword_getby(name=kw0.name))
        ok_(self.keyword_getby(name=kw1.name))
        assert_equal(KeywordRelationship.get_by(left=kw0), None)

    def testGenericQuery(self):
        # A simple little test
        assert_equal(list(self.ot.queryKeywords()), [])
        for x in range(3):
            self.keyword_new(name=u"testKW%d" % x, description=u"kwd%d" % x)
            kws = list(self.ot.queryKeywords())
            assert_equal(len(kws), x + 1)

        # Before we get any further, check that the definition
        # of Keyword has not changed
        assert_equal(Keyword.list_fields()[3].name, 'description')

        assert_equal(len(list(self.ot.queryKeywords(None, None, u'kwd0'))), 1)
        assert_equal(len(list(self.ot.queryKeywords(u'testKW0'))), 1)

    def testGetRelatedKeywords(self):
        rs = {}
        rs['k'] = self.relation_new(u"kind of",
                                    weight=0.5,
                                    types=['symmetric'])
        rs['s'] = self.relation_new(u"synonym of",
                                    weight=1,
                                    types=['symmetric'])
        rs['b'] = self.relation_new(u"breed of", weight=0.75)
        kwrs = (("animal", "kind of", "living thing"),
                ("dog", "kind of", "animal"), ("cat", "kind of", "animal"),
                ("cachorro", "synonym of", "dog"),
                ("egyptian", "breed of", "cat"), ("collie", "breed of", "dog"))
        ks = {}
        for kwr in kwrs:
            for kw in (kwr[0], kwr[2]):
                if kw in ks: continue
                ks[kw] = self.keyword_new(unicode(kw))
            KeywordRelationship.new(left=ks[kwr[0]],
                                    relation=rs[kwr[1][0]],
                                    right=ks[kwr[2]])
        db.flush()

        queries = (
            (("animal", 0.5, None), {
                'cat': 0.5,
                'living thing': 0.5,
                'dog': 0.5,
                'animal': 1,
                'cachorro': 0.5
            }),
            (("collie", 0.75, None), {
                'collie': 1,
                'dog': 0.75,
                'cachorro': 0.75
            }),
            (("collie", 0, None), {
                'collie': 1,
                'living thing': 0.1875,
                'egyptian': 0.140625,
                'dog': 0.75,
                'cat': 0.1875,
                'animal': 0.375,
                'cachorro': 0.75
            }),
            (("living thing", 0, [u"kind of"]), {
                'living thing': 1,
                'dog': 0.25,
                'animal': 0.5,
                'cat': 0.25
            }),
            (("dog", 0, [u"synonym of", u"breed of"]), {
                'collie': 0.75,
                'dog': 1,
                'cachorro': 1
            }),
        )

        for (query, expected) in queries:
            actual = self.ot.getRelatedKeywords(unicode(query[0]),
                                                cutoff=query[1],
                                                links=query[2])
            assert_equal(actual, expected)