Пример #1
0
class TestBravoFactoryPacks(unittest.TestCase):
    """
    The plugin pack system should work.
    """

    def test_pack_beta(self):
        """
        The "beta" plugin pack should always work. Period.
        """

        self.d = tempfile.mkdtemp()
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "authenticator": "offline",
            "mode": "creative",
            "packs": "beta",
            "port": "0",
            "serializer": "alpha",
            "url": "file://%s" % self.d,
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()

    def tearDown(self):
        self.f.stopFactory()
        shutil.rmtree(self.d)
Пример #2
0
class TestWorld(unittest.TestCase):

    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    def test_load_player_initial(self):
        """
        Calling load_player() on a player which has never been loaded should
        not result in an exception. Instead, the player should be returned,
        wrapped in a Deferred.
        """

        # For bonus points, assert that the player's username is correct.
        d = self.w.load_player("unittest")

        @d.addCallback
        def cb(player):
            self.assertEqual(player.username, "unittest")
        return d
Пример #3
0
class TestWorld(unittest.TestCase):
    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    def test_load_player_initial(self):
        """
        Calling load_player() on a player which has never been loaded should
        not result in an exception. Instead, the player should be returned,
        wrapped in a Deferred.
        """

        # For bonus points, assert that the player's username is correct.
        d = self.w.load_player("unittest")

        @d.addCallback
        def cb(player):
            self.assertEqual(player.username, "unittest")

        return d
Пример #4
0
class TestBravoFactoryPacks(unittest.TestCase):
    """
    The plugin pack system should work.
    """
    def test_pack_beta(self):
        """
        The "beta" plugin pack should always work. Period.
        """

        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "mode": "creative",
            "packs": "beta",
            "port": "0",
            "serializer": "memory",
            "url": "",
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()
        # And stop it, too.
        self.f.stopFactory()
Пример #5
0
class TestBravoFactoryPacks(unittest.TestCase):
    """
    The plugin pack system should work.
    """
    def test_pack_beta(self):
        """
        The "beta" plugin pack should always work. Period.
        """

        self.d = tempfile.mkdtemp()
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "authenticator": "offline",
            "mode": "creative",
            "packs": "beta",
            "port": "0",
            "serializer": "alpha",
            "url": "file://%s" % self.d,
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()

    def tearDown(self):
        self.f.stopFactory()
        shutil.rmtree(self.d)
Пример #6
0
class TestBravoFactoryPacks(unittest.TestCase):
    """
    The plugin pack system should work.
    """

    def test_pack_beta(self):
        """
        The "beta" plugin pack should always work. Period.
        """

        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "mode"          : "creative",
            "packs"         : "beta",
            "port"          : "0",
            "serializer"    : "memory",
            "url"           : "",
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()
        # And stop it, too.
        self.f.stopFactory()
Пример #7
0
class TestWorldConfig(unittest.TestCase):

    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []

    def test_trivial(self):
        pass

    def test_world_configured_seed(self):
        """
        Worlds can have their seed set via configuration.
        """

        self.bcp.set("world unittest", "seed", "42")
        self.w.start()
        self.assertEqual(self.w.level.seed, 42)
        self.w.stop()
Пример #8
0
class TestBravoConfigParser(unittest.TestCase):
    def setUp(self):
        self.bcp = BravoConfigParser()
        self.bcp.add_section("unittest")

    def test_trivial(self):
        pass

    def test_getlist(self):
        self.bcp.set("unittest", "l", "a,b,c,d")
        self.assertEqual(self.bcp.getlist("unittest", "l"),
                         ["a", "b", "c", "d"])

    def test_getlist_separator(self):
        self.bcp.set("unittest", "l", "a:b:c:d")
        self.assertEqual(self.bcp.getlist("unittest", "l", ":"),
                         ["a", "b", "c", "d"])

    def test_getlist_empty(self):
        self.bcp.set("unittest", "l", "")
        self.assertEqual(self.bcp.getlist("unittest", "l"), [])

    def test_getlist_whitespace(self):
        self.bcp.set("unittest", "l", " ")
        self.assertEqual(self.bcp.getlist("unittest", "l"), [])

    def test_getdefault(self):
        self.assertEqual(self.bcp.getdefault("unittest", "fake", ""), "")

    def test_getdefault_no_section(self):
        self.assertEqual(self.bcp.getdefault("fake", "fake", ""), "")

    def test_getbooleandefault(self):
        self.assertEqual(self.bcp.getbooleandefault("unittest", "fake", True),
                         True)

    def test_getintdefault(self):
        self.assertEqual(self.bcp.getintdefault("unittest", "fake", 42), 42)

    def test_getlistdefault(self):
        self.assertEqual(self.bcp.getlistdefault("unittest", "fake", []), [])
Пример #9
0
class TestBravoConfigParser(unittest.TestCase):
    def setUp(self):
        self.bcp = BravoConfigParser()
        self.bcp.add_section("unittest")

    def test_trivial(self):
        pass

    def test_getlist(self):
        self.bcp.set("unittest", "l", "a,b,c,d")
        self.assertEqual(self.bcp.getlist("unittest", "l"), ["a", "b", "c", "d"])

    def test_getlist_separator(self):
        self.bcp.set("unittest", "l", "a:b:c:d")
        self.assertEqual(self.bcp.getlist("unittest", "l", ":"), ["a", "b", "c", "d"])

    def test_getlist_empty(self):
        self.bcp.set("unittest", "l", "")
        self.assertEqual(self.bcp.getlist("unittest", "l"), [])

    def test_getlist_whitespace(self):
        self.bcp.set("unittest", "l", " ")
        self.assertEqual(self.bcp.getlist("unittest", "l"), [])

    def test_getdefault(self):
        self.assertEqual(self.bcp.getdefault("unittest", "fake", ""), "")

    def test_getdefault_no_section(self):
        self.assertEqual(self.bcp.getdefault("fake", "fake", ""), "")

    def test_getbooleandefault(self):
        self.assertEqual(self.bcp.getbooleandefault("unittest", "fake", True), True)

    def test_getintdefault(self):
        self.assertEqual(self.bcp.getintdefault("unittest", "fake", 42), 42)

    def test_getlistdefault(self):
        self.assertEqual(self.bcp.getlistdefault("unittest", "fake", []), [])
Пример #10
0
class TestWorldConfig(unittest.TestCase):
    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []

    def test_trivial(self):
        pass

    def test_world_configured_seed(self):
        """
        Worlds can have their seed set via configuration.
        """

        self.bcp.set("world unittest", "seed", "42")
        self.w.start()
        self.assertEqual(self.w.level.seed, 42)
        self.w.stop()
