示例#1
0
class TestValidateFilterSyntax(TestBaseWithExceptionTests):
    """
    Tests filter syntax support.
    """
    def setUp(self):
        """
        Creates test data.
        """
        super(TestValidateFilterSyntax, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        self._mockgun.create("Shot", {"code": "shot"})

    def test_filter_array_or_dict(self):
        """
        Ensure that arrays and dictionaries are supported for filters.
        """
        # This should not throw.
        self._mockgun.find("Shot", [{
            "filter_operator": "any",
            "filters": [["code", "is", "shot"]]
        }, ["code", "is", "shot"]])

        # We can't have not dict/list values for filters however.
        self.assertRaisesRegexp(
            ShotgunError,
            "Filters can only be lists or dictionaries, not int.",
            lambda: self._mockgun.find("Shot", [1]))
示例#2
0
class TestEntityFieldComparison(TestBaseWithExceptionTests):
    """
    Checks if entity fields comparison work.
    """

    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._project_link = self._mockgun.create("Project", {"name": "project", "archived": False})

        # This entity will ensure that a populated link field will be comparable.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_project", "project": self._project_link, }
        )

        # This entity will ensure that an unpopulated link field will be comparable.
        self._mockgun.create("PipelineConfiguration", {"code": "without_project"})

    def test_searching_for_none_entity_field(self):
        """
        Ensures that comparison with None work.
        """

        items = self._mockgun.find("PipelineConfiguration", [["project", "is", None]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration", [["project", "is_not", None]])
        self.assertEqual(len(items), 1)

    def test_searching_for_initialized_entity_field(self):
        """
        Ensures that comparison with an entity works.
        """
        items = self._mockgun.find("PipelineConfiguration", [["project", "is", self._project_link]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration", [["project", "is_not", self._project_link]])
        self.assertEqual(len(items), 1)

    def test_find_entity_with_none_link(self):
        """
        Make sure that we can search for sub entity fields on entities that have the field not set.
        """
        # The pipeline configuration without_project doesn't have the project field set, so we're expecting
        # it to not be returned here.
        items = self._mockgun.find("PipelineConfiguration", [["project.Project.archived", "is", False]])
        self.assertEqual(len(items), 1)
        self.assertEqual(items[0]["id"], self._project_link["id"])
class TestEntityFieldComparison(TestBaseWithExceptionTests):
    """
    Checks if entity fields comparison work.
    """

    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._project_link = self._mockgun.create("Project", {"name": "project", "archived": False})

        # This entity will ensure that a populated link field will be comparable.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_project", "project": self._project_link, }
        )

        # This entity will ensure that an unpopulated link field will be comparable.
        self._mockgun.create("PipelineConfiguration", {"code": "without_project"})

    def test_searching_for_none_entity_field(self):
        """
        Ensures that comparison with None work.
        """

        items = self._mockgun.find("PipelineConfiguration", [["project", "is", None]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration", [["project", "is_not", None]])
        self.assertEqual(len(items), 1)

    def test_searching_for_initialized_entity_field(self):
        """
        Ensures that comparison with an entity works.
        """
        items = self._mockgun.find("PipelineConfiguration", [["project", "is", self._project_link]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration", [["project", "is_not", self._project_link]])
        self.assertEqual(len(items), 1)

    def test_find_entity_with_none_link(self):
        """
        Make sure that we can search for sub entity fields on entities that have the field not set.
        """
        # The pipeline configuration without_project doesn't have the project field set, so we're expecting
        # it to not be returned here.
        items = self._mockgun.find("PipelineConfiguration", [["project.Project.archived", "is", False]])
        self.assertEqual(len(items), 1)
        self.assertEqual(items[0]["id"], self._project_link["id"])
    def setUp(self):
        """
        Creates test data.
        """

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        # Create two users to assign to the pipeline configurations.
        self._user1 = self._mockgun.create("HumanUser", {"login": "******"})
        self._user2 = self._mockgun.create("HumanUser", {"login": "******"})

        # Create pipeline configurations that are assigned none, one or two users.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_user1", "users": [self._user1]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_user2", "users": [self._user2]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_both", "users": [self._user2, self._user1]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_none", "users": []}
        )
示例#5
0
    def setUp(self):
        """
        Creates test data.
        """

        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        # Create two users to assign to the pipeline configurations.
        self._user1 = self._mockgun.create("HumanUser", {"login": "******"})
        self._user2 = self._mockgun.create("HumanUser", {"login": "******"})

        # Create pipeline configurations that are assigned none, one or two users.
        self._mockgun.create("PipelineConfiguration", {
            "code": "with_user1",
            "users": [self._user1]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_user2",
            "users": [self._user2]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_both",
            "users": [self._user2, self._user1]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_none",
            "users": []
        })
示例#6
0
    def setUp(self):
        """
        Creates tests data.
        """
        super(TestFilterOperator, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        self._prj1_link = self._mockgun.create("Project", {"name": "prj1"})

        self._prj2_link = self._mockgun.create("Project", {"name": "prj2"})

        self._shot1 = self._mockgun.create("Shot", {
            "code": "shot1",
            "project": self._prj1_link
        })

        self._shot2 = self._mockgun.create("Shot", {
            "code": "shot2",
            "project": self._prj1_link
        })

        self._shot3 = self._mockgun.create("Shot", {
            "code": "shot3",
            "project": self._prj2_link
        })
示例#7
0
class TestTextFieldOperators(TestBaseWithExceptionTests):
    """
    Checks if text field comparison work.
    """
    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")
        self._user = self._mockgun.create("HumanUser", {"login": "******"})

    def test_operator_contains(self):
        """
        Ensures contains operator works.
        """
        item = self._mockgun.find_one("HumanUser", [["login", "contains", "se"]])
        self.assertTrue(item)
示例#8
0
 def setUp(self):
     """
     Creates test data.
     """
     self._mockgun = Mockgun("https://test.shotgunstudio.com",
                             login="******",
                             password="******")
     self._user = self._mockgun.create("HumanUser", {"login": "******"})
class TestTextFieldOperators(TestBaseWithExceptionTests):
    """
    Checks if text field comparison work.
    """
    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")
        self._user = self._mockgun.create("HumanUser", {"login": "******"})

    def test_operator_contains(self):
        """
        Ensures contains operator works.
        """
        item = self._mockgun.find_one("HumanUser", [["login", "contains", "se"]])
        self.assertTrue(item)
示例#10
0
    def setUp(self):
        """
        Creates test data.
        """
        super(TestValidateFilterSyntax, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._mockgun.create("Shot", {"code": "shot"})
示例#11
0
    def setUp(self):
        """
        Creates test data.
        """
        super(TestValidateFilterSyntax, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._mockgun.create("Shot", {"code": "shot"})
示例#12
0
class TestEntityFieldComparison(TestBaseWithExceptionTests):
    """
    Checks if entity fields comparison work.
    """
    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        self._project_link = self._mockgun.create("Project",
                                                  {"name": "project"})

        # This entity will ensure that a populated link field will be comparable.
        self._mockgun.create("PipelineConfiguration", {
            "code": "with_project",
            "project": self._project_link
        })

        # This entity will ensure that an unpopulated link field will be comparable.
        self._mockgun.create("PipelineConfiguration",
                             {"code": "without_project"})

    def test_searching_for_none_entity_field(self):
        """
        Ensures that comparison with None work.
        """

        items = self._mockgun.find("PipelineConfiguration",
                                   [["project", "is", None]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration",
                                   [["project", "is_not", None]])
        self.assertEqual(len(items), 1)

    def test_searching_for_initialized_entity_field(self):
        """
        Ensures that comparison with an entity works.
        """
        items = self._mockgun.find("PipelineConfiguration",
                                   [["project", "is", self._project_link]])
        self.assertEqual(len(items), 1)

        items = self._mockgun.find("PipelineConfiguration",
                                   [["project", "is_not", self._project_link]])
        self.assertEqual(len(items), 1)
示例#13
0
class TestValidateFilterSyntax(TestBaseWithExceptionTests):
    """
    Tests filter syntax support.
    """

    def setUp(self):
        """
        Creates test data.
        """
        super(TestValidateFilterSyntax, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._mockgun.create("Shot", {"code": "shot"})

    def test_filter_array_or_dict(self):
        """
        Ensure that arrays and dictionaries are supported for filters.
        """
        # This should not throw.
        self._mockgun.find(
            "Shot",
            [
                {
                    "filter_operator": "any",
                    "filters": [["code", "is", "shot"]]
                },
                [
                    "code", "is", "shot"
                ]
            ]
        )

        # We can't have not dict/list values for filters however.
        self.assertRaisesRegexp(
            ShotgunError,
            "Filters can only be lists or dictionaries, not int.",
            lambda: self._mockgun.find(
                "Shot",
                [1]
            )
        )
示例#14
0
    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._project_link = self._mockgun.create("Project", {"name": "project", "archived": False})

        # This entity will ensure that a populated link field will be comparable.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_project", "project": self._project_link, }
        )

        # This entity will ensure that an unpopulated link field will be comparable.
        self._mockgun.create("PipelineConfiguration", {"code": "without_project"})
示例#15
0
    def setUp(self):
        """
        Creates test data.
        """
        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._project_link = self._mockgun.create("Project", {"name": "project", "archived": False})

        # This entity will ensure that a populated link field will be comparable.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_project", "project": self._project_link, }
        )

        # This entity will ensure that an unpopulated link field will be comparable.
        self._mockgun.create("PipelineConfiguration", {"code": "without_project"})
示例#16
0
    def setUp(self):
        """
        Creates tests data.
        """
        super(TestFilterOperator, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._prj1_link = self._mockgun.create(
            "Project",
            {
                "name": "prj1"
            }
        )

        self._prj2_link = self._mockgun.create(
            "Project",
            {
                "name": "prj2"
            }
        )

        self._shot1 = self._mockgun.create(
            "Shot",
            {
                "code": "shot1",
                "project": self._prj1_link
            }
        )

        self._shot2 = self._mockgun.create(
            "Shot",
            {
                "code": "shot2",
                "project": self._prj1_link
            }
        )

        self._shot3 = self._mockgun.create(
            "Shot",
            {
                "code": "shot3",
                "project": self._prj2_link
            }
        )
示例#17
0
"""

import re
import os
import unittest
from shotgun_api3.lib.mockgun import Shotgun as Mockgun
from shotgun_api3 import ShotgunError


mockgun_schema_folder = os.path.join(
    os.path.dirname(__file__),
    "mockgun"
)

Mockgun.set_schema_paths(
    os.path.join(mockgun_schema_folder, "schema.pickle"),
    os.path.join(mockgun_schema_folder, "schema_entity.pickle")
)


# FIXME: This should probably be refactored into a base class for
# all test bases
class TestBaseWithExceptionTests(unittest.TestCase):
    """
    Implements a Python 2.4 compatible assertRaisesRegexp like method. This
    was introduced in Python 2.7.
    """
    def assertRaisesRegexp(self, exception_type, re_msg, func):
        try:
            func()
        except exception_type, exception:
            matches = re.findall(re_msg, str(exception))
示例#18
0
class TestFilterOperator(TestBaseWithExceptionTests):
    """
    Unit tests for the filter_operator filter syntax.
    """
    def setUp(self):
        """
        Creates tests data.
        """
        super(TestFilterOperator, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        self._prj1_link = self._mockgun.create("Project", {"name": "prj1"})

        self._prj2_link = self._mockgun.create("Project", {"name": "prj2"})

        self._shot1 = self._mockgun.create("Shot", {
            "code": "shot1",
            "project": self._prj1_link
        })

        self._shot2 = self._mockgun.create("Shot", {
            "code": "shot2",
            "project": self._prj1_link
        })

        self._shot3 = self._mockgun.create("Shot", {
            "code": "shot3",
            "project": self._prj2_link
        })

    def test_simple_filter_operators(self):
        """
        Tests a simple use of the filter_operator.
        """
        shots = self._mockgun.find(
            "Shot",
            [{
                "filter_operator": "any",
                "filters": [["code", "is", "shot1"], ["code", "is", "shot2"]]
            }])

        self.assertEqual(len(shots), 2)

        shots = self._mockgun.find(
            "Shot",
            [{
                "filter_operator": "all",
                "filters": [["code", "is", "shot1"], ["code", "is", "shot2"]]
            }])

        self.assertEqual(len(shots), 0)

    def test_nested_filter_operators(self):
        """
        Tests a the use of the filter_operator nested
        inside the filter_operator.
        """
        shots = self._mockgun.find("Shot", [{
            "filter_operator":
            "any",
            "filters": [{
                "filter_operator":
                "all",
                "filters": [["code", "is", "shot1"],
                            ["project", "is", self._prj1_link]]
            }, {
                "filter_operator":
                "all",
                "filters": [["code", "is", "shot3"],
                            ["project", "is", self._prj2_link]]
            }]
        }])

        self.assertEqual(len(shots), 2)

    def test_invalid_operator(self):

        self.assertRaisesRegexp(
            ShotgunError, "Unknown filter_operator type: bad",
            lambda: self._mockgun.find("Shot", [{
                "filter_operator": "bad",
                "filters": []
            }]))

        self.assertRaisesRegexp(
            ShotgunError,
            "Bad filter operator, requires keys 'filter_operator' and 'filters',",
            lambda: self._mockgun.find("Shot", [{}]))
示例#19
0
 def setUp(self):
     """
     Creates test data.
     """
     self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")
     self._user = self._mockgun.create("HumanUser", {"login": "******"})
示例#20
0
class TestMultiEntityFieldComparison(TestBaseWithExceptionTests):
    """
    Ensures multi entity field comparison work.
    """
    def setUp(self):
        """
        Creates test data.
        """

        self._mockgun = Mockgun("https://test.shotgunstudio.com",
                                login="******",
                                password="******")

        # Create two users to assign to the pipeline configurations.
        self._user1 = self._mockgun.create("HumanUser", {"login": "******"})
        self._user2 = self._mockgun.create("HumanUser", {"login": "******"})

        # Create pipeline configurations that are assigned none, one or two users.
        self._mockgun.create("PipelineConfiguration", {
            "code": "with_user1",
            "users": [self._user1]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_user2",
            "users": [self._user2]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_both",
            "users": [self._user2, self._user1]
        })

        self._mockgun.create("PipelineConfiguration", {
            "code": "with_none",
            "users": []
        })

    def test_find_by_sub_entity_field(self):
        """
        Ensures that queries on linked entity fields works.
        """
        items = self._mockgun.find("PipelineConfiguration",
                                   [["users.HumanUser.login", "is", "user1"]])
        self.assertEqual(len(items), 2)

        items = self._mockgun.find("PipelineConfiguration",
                                   [["users.HumanUser.login", "is", "user2"]])
        self.assertEqual(len(items), 2)

        items = self._mockgun.find(
            "PipelineConfiguration",
            [["users.HumanUser.login", "contains", "ser"]])
        self.assertEqual(len(items), 3)

        # Lets get fancy a bit.
        items = self._mockgun.find("PipelineConfiguration", [{
            "filter_operator":
            "any",
            "filters": [["users.HumanUser.login", "is", "user1"],
                        ["users.HumanUser.login", "is", "user2"]]
        }])
        self.assertEqual(len(items), 3)

        items = self._mockgun.find("PipelineConfiguration", [{
            "filter_operator":
            "all",
            "filters": [["users.HumanUser.login", "is", "user1"],
                        ["users.HumanUser.login", "is", "user2"]]
        }])
        self.assertEqual(len(items), 1)

    def test_find_with_none(self):
        """
        Ensures comparison with multi-entity fields and None works.
        """
        items = self._mockgun.find("PipelineConfiguration",
                                   [["users", "is", None]], ["users"])
        self.assertEqual(len(items), 1)
        self.assertEqual(items[0]["users"], [])

        items = self._mockgun.find("PipelineConfiguration",
                                   [["users", "is_not", None]], ["users"])
        self.assertEqual(len(items), 3)
        for item in items:
            self.assertTrue(len(item["users"]) > 0)
示例#21
0
class TestMultiEntityFieldComparison(TestBaseWithExceptionTests):
    """
    Ensures multi entity field comparison work.
    """

    def setUp(self):
        """
        Creates test data.
        """

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        # Create two users to assign to the pipeline configurations.
        self._user1 = self._mockgun.create("HumanUser", {"login": "******"})
        self._user2 = self._mockgun.create("HumanUser", {"login": "******"})

        # Create pipeline configurations that are assigned none, one or two users.
        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_user1", "users": [self._user1]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_user2", "users": [self._user2]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_both", "users": [self._user2, self._user1]}
        )

        self._mockgun.create(
            "PipelineConfiguration",
            {"code": "with_none", "users": []}
        )

    def test_find_by_sub_entity_field(self):
        """
        Ensures that queries on linked entity fields works.
        """
        items = self._mockgun.find("PipelineConfiguration", [["users.HumanUser.login", "is", "user1"]])
        self.assertEqual(len(items), 2)

        items = self._mockgun.find("PipelineConfiguration", [["users.HumanUser.login", "is", "user2"]])
        self.assertEqual(len(items), 2)

        items = self._mockgun.find("PipelineConfiguration", [["users.HumanUser.login", "contains", "ser"]])
        self.assertEqual(len(items), 3)

        # Lets get fancy a bit.
        items = self._mockgun.find("PipelineConfiguration", [{
            "filter_operator": "any",
            "filters": [
                ["users.HumanUser.login", "is", "user1"],
                ["users.HumanUser.login", "is", "user2"]
            ]}]
        )
        self.assertEqual(len(items), 3)

        items = self._mockgun.find("PipelineConfiguration", [{
            "filter_operator": "all",
            "filters": [
                ["users.HumanUser.login", "is", "user1"],
                ["users.HumanUser.login", "is", "user2"]
            ]}]
        )
        self.assertEqual(len(items), 1)

    def test_find_with_none(self):
        """
        Ensures comparison with multi-entity fields and None works.
        """
        items = self._mockgun.find("PipelineConfiguration", [["users", "is", None]], ["users"])
        self.assertEqual(len(items), 1)
        self.assertEqual(items[0]["users"], [])

        items = self._mockgun.find("PipelineConfiguration", [["users", "is_not", None]], ["users"])
        self.assertEqual(len(items), 3)
        for item in items:
            self.assertTrue(len(item["users"]) > 0)
示例#22
0
# -----------------------------------------------------------------------------
"""
Unit tests for Mockgun. Does not require an Internet connection
and can be run on their own by typing "python test_mockgun.py".
"""

import re
import os
import unittest
from shotgun_api3.lib.mockgun import Shotgun as Mockgun
from shotgun_api3 import ShotgunError

mockgun_schema_folder = os.path.join(os.path.dirname(__file__), "mockgun")

Mockgun.set_schema_paths(
    os.path.join(mockgun_schema_folder, "schema.pickle"),
    os.path.join(mockgun_schema_folder, "schema_entity.pickle"))


# FIXME: This should probably be refactored into a base class for
# all test bases
class TestBaseWithExceptionTests(unittest.TestCase):
    """
    Implements a Python 2.4 compatible assertRaisesRegexp like method. This
    was introduced in Python 2.7.
    """
    def assertRaisesRegexp(self, exception_type, re_msg, func):
        try:
            func()
        except exception_type, exception:
            matches = re.findall(re_msg, str(exception))
示例#23
0
class TestFilterOperator(TestBaseWithExceptionTests):
    """
    Unit tests for the filter_operator filter syntax.
    """

    def setUp(self):
        """
        Creates tests data.
        """
        super(TestFilterOperator, self).setUp()

        self._mockgun = Mockgun("https://test.shotgunstudio.com", login="******", password="******")

        self._prj1_link = self._mockgun.create(
            "Project",
            {
                "name": "prj1"
            }
        )

        self._prj2_link = self._mockgun.create(
            "Project",
            {
                "name": "prj2"
            }
        )

        self._shot1 = self._mockgun.create(
            "Shot",
            {
                "code": "shot1",
                "project": self._prj1_link
            }
        )

        self._shot2 = self._mockgun.create(
            "Shot",
            {
                "code": "shot2",
                "project": self._prj1_link
            }
        )

        self._shot3 = self._mockgun.create(
            "Shot",
            {
                "code": "shot3",
                "project": self._prj2_link
            }
        )

    def test_simple_filter_operators(self):
        """
        Tests a simple use of the filter_operator.
        """
        shots = self._mockgun.find(
            "Shot",
            [{
                "filter_operator": "any",
                "filters": [
                    ["code", "is", "shot1"],
                    ["code", "is", "shot2"]
                ]
            }]
        )

        self.assertEqual(len(shots), 2)

        shots = self._mockgun.find(
            "Shot",
            [{
                "filter_operator": "all",
                "filters": [
                    ["code", "is", "shot1"],
                    ["code", "is", "shot2"]
                ]
            }]
        )

        self.assertEqual(len(shots), 0)

    def test_nested_filter_operators(self):
        """
        Tests a the use of the filter_operator nested
        inside the filter_operator.
        """
        shots = self._mockgun.find(
            "Shot",
            [
                {
                    "filter_operator": "any",
                    "filters": [
                        {
                            "filter_operator": "all",
                            "filters": [
                                ["code", "is", "shot1"],
                                ["project", "is", self._prj1_link]
                            ]
                        },
                        {
                            "filter_operator": "all",
                            "filters": [
                                ["code", "is", "shot3"],
                                ["project", "is", self._prj2_link]
                            ]
                        }
                    ]
                }
            ]
        )

        self.assertEqual(len(shots), 2)

    def test_invalid_operator(self):

        self.assertRaisesRegexp(
            ShotgunError,
            "Unknown filter_operator type: bad",
            lambda: self._mockgun.find(
                "Shot",
                [
                    {
                        "filter_operator": "bad",
                        "filters": []
                    }
                ])
        )

        self.assertRaisesRegexp(
            ShotgunError,
            "Bad filter operator, requires keys 'filter_operator' and 'filters',",
            lambda: self._mockgun.find(
                "Shot",
                [
                    {
                    }
                ])
        )