import unittest
from pygame.tests.test_utils import fixture_path
import pygame


class CursorsModuleTest(unittest.TestCase):
    def test_compile(self):

        # __doc__ (as of 2008-06-25) for pygame.cursors.compile:

        # pygame.cursors.compile(strings, black, white,xor) -> data, mask
        # compile cursor strings into cursor data
        #
        # This takes a set of strings with equal length and computes
        # the binary data for that cursor. The string widths must be
        # divisible by 8.
        #
        # The black and white arguments are single letter strings that
        # tells which characters will represent black pixels, and which
        # characters represent white pixels. All other characters are
        # considered clear.
        #
        # This returns a tuple containing the cursor data and cursor mask
        # data. Both these arguments are used when setting a cursor with
        # pygame.mouse.set_cursor().

        #Various types of input strings
        test_cursor1 = (
            "X.X.XXXX",
            "XXXXXX..",
            "  XXXX  "
        )

        test_cursor2 = (
            "X.X.XXXX",
            "XXXXXX..",
            "XXXXXX ",
            "XXXXXX..",
            "XXXXXX..",
            "XXXXXX",
            "XXXXXX..",
            "XXXXXX.."
        )
        test_cursor3 = (
            ".XX.",
            "  ",
            "..  ",
            "X.. X"
        )
        
        # Test such that total number of strings is not divisible by 8
        with self.assertRaises(ValueError):
            pygame.cursors.compile(test_cursor1)

        # Test such that size of individual string is not divisible by 8
        with self.assertRaises(ValueError):
            pygame.cursors.compile(test_cursor2)

        # Test such that neither size of individual string nor total number of strings is divisible by 8
        with self.assertRaises(ValueError):
            pygame.cursors.compile(test_cursor3)

        #Test that checks whether the byte data from compile funtion is equal to actual byte data
        actual_byte_data = (192, 0, 0, 224, 0, 0, 240, 0, 0, 216, 0, 0, 
            204, 0, 0, 198, 0, 0, 195, 0, 0, 193, 128, 0, 192, 192, 0, 192, 96, 0, 192, 48, 0, 
            192, 56, 0, 192, 248, 0, 220, 192, 0, 246, 96, 0, 198, 96, 0, 6, 96, 0, 3, 48, 0, 
            3, 48, 0, 1, 224, 0, 1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (192, 0, 0, 224, 0, 0, 
            240, 0, 0, 248, 0, 0, 252, 0, 0, 254, 0, 0, 255, 0, 0, 255, 128, 0, 255, 192, 0, 255, 
            224, 0, 255, 240, 0, 255, 248, 0, 255, 248, 0, 255, 192, 0, 247, 224, 0, 199, 224, 
            0, 7, 224, 0, 3, 240, 0, 3, 240, 0, 1, 224, 0, 1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

        cursor = pygame.cursors.compile(pygame.cursors.thickarrow_strings)
        self.assertEqual(cursor,actual_byte_data)

        #Test such that cursor byte data obtained from compile function is valid in pygame.mouse.set_cursor()
        pygame.display.init()
        try:
            pygame.mouse.set_cursor((24, 24), (0, 0), *cursor)
        except pygame.error as e:
            if "not currently supported" in str(e):
                unittest.skip("skipping test as set_cursor() is not supported")
        finally:
            pygame.display.quit()


################################################################################

    def test_load_xbm(self):
        # __doc__ (as of 2008-06-25) for pygame.cursors.load_xbm:

        # pygame.cursors.load_xbm(cursorfile, maskfile) -> cursor_args
        # reads a pair of XBM files into set_cursor arguments
        #
        # Arguments can either be filenames or filelike objects
        # with the readlines method. Not largely tested, but
        # should work with typical XBM files.

        # Test that load_xbm will take filenames as arguments
        cursorfile = fixture_path(r"xbm_cursors/white_sizing.xbm")
        maskfile = fixture_path(r"xbm_cursors/white_sizing_mask.xbm")
        cursor = pygame.cursors.load_xbm(cursorfile, maskfile)

        # Test that load_xbm will take file objects as arguments
        with open(cursorfile) as cursor_f, open(maskfile) as mask_f:
            cursor = pygame.cursors.load_xbm(cursor_f, mask_f)

        # Is it in a format that mouse.set_cursor won't blow up on?
        pygame.display.init()
        try:
            pygame.mouse.set_cursor(*cursor)
        except pygame.error as e:
            if "not currently supported" in str(e):
                unittest.skip("skipping test as set_cursor() is not supported")
        finally:
            pygame.display.quit()


    def test_Cursor(self):
        """Ensure that the cursor object parses information properly"""

        c1 = pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_CROSSHAIR)

        self.assertEqual(c1.data, (pygame.SYSTEM_CURSOR_CROSSHAIR,))
        self.assertEqual(c1.type, "system")

        c2 = pygame.cursors.Cursor(c1)

        self.assertEqual(c1, c2)

        with self.assertRaises(TypeError):
            pygame.cursors.Cursor(-34002)
        with self.assertRaises(TypeError):
            pygame.cursors.Cursor("a", "b", "c", "d")
        with self.assertRaises(TypeError):
            pygame.cursors.Cursor((2,))

        c3 = pygame.cursors.Cursor((0,0), pygame.Surface((20,20)))

        self.assertEqual(c3.data[0], (0,0))
        self.assertEqual(c3.data[1].get_size(), (20, 20))
        self.assertEqual(c3.type, "color")

        xormask, andmask = pygame.cursors.compile(pygame.cursors.thickarrow_strings)
        c4 = pygame.cursors.Cursor((24, 24), (0, 0), xormask, andmask)

        self.assertEqual(c4.data, ((24,24), (0,0), xormask, andmask))
        self.assertEqual(c4.type, "bitmap")

################################################################################

if __name__ == "__main__":
    unittest.main()

################################################################################