Пример #11
0
class TestWorldChunks(unittest.TestCase):
    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    @inlineCallbacks
    def test_request_chunk_identity(self):
        first = yield self.w.request_chunk(0, 0)
        second = yield self.w.request_chunk(0, 0)
        self.assertIs(first, second)

    @inlineCallbacks
    def test_request_chunk_cached_identity(self):
        # Turn on the cache and get a few chunks in there, then request a
        # chunk that is in the cache.
        yield self.w.enable_cache(1)
        first = yield self.w.request_chunk(0, 0)
        second = yield self.w.request_chunk(0, 0)
        self.assertIs(first, second)

    @inlineCallbacks
    def test_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = array("B")
        chunk.metadata.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback_negative(self):
        chunk = yield self.w.request_chunk(-1, -1)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(-1, -1)

        for x, y, z in product(xrange(2), repeat=3):
            block = yield self.w.get_block((x - 16, y, z - 16))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = array("B")
        chunk.metadata.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Reload chunk.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((12, 64, 4))
        chunk = yield self.w.request_chunk(0, 0)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty_offset(self):
        chunk = yield self.w.request_chunk(1, 2)

        # Reload chunk.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(1, 2)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((29, 64, 43))
        chunk = yield self.w.request_chunk(1, 2)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_sync_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = self.w.sync_get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    def test_sync_get_block_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.w.sync_get_block, (0, 0, 0))

    def test_sync_get_metadata_neighboring(self):
        """
        Even if a neighboring chunk is loaded, the target chunk could still be
        unloaded.

        Test with sync_get_metadata() to increase test coverage.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertRaises(ChunkNotLoaded, self.w.sync_get_metadata,
                              (16, 0, 0))

        return d
Пример #12
0
class TestGrass(TestCase):

    def setUp(self):
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, "unittest")
        self.w.pipeline = []
        self.w.start()

        self.f = GrassMockFactory()
        self.f.world = self.w
        self.w.factory = self.f

        plugins = retrieve_plugins(IAutomaton, factory=self.f)
        self.hook = plugins["grass"]

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    @inlineCallbacks
    def test_not_dirt(self):
        """
        Blocks which aren't dirt by the time they're processed will be
        ignored.
        """

        chunk = yield self.w.request_chunk(0, 0)

        chunk.set_block((0, 0, 0), blocks["bedrock"].slot)

        # Run the loop once.
        self.hook.feed((0, 0, 0))
        self.hook.process()

        # We shouldn't have any pending blocks now.
        self.assertFalse(self.hook.tracked)

    @inlineCallbacks
    def test_unloaded_chunk(self):
        """
        The grass automaton can't load chunks, so it will stop tracking blocks
        on the edge of the loaded world.
        """

        chunk = yield self.w.request_chunk(0, 0)

        chunk.set_block((0, 0, 0), blocks["dirt"].slot)

        # Run the loop once.
        self.hook.feed((0, 0, 0))
        self.hook.process()

        # We shouldn't have any pending blocks now.
        self.assertFalse(self.hook.tracked)

    @inlineCallbacks
    def test_surrounding(self):
        """
        When surrounded by eight grassy neighbors, dirt should turn into grass
        immediately.
        """

        chunk = yield self.w.request_chunk(0, 0)

        # Set up grassy surroundings.
        for x, z in product(xrange(0, 3), repeat=2):
            chunk.set_block((x, 0, z), blocks["grass"].slot)

        # Our lone Cinderella.
        chunk.set_block((1, 0, 1), blocks["dirt"].slot)

        # Do the actual hook run. This should take exactly one run.
        self.hook.feed((1, 0, 1))
        self.hook.process()

        self.assertFalse(self.hook.tracked)
        self.assertEqual(chunk.get_block((1, 0, 1)), blocks["grass"].slot)

    def test_surrounding_not_dirt(self):
        """
        Blocks which aren't dirt by the time they're processed will be
        ignored, even when surrounded by grass.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            # Set up grassy surroundings.
            for x, z in product(xrange(0, 3), repeat=2):
                chunk.set_block((x, 0, z), blocks["grass"].slot)

            chunk.set_block((1, 0, 1), blocks["bedrock"].slot)

            # Run the loop once.
            self.hook.feed((1, 0, 1))
            self.hook.process()

            # We shouldn't have any pending blocks now.
            self.assertFalse(self.hook.tracked)

        return d

    @inlineCallbacks
    def test_surrounding_obstructed(self):
        """
        Grass can't grow on blocks which have other blocks on top of them.
        """

        chunk = yield self.w.request_chunk(0, 0)

        # Set up grassy surroundings.
        for x, z in product(xrange(0, 3), repeat=2):
            chunk.set_block((x, 0, z), blocks["grass"].slot)

        # Put an obstruction on top.
        chunk.set_block((1, 1, 1), blocks["stone"].slot)

        # Our lone Cinderella.
        chunk.set_block((1, 0, 1), blocks["dirt"].slot)

        # Do the actual hook run. This should take exactly one run.
        self.hook.feed((1, 0, 1))
        self.hook.process()

        self.assertFalse(self.hook.tracked)
        self.assertEqual(chunk.get_block((1, 0, 1)), blocks["dirt"].slot)

    @inlineCallbacks
    def test_above(self):
        """
        Grass spreads downwards.
        """

        chunk = yield self.w.request_chunk(0, 0)

        # Set up grassy surroundings.
        for x, z in product(xrange(0, 3), repeat=2):
            chunk.set_block((x, 1, z), blocks["grass"].slot)

        chunk.destroy((1, 1, 1))

        # Our lone Cinderella.
        chunk.set_block((1, 0, 1), blocks["dirt"].slot)

        # Do the actual hook run. This should take exactly one run.
        self.hook.feed((1, 0, 1))
        self.hook.process()

        self.assertFalse(self.hook.tracked)
        self.assertEqual(chunk.get_block((1, 0, 1)), blocks["grass"].slot)

    def test_two_of_four(self):
        """
        Grass should eventually spread to all filled-in plots on a 2x2 grid.

        Discovered by TkTech.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):

            for x, y, z in product(xrange(0, 4), xrange(0, 2), xrange(0, 4)):
                chunk.set_block((x, y, z), blocks["grass"].slot)

            for x, z in product(xrange(1, 3), repeat=2):
                chunk.set_block((x, 1, z), blocks["dirt"].slot)

            self.hook.feed((1, 1, 1))
            self.hook.feed((2, 1, 1))
            self.hook.feed((1, 1, 2))
            self.hook.feed((2, 1, 2))

            # Run to completion. This can take varying amounts of time
            # depending on the RNG, but it should be fairly speedy.
            # XXX patch the RNG so we can do this deterministically
            while self.hook.tracked:
                self.hook.process()

            self.assertEqual(chunk.get_block((1, 1, 1)), blocks["grass"].slot)
            self.assertEqual(chunk.get_block((2, 1, 1)), blocks["grass"].slot)
            self.assertEqual(chunk.get_block((1, 1, 2)), blocks["grass"].slot)
            self.assertEqual(chunk.get_block((2, 1, 2)), blocks["grass"].slot)
Пример #13
0
class TestRedstone(TestCase):
    def setUp(self):
        # Set up world.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

        # And finally the mock factory.
        self.f = RedstoneMockFactory()
        self.f.world = self.w

        self.p = retrieve_plugins(IDigHook, factory=self.f)
        self.hook = self.p["redstone"]

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    def test_and_gate(self):
        """
        AND gates should work.

        This test also bumps up against a chunk boundary intentionally.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, False),
                (True, False, False),
                (False, True, False),
                (True, True, True),
            ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 1), blocks["sand"].slot)
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((1, 1, 3), blocks["sand"].slot)

                chunk.set_block((1, 2, 1), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 1),
                                   blocks["redstone-torch"].orientation("+y"))
                chunk.set_block((1, 2, 3), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 3),
                                   blocks["redstone-torch"].orientation("+y"))

                chunk.set_block((1, 2, 2), blocks["redstone-wire"].slot)

                # Output torch.
                chunk.set_block((2, 1, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((2, 1, 2),
                                   blocks["redstone-torch"].orientation("+x"))

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-x")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((0, 1, 1), iblock)
                chunk.set_metadata((0, 1, 1), imetadata)
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((0, 1, 3), iblock)
                chunk.set_metadata((0, 1, 3), imetadata)

                # Run the circuit, starting at the switches. Six times:
                # Lever (x2), sand (x2), torch (x2), wire, block, torch.
                self.hook.feed((0, 1, 1))
                self.hook.feed((0, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((2, 1, 2))
                metadata = chunk.get_metadata((2, 1, 2))
                self.assertEqual((block, metadata),
                                 truthify_block(o, block, metadata))

        return d

    def test_or_gate(self):
        """
        OR gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, False),
                (True, False, True),
                (False, True, True),
                (True, True, True),
            ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((1, 2, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 2),
                                   blocks["redstone-torch"].orientation("+y"))
                chunk.set_block((2, 2, 2), blocks["redstone-wire"].slot)
                chunk.set_block((2, 1, 2), blocks["sand"].slot)
                chunk.set_block((3, 1, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((3, 1, 2),
                                   blocks["redstone-torch"].orientation("+x"))

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-z")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)
                orientation = blocks["lever"].orientation("+z")
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((1, 1, 3), iblock)
                chunk.set_metadata((1, 1, 3), imetadata)

                # Run the circuit, starting at the switches. Six times:
                # Lever (x2), sand, torch, wire, sand, torch.
                self.hook.feed((1, 1, 1))
                self.hook.feed((1, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((3, 1, 2))
                metadata = chunk.get_metadata((3, 1, 2))
                self.assertEqual((block, metadata),
                                 truthify_block(o, block, metadata))

        return d

    def test_nor_gate(self):
        """
        NOR gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, True),
                (True, False, False),
                (False, True, False),
                (True, True, False),
            ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((2, 1, 2), blocks["redstone-torch"].slot)

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-z")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)
                orientation = blocks["lever"].orientation("+z")
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((1, 1, 3), iblock)
                chunk.set_metadata((1, 1, 3), imetadata)
                # Attach the torch to the sand block too.
                orientation = blocks["redstone-torch"].orientation("+x")
                chunk.set_metadata((2, 1, 2), orientation)

                # Run the circuit, starting at the switches. Three times:
                # Lever (x2), sand, torch.
                self.hook.feed((1, 1, 1))
                self.hook.feed((1, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((2, 1, 2))
                metadata = chunk.get_metadata((2, 1, 2))
                self.assertEqual((block, metadata),
                                 truthify_block(o, block, metadata))

        return d

    def test_not_gate(self):
        """
        NOT gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i, o in ((True, False), (False, True)):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((2, 1, 1), blocks["sand"].slot)
                chunk.set_block((3, 1, 1), blocks["redstone-torch"].slot)

                # Attach the lever to the sand block, and throw it. For sanity
                # purposes, grab the orientation metadata from the block
                # definition.
                orientation = blocks["lever"].orientation("-x")
                iblock, imetadata = truthify_block(i, blocks["lever"].slot,
                                                   orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)

                # Attach the torch to the sand block too.
                orientation = blocks["redstone-torch"].orientation("+x")
                chunk.set_metadata((3, 1, 1), orientation)

                # Run the circuit, starting at the switch.
                self.hook.feed((1, 1, 1))

                # Lever, torch, sand.
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((3, 1, 1))
                metadata = chunk.get_metadata((3, 1, 1))
                self.assertEqual((block, metadata),
                                 truthify_block(o, block, metadata))

        return d
Пример #14
0
class TestWorldChunks(unittest.TestCase):

    def setUp(self):
        self.name = "unittest"
        self.d = tempfile.mkdtemp()
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "file://%s" % self.d)
        self.bcp.set("world unittest", "serializer", "alpha")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()
        shutil.rmtree(self.d)

    def test_trivial(self):
        pass

    @inlineCallbacks
    def test_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.metadata.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback_negative(self):
        chunk = yield self.w.request_chunk(-1, -1)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(-1, -1)

        for x, y, z in product(xrange(2), repeat=3):
            block = yield self.w.get_block((x - 16, y, z - 16))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.metadata.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Reload chunk.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((12, 64, 4))
        chunk = yield self.w.request_chunk(0, 0)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty_offset(self):
        chunk = yield self.w.request_chunk(1, 2)

        # Reload chunk.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(1, 2)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((29, 64, 43))
        chunk = yield self.w.request_chunk(1, 2)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_sync_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
            dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = self.w.sync_get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    def test_sync_get_block_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.w.sync_get_block, (0, 0, 0))

    def test_sync_get_metadata_neighboring(self):
        """
        Even if a neighboring chunk is loaded, the target chunk could still be
        unloaded.

        Test with sync_get_metadata() to increase test coverage.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertRaises(ChunkNotLoaded,
                              self.w.sync_get_metadata, (16, 0, 0))

        return d
Пример #15
0
class TestBravoFactory(unittest.TestCase):
    def setUp(self):
        # Same setup as World, because Factory is very automagical.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "port", "0")
        self.bcp.set("world unittest", "mode", "creative")

        self.f = BravoFactory(self.bcp, self.name)

    def test_trivial(self):
        pass

    def test_initial_attributes(self):
        """
        Make sure that the basic attributes of the factory are correct.

        You'd be surprised how often this test breaks.
        """

        self.assertEqual(self.f.name, "unittest")
        self.assertEqual(self.f.config_name, "world unittest")

        self.assertEqual(self.f.eid, 1)

    def test_update_time(self):
        """
        Timekeeping should work.
        """

        clock = Clock()
        clock.advance(20)

        self.patch(reactor, "seconds", clock.seconds)
        self.patch(self.f, "update_season", lambda: None)

        self.f.timestamp = 0
        self.f.time = 0

        self.f.update_time()
        self.assertEqual(self.f.timestamp, 20)
        self.assertEqual(self.f.time, 400)

    def test_update_time_by_day(self):
        """
        Timekeeping should be alright with more than a day passing at once.
        """

        clock = Clock()
        clock.advance(1201)

        self.patch(reactor, "seconds", clock.seconds)
        self.patch(self.f, "update_season", lambda: None)

        self.f.timestamp = 0
        self.f.time = 0
        self.f.day = 0

        self.f.update_time()
        self.assertEqual(self.f.time, 20)
        self.assertEqual(self.f.day, 1)

    def test_update_season_empty(self):
        """
        If no seasons are enabled, things should proceed as normal.
        """

        self.bcp.set("world unittest", "seasons", "")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertTrue(self.f.world.season is None)

        self.f.day = 90
        self.f.update_season()
        self.assertTrue(self.f.world.season is None)

    def test_update_season_winter(self):
        """
        If winter is the only season available, then only winter should be
        selected, regardless of day.
        """

        self.bcp.set("world unittest", "seasons", "winter")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

        self.f.day = 90
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

    def test_update_season_switch(self):
        """
        The season should change from spring to winter when both are enabled.
        """

        self.bcp.set("world unittest", "seasons", "winter, spring")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

        self.f.day = 90
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "spring")

    def test_set_username(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p

        self.assertTrue(self.f.set_username(p, "Derp"))

        self.assertTrue("Derp" in self.f.protocols)
        self.assertTrue("Hurp" not in self.f.protocols)
        self.assertEqual(p.username, "Derp")

    def test_set_username_taken(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p
        self.f.protocols["Derp"] = None

        self.assertFalse(self.f.set_username(p, "Derp"))

        self.assertEqual(p.username, "Hurp")

    def test_set_username_noop(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p

        self.assertFalse(self.f.set_username(p, "Hurp"))
Пример #16
0
class TestBravoFactoryStarted(unittest.TestCase):
    """
    Tests which require ``startFactory()`` to be called.
    """
    def setUp(self):
        # Same setup as World, because Factory is very automagical.
        self.d = tempfile.mkdtemp()
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "authenticator": "offline",
            "automatons": "",
            "generators": "",
            "mode": "creative",
            "port": "0",
            "seasons": "winter, spring",
            "serializer": "alpha",
            "url": "file://%s" % self.d,
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()

    def tearDown(self):
        self.f.stopFactory()
        shutil.rmtree(self.d)

    def test_trivial(self):
        pass

    def test_create_entity_pickup(self):
        entity = self.f.create_entity(0, 0, 0, "Item")
        self.assertEqual(entity.eid, 2)
        self.assertEqual(self.f.eid, 2)

    def test_create_entity_player(self):
        entity = self.f.create_entity(0, 0, 0, "Player", username="******")
        self.assertEqual(entity.eid, 2)
        self.assertEqual(entity.username, "unittest")
        self.assertEqual(self.f.eid, 2)

    def test_give(self):
        self.f.give((0, 0, 0), (2, 0), 1)

    def test_give_oversized(self):
        """
        Check that oversized inputs to ``give()`` merely cause lots of pickups
        to be spawned.
        """

        # Our check consists of counting the number of times broadcast is
        # called.
        count = [0]

        def broadcast(packet):
            count[0] += 1

        self.patch(self.f, "broadcast", broadcast)

        # 65 blocks should be split into two stacks.
        self.f.give((0, 0, 0), (2, 0), 65)
        self.assertEqual(count[0], 2)

    def test_players_near(self):
        # Register some protocols with a player on the factory first.
        players = [
            self.f.create_entity(0, 0, 0, "Player", username=""),  # eid 2
            self.f.create_entity(0, 2, 0, "Player", username=""),  # eid 3
            self.f.create_entity(1, 0, 3, "Player", username=""),  # eid 4
            self.f.create_entity(0, 4, 1, "Player", username=""),  # eid 5
        ]

        for i, player in enumerate(players):
            self.f.protocols[i] = MockProtocol(player)

        # List of tests (player in the center, radius, expected eids).
        expected_results = [
            (players[0], 1, []),
            (players[0], 2, [3]),
            (players[0], 4, [3, 4]),
            (players[0], 5, [3, 4, 5]),
            (players[1], 3, [2, 5]),
        ]

        for player, radius, result in expected_results:
            found = [p.eid for p in self.f.players_near(player, radius)]
            self.assertEqual(set(found), set(result))
Пример #17
0
class TestRedstone(TestCase):

    def setUp(self):
        # Set up world.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

        # And finally the mock factory.
        self.f = RedstoneMockFactory()
        self.f.world = self.w

        self.p = retrieve_plugins(IDigHook, factory=self.f)
        self.hook = self.p["redstone"]

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    def test_and_gate(self):
        """
        AND gates should work.

        This test also bumps up against a chunk boundary intentionally.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, False),
                (True, False, False),
                (False, True, False),
                (True, True, True),
                ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 1), blocks["sand"].slot)
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((1, 1, 3), blocks["sand"].slot)

                chunk.set_block((1, 2, 1), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 1),
                    blocks["redstone-torch"].orientation("+y"))
                chunk.set_block((1, 2, 3), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 3),
                    blocks["redstone-torch"].orientation("+y"))

                chunk.set_block((1, 2, 2), blocks["redstone-wire"].slot)

                # Output torch.
                chunk.set_block((2, 1, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((2, 1, 2),
                    blocks["redstone-torch"].orientation("+x"))

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-x")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                    orientation)
                chunk.set_block((0, 1, 1), iblock)
                chunk.set_metadata((0, 1, 1), imetadata)
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                    orientation)
                chunk.set_block((0, 1, 3), iblock)
                chunk.set_metadata((0, 1, 3), imetadata)

                # Run the circuit, starting at the switches. Six times:
                # Lever (x2), sand (x2), torch (x2), wire, block, torch.
                self.hook.feed((0, 1, 1))
                self.hook.feed((0, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((2, 1, 2))
                metadata = chunk.get_metadata((2, 1, 2))
                self.assertEqual((block, metadata),
                    truthify_block(o, block, metadata))

        return d

    def test_or_gate(self):
        """
        OR gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, False),
                (True, False, True),
                (False, True, True),
                (True, True, True),
                ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((1, 2, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((1, 2, 2),
                    blocks["redstone-torch"].orientation("+y"))
                chunk.set_block((2, 2, 2), blocks["redstone-wire"].slot)
                chunk.set_block((2, 1, 2), blocks["sand"].slot)
                chunk.set_block((3, 1, 2), blocks["redstone-torch"].slot)
                chunk.set_metadata((3, 1, 2),
                    blocks["redstone-torch"].orientation("+x"))

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-z")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                    orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)
                orientation = blocks["lever"].orientation("+z")
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                    orientation)
                chunk.set_block((1, 1, 3), iblock)
                chunk.set_metadata((1, 1, 3), imetadata)

                # Run the circuit, starting at the switches. Six times:
                # Lever (x2), sand, torch, wire, sand, torch.
                self.hook.feed((1, 1, 1))
                self.hook.feed((1, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((3, 1, 2))
                metadata = chunk.get_metadata((3, 1, 2))
                self.assertEqual((block, metadata),
                    truthify_block(o, block, metadata))

        return d

    def test_nor_gate(self):
        """
        NOR gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i1, i2, o in (
                (False, False, True),
                (True, False, False),
                (False, True, False),
                (True, True, False),
                ):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((1, 1, 2), blocks["sand"].slot)
                chunk.set_block((2, 1, 2), blocks["redstone-torch"].slot)

                # Attach the levers to the sand block.
                orientation = blocks["lever"].orientation("-z")
                iblock, imetadata = truthify_block(i1, blocks["lever"].slot,
                    orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)
                orientation = blocks["lever"].orientation("+z")
                iblock, imetadata = truthify_block(i2, blocks["lever"].slot,
                    orientation)
                chunk.set_block((1, 1, 3), iblock)
                chunk.set_metadata((1, 1, 3), imetadata)
                # Attach the torch to the sand block too.
                orientation = blocks["redstone-torch"].orientation("+x")
                chunk.set_metadata((2, 1, 2), orientation)

                # Run the circuit, starting at the switches. Three times:
                # Lever (x2), sand, torch.
                self.hook.feed((1, 1, 1))
                self.hook.feed((1, 1, 3))
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((2, 1, 2))
                metadata = chunk.get_metadata((2, 1, 2))
                self.assertEqual((block, metadata),
                    truthify_block(o, block, metadata))

        return d

    def test_not_gate(self):
        """
        NOT gates should work.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            for i, o in ((True, False), (False, True)):
                # Reset the hook.
                self.hook.asic = Asic()

                # The tableau.
                chunk.set_block((2, 1, 1), blocks["sand"].slot)
                chunk.set_block((3, 1, 1), blocks["redstone-torch"].slot)

                # Attach the lever to the sand block, and throw it. For sanity
                # purposes, grab the orientation metadata from the block
                # definition.
                orientation = blocks["lever"].orientation("-x")
                iblock, imetadata = truthify_block(i, blocks["lever"].slot,
                    orientation)
                chunk.set_block((1, 1, 1), iblock)
                chunk.set_metadata((1, 1, 1), imetadata)

                # Attach the torch to the sand block too.
                orientation = blocks["redstone-torch"].orientation("+x")
                chunk.set_metadata((3, 1, 1), orientation)

                # Run the circuit, starting at the switch.
                self.hook.feed((1, 1, 1))

                # Lever, torch, sand.
                self.hook.process()
                self.hook.process()
                self.hook.process()

                block = chunk.get_block((3, 1, 1))
                metadata = chunk.get_metadata((3, 1, 1))
                self.assertEqual((block, metadata),
                    truthify_block(o, block, metadata))

        return d
Пример #18
0
class TestBravoFactory(unittest.TestCase):

    def setUp(self):
        # Same setup as World, because Factory is very automagical.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "port", "0")
        self.bcp.set("world unittest", "mode", "creative")

        self.f = BravoFactory(self.bcp, self.name)

    def test_trivial(self):
        pass

    def test_initial_attributes(self):
        """
        Make sure that the basic attributes of the factory are correct.

        You'd be surprised how often this test breaks.
        """

        self.assertEqual(self.f.name, "unittest")
        self.assertEqual(self.f.config_name, "world unittest")

        self.assertEqual(self.f.eid, 1)

    def test_update_time(self):
        """
        Timekeeping should work.
        """

        clock = Clock()
        clock.advance(20)

        self.patch(reactor, "seconds", clock.seconds)
        self.patch(self.f, "update_season", lambda: None)

        self.f.timestamp = 0
        self.f.time = 0

        self.f.update_time()
        self.assertEqual(self.f.timestamp, 20)
        self.assertEqual(self.f.time, 400)

    def test_update_time_by_day(self):
        """
        Timekeeping should be alright with more than a day passing at once.
        """

        clock = Clock()
        clock.advance(1201)

        self.patch(reactor, "seconds", clock.seconds)
        self.patch(self.f, "update_season", lambda: None)

        self.f.timestamp = 0
        self.f.time = 0
        self.f.day = 0

        self.f.update_time()
        self.assertEqual(self.f.time, 20)
        self.assertEqual(self.f.day, 1)

    def test_update_season_empty(self):
        """
        If no seasons are enabled, things should proceed as normal.
        """

        self.bcp.set("world unittest", "seasons", "")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertTrue(self.f.world.season is None)

        self.f.day = 90
        self.f.update_season()
        self.assertTrue(self.f.world.season is None)

    def test_update_season_winter(self):
        """
        If winter is the only season available, then only winter should be
        selected, regardless of day.
        """

        self.bcp.set("world unittest", "seasons", "winter")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

        self.f.day = 90
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

    def test_update_season_switch(self):
        """
        The season should change from spring to winter when both are enabled.
        """

        self.bcp.set("world unittest", "seasons",
            "winter, spring")
        self.f.register_plugins()

        self.f.day = 0
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "winter")

        self.f.day = 90
        self.f.update_season()
        self.assertEqual(self.f.world.season.name, "spring")

    def test_set_username(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p

        self.assertTrue(self.f.set_username(p, "Derp"))

        self.assertTrue("Derp" in self.f.protocols)
        self.assertTrue("Hurp" not in self.f.protocols)
        self.assertEqual(p.username, "Derp")

    def test_set_username_taken(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p
        self.f.protocols["Derp"] = None

        self.assertFalse(self.f.set_username(p, "Derp"))

        self.assertEqual(p.username, "Hurp")

    def test_set_username_noop(self):
        p = MockProtocol(None)
        p.username = "******"
        self.f.protocols["Hurp"] = p

        self.assertFalse(self.f.set_username(p, "Hurp"))
Пример #19
0
class TestBravoFactoryStarted(unittest.TestCase):
    """
    Tests which require ``startFactory()`` to be called.
    """

    def setUp(self):
        # Same setup as World, because Factory is very automagical.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        d = {
            "automatons"    : "",
            "generators"    : "",
            "mode"          : "creative",
            "port"          : "0",
            "seasons"       : "winter, spring",
            "serializer"    : "memory",
            "url"           : "",
        }
        for k, v in d.items():
            self.bcp.set("world unittest", k, v)

        self.f = BravoFactory(self.bcp, self.name)
        # And now start the factory.
        self.f.startFactory()

    def tearDown(self):
        self.f.stopFactory()

    def test_trivial(self):
        pass

    def test_create_entity_pickup(self):
        entity = self.f.create_entity(0, 0, 0, "Item")
        self.assertEqual(entity.eid, 2)
        self.assertEqual(self.f.eid, 2)

    def test_create_entity_player(self):
        entity = self.f.create_entity(0, 0, 0, "Player", username="******")
        self.assertEqual(entity.eid, 2)
        self.assertEqual(entity.username, "unittest")
        self.assertEqual(self.f.eid, 2)

    def test_give(self):
        self.f.give((0, 0, 0), (2, 0), 1)

    def test_give_oversized(self):
        """
        Check that oversized inputs to ``give()`` merely cause lots of pickups
        to be spawned.
        """

        # Our check consists of counting the number of times broadcast is
        # called.
        count = [0]
        def broadcast(packet):
            count[0] += 1
        self.patch(self.f, "broadcast", broadcast)

        # 65 blocks should be split into two stacks.
        self.f.give((0, 0, 0), (2, 0), 65)
        self.assertEqual(count[0], 2)

    def test_players_near(self):
        # Register some protocols with a player on the factory first.
        players = [
            self.f.create_entity(0, 0, 0, "Player", username=""),   # eid 2
            self.f.create_entity(0, 2, 0, "Player", username=""),   # eid 3
            self.f.create_entity(1, 0, 3, "Player", username=""),   # eid 4
            self.f.create_entity(0, 4, 1, "Player", username=""),   # eid 5
        ]

        for i, player in enumerate(players):
            self.f.protocols[i] = MockProtocol(player)

        # List of tests (player in the center, radius, expected eids).
        expected_results = [
            (players[0], 1, []),
            (players[0], 2, [3]),
            (players[0], 4, [3, 4]),
            (players[0], 5, [3, 4, 5]),
            (players[1], 3, [2, 5]),
        ]

        for player, radius, result in expected_results:
            found = [p.eid for p in self.f.players_near(player, radius)]
            self.assertEqual(set(found), set(result))
Пример #20
0
class TestWorldChunks(unittest.TestCase):
    def setUp(self):
        self.name = "unittest"
        self.d = tempfile.mkdtemp()
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "file://%s" % self.d)
        self.bcp.set("world unittest", "serializer", "alpha")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()
        shutil.rmtree(self.d)

    def test_trivial(self):
        pass

    @inlineCallbacks
    def test_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
                                        dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = numpy.fromstring(numpy.random.bytes(
            chunk.blocks.size),
                                          dtype=numpy.uint8)
        chunk.metadata.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
                                        dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback_negative(self):
        chunk = yield self.w.request_chunk(-1, -1)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
                                        dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(-1, -1)

        for x, y, z in product(xrange(2), repeat=3):
            block = yield self.w.get_block((x - 16, y, z - 16))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = numpy.fromstring(numpy.random.bytes(
            chunk.blocks.size),
                                          dtype=numpy.uint8)
        chunk.metadata.shape = (16, 16, 128)

        # Evict the chunk and grab it again.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Reload chunk.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(0, 0)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((12, 64, 4))
        chunk = yield self.w.request_chunk(0, 0)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty_offset(self):
        chunk = yield self.w.request_chunk(1, 2)

        # Reload chunk.
        self.w.save_chunk(chunk)
        del chunk
        self.w.chunk_cache.clear()
        self.w.dirty_chunk_cache.clear()
        chunk = yield self.w.request_chunk(1, 2)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((29, 64, 43))
        chunk = yield self.w.request_chunk(1, 2)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_sync_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
                                        dtype=numpy.uint8)
        chunk.blocks.shape = (16, 16, 128)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = self.w.sync_get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    def test_sync_get_block_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.w.sync_get_block, (0, 0, 0))

    def test_sync_get_metadata_neighboring(self):
        """
        Even if a neighboring chunk is loaded, the target chunk could still be
        unloaded.

        Test with sync_get_metadata() to increase test coverage.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertRaises(ChunkNotLoaded, self.w.sync_get_metadata,
                              (16, 0, 0))

        return d
Пример #21
0
if len(sys.argv) <= 3:
    print "Not enough arguments."
    sys.exit()

d = retrieve_plugins(ITerrainGenerator)

size = int(sys.argv[1])
pipeline = [d[name] for name in sys.argv[2].split(",")]
target = sys.argv[3]

print "Making map of %dx%d chunks in %s" % (size, size, target)
print "Using pipeline: %s" % ", ".join(plugin.name for plugin in pipeline)

config = BravoConfigParser()
config.add_section("world mapgen")
config.set("world mapgen", "url", target)
config.set("world mapgen", "serializer", "beta")

world = World(config, "mapgen")
world.connect()
world.pipeline = pipeline
world.season = None
world.saving = True

counts = [1, 2, 4, 5, 8]
count = 0
total = size**2

cpu = 0
before = time.time()
for i, j in product(xrange(size), repeat=2):
Пример #22
0
class TestWater(TestCase):

    def setUp(self):
        # Set up world.
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

        # And finally the mock factory.
        self.f = PhysicsMockFactory()
        self.f.world = self.w

        # Using dig hook to grab the plugin since the build hook was nuked in
        # favor of the automaton interface.
        self.p = bravo.plugin.retrieve_plugins(IDigHook, factory=self.f)
        self.hook = self.p["water"]

    def tearDown(self):
        self.w.stop()
        self.hook.stop()

    def test_trivial(self):
        pass

    def test_update_fluid_negative(self):
        """
        update_fluid() should always return False for Y at the bottom of the
        world.
        """

        self.assertFalse(self.hook.update_fluid(self.w, (0, -1, 0), False))

    def test_update_fluid_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.hook.update_fluid, self.w,
            (0, 0, 0), False)

    def test_update_fluid(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), False))
            self.assertEqual(self.w.sync_get_block((0, 0, 0)),
                blocks["water"].slot)
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 0)

        return d

    def test_update_fluid_metadata(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), False,
                1))
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 1)

        return d

    def test_update_fluid_falling(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), True))
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 8)

        return d

    def test_zero_y(self):
        """
        Double-check that water placed on the very bottom of the world doesn't
        cause internal errors.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium; if any exceptions happen,
        # they will bubble up.
        while self.hook.tracked:
            self.hook.process()

    def test_spring_spread(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((1, 0, 1), blocks["spring"].slot)
            self.hook.tracked.add((1, 0, 1))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((2, 0, 1), (1, 0, 2), (0, 0, 1), (1, 0, 0)):
                self.assertEqual(chunk.get_block(coords),
                    blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x0)

        return d

    def test_spring_spread_edge(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((1, 0, 0), (0, 0, 1)):
                self.assertEqual(chunk.get_block(coords),
                    blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x0)

        return d

    def test_fluid_spread_edge(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((2, 0, 0), (1, 0, 1), (0, 0, 2)):
                self.assertEqual(chunk.get_block(coords),
                    blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x1)

        return d

    @inlineCallbacks
    def test_spring_fall(self):
        """
        Falling water should appear below springs.
        """

        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        block = yield self.w.get_block((0, 0, 0))
        metadata = yield self.w.get_metadata((0, 0, 0))
        self.assertEqual(block, blocks["water"].slot)
        self.assertEqual(metadata, 0x8)

    @inlineCallbacks
    def test_spring_fall_dig(self):
        """
        Destroying ground underneath spring should allow water to continue
        falling downwards.
        """

        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.w.set_block((0, 0, 0), blocks["dirt"].slot)
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        #dig away dirt under spring
        self.w.destroy((0, 0, 0))
        self.hook.tracked.add((0, 1, 0))

        while self.hook.tracked:
            self.hook.process()

        block = yield self.w.get_block((0, 0, 0))
        self.assertEqual(block, blocks["water"].slot)

    def test_spring_fall_dig_offset(self):
        """
        Destroying ground next to a spring should cause a waterfall effect.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):

            chunk.set_block((1, 1, 0), blocks["spring"].slot)
            chunk.set_block((1, 0, 0), blocks["dirt"].slot)
            chunk.set_block((1, 0, 1), blocks["dirt"].slot)
            self.hook.tracked.add((1, 1, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            # Dig away the dirt next to the dirt under the spring, and simulate
            # the dig hook by adding the block above it.
            chunk.destroy((1, 0, 1))
            self.hook.tracked.add((1, 1, 1))

            while self.hook.tracked:
                self.hook.process()

            self.assertEqual(chunk.get_block((1, 0, 1)), blocks["water"].slot)

        return d

    def test_trench(self):
        """
        Fluid should not spread across the top of existing fluid.

        This test is for a specific kind of trench-digging pattern.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 2, 0), blocks["spring"].slot)
            chunk.set_block((0, 1, 0), blocks["dirt"].slot)
            self.hook.tracked.add((0, 2, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            # Dig the dirt.
            self.w.destroy((0, 1, 0))
            self.hook.tracked.add((0, 1, 1))
            self.hook.tracked.add((0, 2, 0))
            self.hook.tracked.add((1, 1, 0))

            while self.hook.tracked:
                self.hook.process()

            block = chunk.get_block((0, 2, 2))
            self.assertEqual(block, blocks["air"].slot)

    @inlineCallbacks
    def test_obstacle(self):
        """
        Test that obstacles are flowed around correctly.
        """

        yield self.w.set_block((0, 0, 0), blocks["spring"].slot)
        yield self.w.set_block((1, 0, 0), blocks["stone"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Make sure that the water level behind the stone is 0x3, not 0x0.
        metadata = yield self.w.get_metadata((2, 0, 0))
        self.assertEqual(metadata, 0x3)

    @inlineCallbacks
    def test_sponge(self):
        """
        Test that sponges prevent water from spreading near them.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.w.set_block((3, 0, 0), blocks["sponge"].slot)
        self.hook.tracked.add((0, 0, 0))
        self.hook.tracked.add((3, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Make sure that water did not spread near the sponge.
        block = yield self.w.get_block((1, 0, 0))
        self.assertNotEqual(block, blocks["water"].slot)

    def test_sponge_absorb_spring(self):
        """
        Test that sponges can absorb springs and will cause all of the
        surrounding water to dry up.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            self.w.set_block((1, 0, 0), blocks["sponge"].slot)
            self.hook.tracked.add((1, 0, 0))

            while self.hook.tracked:
                self.hook.process()

            for coords in ((0, 0, 0), (0, 0, 1)):
                block = yield self.w.get_block(coords)
                self.assertEqual(block, blocks["air"].slot)

            # Make sure that water did not spread near the sponge.
            block = yield self.w.get_block((1, 0, 0))
            self.assertNotEqual(block, blocks["water"].slot)

        return d

    @inlineCallbacks
    def test_sponge_salt(self):
        """
        Test that sponges don't "salt the earth" or have any kind of lasting
        effects after destruction.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        chunk = yield self.w.request_chunk(0, 0)

        # Take a snapshot at the base level, with a clever slice.
        before = chunk.sections[0].blocks[:256], chunk.sections[0].metadata[:256]

        self.w.set_block((3, 0, 0), blocks["sponge"].slot)
        self.hook.tracked.add((3, 0, 0))

        while self.hook.tracked:
            self.hook.process()

        self.w.destroy((3, 0, 0))
        self.hook.tracked.add((3, 0, 0))

        while self.hook.tracked:
            self.hook.process()

        # Make another snapshot, for comparison.
        after = chunk.sections[0].blocks[:256], chunk.sections[0].metadata[:256]

        # Make sure that the sponge didn't permanently change anything.
        self.assertEqual(before, after)

    @inlineCallbacks
    def test_spring_remove(self):
        """
        Test that water dries up if no spring is providing it.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Remove the spring.
        self.w.destroy((0, 0, 0))
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        for coords in ((1, 0, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1)):
            block = yield self.w.get_block(coords)
            self.assertEqual(block, blocks["air"].slot)

    @inlineCallbacks
    def test_spring_underneath_keepalive(self):
        """
        Test that springs located at a lower altitude than stray water do not
        keep that stray water alive.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Remove the upper spring.
        self.w.destroy((0, 1, 0))
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Check that the upper water blocks dried out. Don't care about the
        # lower ones in this test.
        for coords in ((1, 1, 0), (-1, 1, 0), (0, 1, 1), (0, 1, -1)):
            block = yield self.w.get_block(coords)
            self.assertEqual(block, blocks["air"].slot)
Пример #23
0
class TestWorldChunks(unittest.TestCase):

    def setUp(self):
        self.name = "unittest"
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "")
        self.bcp.set("world unittest", "serializer", "memory")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

    def tearDown(self):
        self.w.stop()

    def test_trivial(self):
        pass

    @inlineCallbacks
    def test_request_chunk_identity(self):
        first = yield self.w.request_chunk(0, 0)
        second = yield self.w.request_chunk(0, 0)
        self.assertIs(first, second)

    @inlineCallbacks
    def test_request_chunk_cached_identity(self):
        # Turn on the cache and get a few chunks in there, then request a
        # chunk that is in the cache.
        yield self.w.enable_cache(1)
        first = yield self.w.request_chunk(0, 0)
        second = yield self.w.request_chunk(0, 0)
        self.assertIs(first, second)

    @inlineCallbacks
    def test_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = array("B")
        chunk.metadata.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = yield self.w.get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_block_readback_negative(self):
        chunk = yield self.w.request_chunk(-1, -1)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(-1, -1)

        for x, y, z in product(xrange(2), repeat=3):
            block = yield self.w.get_block((x - 16, y, z - 16))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    @inlineCallbacks
    def test_get_metadata_readback(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.metadata = array("B")
        chunk.metadata.fromstring(os.urandom(32768))

        # Evict the chunk and grab it again.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            metadata = yield self.w.get_metadata((x, y, z))
            self.assertEqual(metadata, chunk.get_metadata((x, y, z)))

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Reload chunk.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(0, 0)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((12, 64, 4))
        chunk = yield self.w.request_chunk(0, 0)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_world_level_mark_chunk_dirty_offset(self):
        chunk = yield self.w.request_chunk(1, 2)

        # Reload chunk.
        yield self.w.save_chunk(chunk)
        del chunk
        chunk = yield self.w.request_chunk(1, 2)

        self.assertFalse(chunk.dirty)
        self.w.mark_dirty((29, 64, 43))
        chunk = yield self.w.request_chunk(1, 2)
        self.assertTrue(chunk.dirty)

    @inlineCallbacks
    def test_sync_get_block(self):
        chunk = yield self.w.request_chunk(0, 0)

        # Fill the chunk with random stuff.
        chunk.blocks = array("B")
        chunk.blocks.fromstring(os.urandom(32768))

        for x, y, z in product(xrange(2), repeat=3):
            # This works because the chunk is at (0, 0) so the coords don't
            # need to be adjusted.
            block = self.w.sync_get_block((x, y, z))
            self.assertEqual(block, chunk.get_block((x, y, z)))

    def test_sync_get_block_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.w.sync_get_block, (0, 0, 0))

    def test_sync_get_metadata_neighboring(self):
        """
        Even if a neighboring chunk is loaded, the target chunk could still be
        unloaded.

        Test with sync_get_metadata() to increase test coverage.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertRaises(ChunkNotLoaded,
                              self.w.sync_get_metadata, (16, 0, 0))

        return d
Пример #24
0
class TestWater(unittest.TestCase):
    def setUp(self):
        # Set up world.
        self.name = "unittest"
        self.d = tempfile.mkdtemp()
        self.bcp = BravoConfigParser()

        self.bcp.add_section("world unittest")
        self.bcp.set("world unittest", "url", "file://%s" % self.d)
        self.bcp.set("world unittest", "serializer", "alpha")

        self.w = World(self.bcp, self.name)
        self.w.pipeline = []
        self.w.start()

        # And finally the mock factory.
        self.f = PhysicsMockFactory()
        self.f.world = self.w

        # Using dig hook to grab the plugin since the build hook was nuked in
        # favor of the automaton interface.
        pp = {"factory": self.f}
        self.p = bravo.plugin.retrieve_plugins(IDigHook, parameters=pp)

        if "water" not in self.p:
            raise unittest.SkipTest("Plugin not present")

        self.hook = self.p["water"]

    def tearDown(self):
        self.w.stop()
        self.hook.stop()
        shutil.rmtree(self.d)

    def test_trivial(self):
        pass

    def test_update_fluid_negative(self):
        """
        update_fluid() should always return False for Y at the bottom of the
        world.
        """

        self.assertFalse(self.hook.update_fluid(self.w, (0, -1, 0), False))

    def test_update_fluid_unloaded(self):
        self.assertRaises(ChunkNotLoaded, self.hook.update_fluid, self.w,
                          (0, 0, 0), False)

    def test_update_fluid(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), False))
            self.assertEqual(self.w.sync_get_block((0, 0, 0)),
                             blocks["water"].slot)
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 0)

        return d

    def test_update_fluid_metadata(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), False,
                                                   1))
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 1)

        return d

    def test_update_fluid_falling(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            self.assertTrue(self.hook.update_fluid(self.w, (0, 0, 0), True))
            self.assertEqual(self.w.sync_get_metadata((0, 0, 0)), 8)

        return d

    def test_zero_y(self):
        """
        Double-check that water placed on the very bottom of the world doesn't
        cause internal errors.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium; if any exceptions happen,
        # they will bubble up.
        while self.hook.tracked:
            self.hook.process()

    def test_spring_spread(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((1, 0, 1), blocks["spring"].slot)
            self.hook.tracked.add((1, 0, 1))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((2, 0, 1), (1, 0, 2), (0, 0, 1), (1, 0, 0)):
                self.assertEqual(chunk.get_block(coords), blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x0)

        return d

    def test_spring_spread_edge(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((1, 0, 0), (0, 0, 1)):
                self.assertEqual(chunk.get_block(coords), blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x0)

        return d

    def test_fluid_spread_edge(self):
        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            for coords in ((2, 0, 0), (1, 0, 1), (0, 0, 2)):
                self.assertEqual(chunk.get_block(coords), blocks["water"].slot)
                self.assertEqual(chunk.get_metadata(coords), 0x1)

        return d

    @inlineCallbacks
    def test_spring_fall(self):
        """
        Falling water should appear below springs.
        """

        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        block = yield self.w.get_block((0, 0, 0))
        metadata = yield self.w.get_metadata((0, 0, 0))
        self.assertEqual(block, blocks["water"].slot)
        self.assertEqual(metadata, 0x8)

    @inlineCallbacks
    def test_spring_fall_dig(self):
        """
        Destroying ground underneath spring should allow water to continue
        falling downwards.
        """

        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.w.set_block((0, 0, 0), blocks["dirt"].slot)
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        #dig away dirt under spring
        self.w.destroy((0, 0, 0))
        self.hook.tracked.add((0, 1, 0))

        while self.hook.tracked:
            self.hook.process()

        block = yield self.w.get_block((0, 0, 0))
        self.assertEqual(block, blocks["water"].slot)

    def test_spring_fall_dig_offset(self):
        """
        Destroying ground next to a spring should cause a waterfall effect.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):

            chunk.set_block((1, 1, 0), blocks["spring"].slot)
            chunk.set_block((1, 0, 0), blocks["dirt"].slot)
            chunk.set_block((1, 0, 1), blocks["dirt"].slot)
            self.hook.tracked.add((1, 1, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            # Dig away the dirt next to the dirt under the spring, and simulate
            # the dig hook by adding the block above it.
            chunk.destroy((1, 0, 1))
            self.hook.tracked.add((1, 1, 1))

            while self.hook.tracked:
                self.hook.process()

            self.assertEqual(chunk.get_block((1, 0, 1)), blocks["water"].slot)

        return d

    def test_trench(self):
        """
        Fluid should not spread across the top of existing fluid.

        This test is for a specific kind of trench-digging pattern.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 2, 0), blocks["spring"].slot)
            chunk.set_block((0, 1, 0), blocks["dirt"].slot)
            self.hook.tracked.add((0, 2, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            # Dig the dirt.
            self.w.destroy((0, 1, 0))
            self.hook.tracked.add((0, 1, 1))
            self.hook.tracked.add((0, 2, 0))
            self.hook.tracked.add((1, 1, 0))

            while self.hook.tracked:
                self.hook.process()

            block = chunk.get_block((0, 2, 2))
            self.assertEqual(block, blocks["air"].slot)

    @inlineCallbacks
    def test_obstacle(self):
        """
        Test that obstacles are flowed around correctly.
        """

        yield self.w.set_block((0, 0, 0), blocks["spring"].slot)
        yield self.w.set_block((1, 0, 0), blocks["stone"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Make sure that the water level behind the stone is 0x3, not 0x0.
        metadata = yield self.w.get_metadata((2, 0, 0))
        self.assertEqual(metadata, 0x3)

    @inlineCallbacks
    def test_sponge(self):
        """
        Test that sponges prevent water from spreading near them.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.w.set_block((3, 0, 0), blocks["sponge"].slot)
        self.hook.tracked.add((0, 0, 0))
        self.hook.tracked.add((3, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Make sure that water did not spread near the sponge.
        block = yield self.w.get_block((1, 0, 0))
        self.assertNotEqual(block, blocks["water"].slot)

    def test_sponge_absorb_spring(self):
        """
        Test that sponges can absorb springs and will cause all of the
        surrounding water to dry up.
        """

        d = self.w.request_chunk(0, 0)

        @d.addCallback
        def cb(chunk):
            chunk.set_block((0, 0, 0), blocks["spring"].slot)
            self.hook.tracked.add((0, 0, 0))

            # Tight-loop run the hook to equilibrium.
            while self.hook.tracked:
                self.hook.process()

            self.w.set_block((1, 0, 0), blocks["sponge"].slot)
            self.hook.tracked.add((1, 0, 0))

            while self.hook.tracked:
                self.hook.process()

            for coords in ((0, 0, 0), (0, 0, 1)):
                block = yield self.w.get_block(coords)
                self.assertEqual(block, blocks["air"].slot)

            # Make sure that water did not spread near the sponge.
            block = yield self.w.get_block((1, 0, 0))
            self.assertNotEqual(block, blocks["water"].slot)

        return d

    @inlineCallbacks
    def test_sponge_salt(self):
        """
        Test that sponges don't "salt the earth" or have any kind of lasting
        effects after destruction.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Take a snapshot.
        chunk = yield self.w.request_chunk(0, 0)
        before = chunk.blocks[:, :, 0], chunk.metadata[:, :, 0]

        self.w.set_block((3, 0, 0), blocks["sponge"].slot)
        self.hook.tracked.add((3, 0, 0))

        while self.hook.tracked:
            self.hook.process()

        self.w.destroy((3, 0, 0))
        self.hook.tracked.add((3, 0, 0))

        while self.hook.tracked:
            self.hook.process()

        after = chunk.blocks[:, :, 0], chunk.metadata[:, :, 0]

        # Make sure that the sponge didn't permanently change anything.
        assert_array_equal(before, after)

    @inlineCallbacks
    def test_spring_remove(self):
        """
        Test that water dries up if no spring is providing it.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Remove the spring.
        self.w.destroy((0, 0, 0))
        self.hook.tracked.add((0, 0, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        for coords in ((1, 0, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1)):
            block = yield self.w.get_block(coords)
            self.assertEqual(block, blocks["air"].slot)

    @inlineCallbacks
    def test_spring_underneath_keepalive(self):
        """
        Test that springs located at a lower altitude than stray water do not
        keep that stray water alive.
        """

        self.w.set_block((0, 0, 0), blocks["spring"].slot)
        self.w.set_block((0, 1, 0), blocks["spring"].slot)
        self.hook.tracked.add((0, 0, 0))
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Remove the upper spring.
        self.w.destroy((0, 1, 0))
        self.hook.tracked.add((0, 1, 0))

        # Tight-loop run the hook to equilibrium.
        while self.hook.tracked:
            self.hook.process()

        # Check that the upper water blocks dried out. Don't care about the
        # lower ones in this test.
        for coords in ((1, 1, 0), (-1, 1, 0), (0, 1, 1), (0, 1, -1)):
            block = yield self.w.get_block(coords)
            self.assertEqual(block, blocks["air"].slot)