예제 #1
0
    def parse_point(cli_input: str):
        """
        Parse either a relative point from input, e.g. '+10,-12' OR an absolute point
        from input, e.g. '10,20'.
        :param cli_input: string
        :return Success(AbsoluteParserPoint or RelativeParserPoint, remainder) if input contains either valid
        absolute point or relative point, Failure(expected format, the given cli_input) otherwise
        """
        first_nat_parser = NatParser(',')
        second_nat_parser = NatParser()
        first_int_parser = IntParser(',')
        second_int_parser = IntParser()

        # Parse absolute point from given input
        abs_point_parse = PointParser().parse_input(first_nat_parser,
                                                    second_nat_parser,
                                                    cli_input)
        if abs_point_parse.is_successful():
            abs_point = AbsoluteParserPoint(abs_point_parse.get_match()[0],
                                            abs_point_parse.get_match()[1])
            return Success(abs_point, abs_point_parse.get_remainder())

        # Parse relative point from given input
        rel_point_parse = PointParser().parse_input(first_int_parser,
                                                    second_int_parser,
                                                    cli_input)
        if rel_point_parse.is_successful():
            rel_point = RelativeParserPoint(rel_point_parse.get_match()[0],
                                            rel_point_parse.get_match()[1])
            return Success(rel_point, rel_point_parse.get_remainder())

        # Both parsers has failed to parse a point, return the last result (a Failure object)
        return rel_point_parse
예제 #2
0
    def parse_params(self, cli_input: str) -> ParseResult:
        points_result = self.parse_two_points(cli_input)
        if points_result.is_successful():
            abs_points = self.convert_points(points_result.get_match())

            # Parse color
            color_result = self.parse_color(points_result.get_remainder(),
                                            self.color_parser)
            if color_result.is_successful():
                start_x = abs_points[0].x
                start_y = abs_points[0].y
                end_x = abs_points[1].x
                end_y = abs_points[1].y
                return Success(
                    PrintRectCommand(
                        self._controller,
                        start_x,
                        start_y,
                        color_result.get_match(),
                        end_x=end_x,
                        end_y=end_y,
                    ), '')
            else:
                return Failure(color_result.get_expected(),
                               points_result.get_remainder())

        point_and_nats_result = self.parse_point_and_nats(cli_input)
        if point_and_nats_result.is_successful():
            width = point_and_nats_result.get_match()[1]
            height = point_and_nats_result.get_match()[2]

            abs_points = self.convert_points(
                [point_and_nats_result.get_match()[0]])

            # Parse color
            color_result = self.parse_color(
                point_and_nats_result.get_remainder(), self.color_parser)
            if color_result.is_successful():
                start_x = abs_points[0].x
                start_y = abs_points[0].y
                return Success(
                    PrintRectCommand(self._controller,
                                     start_x,
                                     start_y,
                                     color_result.get_match(),
                                     DimensionsRectFactory,
                                     width=width,
                                     height=height), '')
            else:
                return Failure(color_result.get_expected(),
                               point_and_nats_result.get_remainder())

        return Failure(
            points_result.get_expected() + ' | ' +
            point_and_nats_result.get_expected(), cli_input)
예제 #3
0
    def parse_params(self, cli_input: str) -> ParseResult:
        points_result = self.parse_two_points(cli_input)
        if points_result.is_successful():
            abs_points = self.convert_points(points_result.get_match())
            start_x = abs_points[0].x
            start_y = abs_points[0].y
            end_x = abs_points[1].x
            end_y = abs_points[1].y

            # Parse color
            color_result = self.parse_color(points_result.get_remainder(),
                                            self.color_parser)
            if color_result.is_successful():
                color = color_result.get_match()
                return Success(
                    PrintCircleCommand(self._controller,
                                       start_x,
                                       start_y,
                                       color,
                                       end_x=end_x,
                                       end_y=end_y), '')
            else:
                return Failure(color_result.get_expected(),
                               points_result.get_remainder())

        point_and_nat_result = self.parse_point_and_nat(cli_input)
        if point_and_nat_result.is_successful():
            radius = point_and_nat_result.get_match()[1]

            abs_point = self.convert_points(
                [point_and_nat_result.get_match()[0]])
            start_x = abs_point[0].x
            start_y = abs_point[0].y

            # Parse color
            color_result = self.parse_color(
                point_and_nat_result.get_remainder(), self.color_parser)
            if color_result.is_successful():
                color = color_result.get_match()
                return Success(
                    PrintCircleCommand(self._controller,
                                       start_x,
                                       start_y,
                                       color,
                                       DimensionsCircleFactory,
                                       radius=radius), '')
            else:
                return Failure(color_result.get_expected(),
                               point_and_nat_result.get_remainder())

        return Failure(
            points_result.get_expected() + ' | ' +
            point_and_nat_result.get_expected(), cli_input)
예제 #4
0
    def parse_color(self, cli_input: str,
                    color_parser: ColorParser) -> ParseResult:
        """
        Parse a Color from given input.
        """
        default_color = Color(0, 0, 0)
        if cli_input == '':
            return Success(default_color, '')

        color_result = color_parser.parse_color(cli_input)
        if color_result.is_successful():
            return Success(color_result.get_match(), '')

        return Failure(color_result.get_expected(), cli_input)
예제 #5
0
    def parse_params(self, cli_input: str):
        if cli_input == '':
            # point parameter is absent, return ListShapeCommand with default values of parameters x and y
            return Success(ListShapeCommand(self._controller), '')

        result = PointParser.parse_point(cli_input)
        if result.is_successful():
            abs_point = self.convert_points([result.get_match()])

            x = abs_point[0].x
            y = abs_point[0].y
            return Success(ListShapeCommand(self._controller, x, y),
                           result.get_remainder())
        else:
            return result
예제 #6
0
def test_point_parser_relative_points():
    """
    Test PointParser's parsing of relative points.
    """
    parser = PointParser()

    # Test invalid inputs
    invalid_inputs = [
        '-10 -20', '-10.-20', '+10', '+ 10,-20', '+10,- 20', '-10,', '+x,-20',
        '-10,+y', '-x,-y'
    ]
    for cli_input in invalid_inputs:
        result = parser.parse_point(cli_input)
        assert result == Failure("x,y or (+-)x,(+-)y", cli_input)

    # Test valid inputs
    valid_inputs = [
        ('-10,+20', RelativeParserPoint(-10, 20), ''),
        ('+10,+20 ', RelativeParserPoint(10, 20), ''),
        ('-10  ,-20', RelativeParserPoint(-10, -20), ''),
        ('+10,   -20', RelativeParserPoint(10, -20), ''),
        ('-10  ,  +20', RelativeParserPoint(-10, 20), ''),
        ('  +10  ,  -20', RelativeParserPoint(10, -20), ''),
        ('  +10  ,  -20   something', RelativeParserPoint(10,
                                                          -20), 'something'),
        ('+100,-250 something', RelativeParserPoint(100, -250), 'something'),
        ('-0,+0', RelativeParserPoint(0, 0), ''),
        ('+10,-20 30,40', RelativeParserPoint(10, -20), '30,40')
    ]
    for cli_input, expected, remainder in valid_inputs:
        result = parser.parse_point(cli_input)
        assert result == Success(expected, remainder)
예제 #7
0
def test_rgb_color_parser():
    """
    Test RgbColorParser's parsing of color in 'rgb([0,255],[0,255],[0,255])' format.
    """
    parser = RgbColorParser()

    # Test invalid inputs
    invalid_inputs = [
        "r gb(0,1,2)", "rgb 0,1,2)", "rgb(0,1,2", "rgb(-5,1,2)",
        "rgb(-5,-1-2)", "rgb(256,1,2)", "rgb(0,256,2)", "rgb(0,1,256)",
        "rgb(260,300,600)"
    ]
    for cli_input in invalid_inputs:
        result = parser.parse_color(cli_input)
        assert result == Failure("rgb([0,255],[0,255],[0,255])", cli_input)

    valid_inputs = [
        ("rgb(0,1,2)", (0, 1, 2), ""),
        ("rgb(255,255,255)", (255, 255, 255), ""),
        ("   rgb( 0,1,2)", (0, 1, 2), ""), ("rgb (0, 1,2 )", (0, 1, 2), ""),
        ("rgb (0,1,2)", (0, 1, 2), ""),
        ("rgb (20,30,40)   something else", (20, 30, 40), "something else"),
        ("rgb ( 0    ,1 ,  2   )    something", (0, 1, 2), "something")
    ]
    # Test valid inputs
    for cli_input, expected, remainder in valid_inputs:
        result = parser.parse_color(cli_input)
        assert result == Success(expected, remainder)
예제 #8
0
def test_point_parser_absolute_points():
    """
    Test PointParser's parsing of absolute points.
    """
    parser = PointParser()

    # Test invalid inputs
    invalid_inputs = [
        '1020', '10 20', '10.20', '10', '10,', 'x,20', '10,y', 'x,y'
    ]
    for cli_input in invalid_inputs:
        result = parser.parse_point(cli_input)
        assert result == Failure("x,y or (+-)x,(+-)y", cli_input)

    # Test valid inputs
    valid_inputs = [
        ('10,20', AbsoluteParserPoint(10, 20), ''),
        ('10,20 ', AbsoluteParserPoint(10, 20), ''),
        ('10  ,20', AbsoluteParserPoint(10, 20), ''),
        ('10,   20', AbsoluteParserPoint(10, 20), ''),
        ('10  ,  20', AbsoluteParserPoint(10, 20), ''),
        ('  10  ,  20', AbsoluteParserPoint(10, 20), ''),
        ('  10  ,  20   something', AbsoluteParserPoint(10, 20), 'something'),
        ('100,250 something', AbsoluteParserPoint(100, 250), 'something'),
        ('0,0', AbsoluteParserPoint(0, 0), ''),
        ('10,20 30,40', AbsoluteParserPoint(10, 20), '30,40')
    ]
    for cli_input, expected, remainder in valid_inputs:
        result = parser.parse_point(cli_input)
        assert result == Success(expected, remainder)
예제 #9
0
    def parse_input(self, cli_input: str):
        result = super().parse_input(cli_input)
        if result.is_successful():
            integer = int(result.get_match())
            return Success(integer, result.get_remainder())

        return result
예제 #10
0
    def parse_params(self, cli_input: str) -> ParseResult:
        points_result = self.parse_two_points(cli_input)
        if points_result.is_successful():
            points = points_result.get_match()

            # two points parsed successfully, try to parse a color
            remainder = points_result.get_remainder()
            color_result = self.parse_color(remainder, self.color_parser)
            if color_result.is_successful():
                # color parsed successfully, no more points will be parsed
                color = color_result.get_match()

                abs_points = self.convert_points(points_result.get_match())
                start_x = abs_points[0].x
                start_y = abs_points[0].y
                end_x = abs_points[1].x
                end_y = abs_points[1].y
                return Success(
                    PrintLineCommand(self._controller, start_x, start_y, end_x,
                                     end_y, color), '')
            else:
                # try to parse a point or a color
                while True:
                    point_result = PointParser().parse_point(remainder)
                    if point_result.is_successful():
                        points.append(point_result.get_match())
                        remainder = point_result.get_remainder()
                    else:
                        color_result = self.parse_color(
                            remainder, self.color_parser)
                        if color_result.is_successful():
                            # color parsed successfully, no more points will be parsed
                            color = color_result.get_match()

                            abs_points = self.convert_points(points)
                            return Success(
                                PrintPolylineCommand(self._controller,
                                                     [(p.x, p.y)
                                                      for p in abs_points],
                                                     color),
                                color_result.get_remainder())
                        else:
                            break

        return Failure("line <POINT> <POINTS>", cli_input)
예제 #11
0
def test_string_parser():
    """
    Test StringParser used for parsing exact word from the beginning of a given string.
    """

    # Test invalid inputs without a delimiter
    invalid_inputs = [('rect', 'recta'), ('rect', 'list rect'),
                      ('rect', 'rect, '), ('rect', 'rect('), ('rect', 'RECT'),
                      ('rect', 'circle'), ('rect', '   circle'),
                      ('rect', 'rect10,20 30,40')]
    for expected, actual in invalid_inputs:
        parser = StringParser(expected, '')
        result = parser.parse_input(actual)
        assert isinstance(result, Failure)

    # Test valid inputs without a delimiter
    valid_inputs = [('rect', 'rect   +10  -10', '+10  -10'),
                    ('rect', 'rect    anything ', 'anything '),
                    ('rect', 'rect +1002', '+1002'),
                    ('rect', '  rect + 1 0 1 2', '+ 1 0 1 2'),
                    ('rect', '  rect', ''), ('rect', '   rect   +10', '+10')]
    for expected, actual, remainder in valid_inputs:
        parser = StringParser(expected, '')
        result = parser.parse_input(actual)
        assert result == Success(expected, remainder)

    # Test invalid inputs with a delimiter
    invalid_inputs = [('rgb', '(', 'rg b(20,20,20)'),
                      ('rgb', '(', '  rgb2(0...'), ('rgb', '(', 'rgb 20...')]
    for expected, delimiter, actual in invalid_inputs:
        parser = StringParser(expected, delimiter)
        result = parser.parse_input(actual)
        assert isinstance(result, Failure)

    # Test valid inputs with a delimiter
    valid_inputs = [('rgb', '(', 'rgb(20,20,20)', '20,20,20)'),
                    ('rgb', '(', '  rgb(20...', '20...'),
                    ('rgb', '(', 'rgb (20...', '20...'),
                    ('rgb', '(', 'rgb (   20...', '20...')]
    for expected, delimiter, actual, remainder in valid_inputs:
        parser = StringParser(expected, delimiter)
        result = parser.parse_input(actual)
        assert result == Success(expected, remainder)
예제 #12
0
    def parse_params(self, cli_input: str) -> ParseResult:
        result = PointParser().parse_point(cli_input)
        if result.is_successful():
            abs_point = self.convert_points([result.get_match()])

            x = abs_point[0].x
            y = abs_point[0].y
            return Success(RemoveShapeCommand(self._controller, x, y),
                           result.get_remainder())
        else:
            return result
예제 #13
0
    def parse_input(self, cli_input: str) -> ParseResult:
        if self._delimiter == '':
            match = re.match(r'^(\s*)(' + self._expected + ')(\s+|$)',
                             cli_input)
        else:
            match = re.match(
                r'^(\s*)(' + self._expected + ')' + r'(\s*)' +
                re.escape(self._delimiter) + r'(\s*|$)', cli_input)

        if match:
            remainder = cli_input[match.end():]
            return Success(match.group(2), remainder)
        else:
            return Failure(self._expected, cli_input)
예제 #14
0
    def parse_point_and_nat(self, cli_input: str) -> ParseResult:
        """
        Parse a Point and a Natural number from given input.
        """
        point_result = PointParser().parse_point(cli_input)
        if point_result.is_successful():
            radius_result = self.radius_parser.parse_input(
                point_result.get_remainder())
            if radius_result.is_successful():
                return Success(
                    [point_result.get_match(),
                     radius_result.get_match()], radius_result.get_remainder())

        return Failure("circle <POINT> <NAT>", cli_input)
예제 #15
0
    def parse_two_points(cli_input: str) -> ParseResult:
        """
        Parse two Points from given input.
        """
        point_result1 = PointParser().parse_point(cli_input)
        if point_result1.is_successful():
            point_result2 = PointParser().parse_point(
                point_result1.get_remainder())
            if point_result2.is_successful():
                return Success(
                    [point_result1.get_match(),
                     point_result2.get_match()], point_result2.get_remainder())

        return Failure("<POINT> <POINT>", cli_input)
예제 #16
0
    def parse_params(self, cli_input: str) -> ParseResult:
        result = self.parse_two_points(cli_input)
        if result.is_successful():
            abs_points = self.convert_points(result.get_match())

            start_x = abs_points[0].x
            start_y = abs_points[0].y
            end_x = abs_points[1].x
            end_y = abs_points[1].y
            return Success(
                MoveShapeCommand(self._controller, start_x, start_y, end_x,
                                 end_y), result.get_remainder())
        else:
            return result
예제 #17
0
    def parse_point_and_nats(self, cli_input: str) -> ParseResult:
        """
        Parse a Point and two Natural numbers from given input.
        """
        point_result = PointParser().parse_point(cli_input)
        if point_result.is_successful():
            width_result = self.width_parser.parse_input(
                point_result.get_remainder())
            if width_result.is_successful():
                height_result = self.height_parser.parse_input(
                    width_result.get_remainder())
                if height_result.is_successful():
                    return Success([
                        point_result.get_match(),
                        width_result.get_match(),
                        height_result.get_match()
                    ], height_result.get_remainder())

        return Failure("rect <POINT> <NAT> <NAT>", cli_input)
예제 #18
0
    def parse_params(self, cli_input: str) -> ParseResult:
        point_result = PointParser().parse_point(cli_input)
        if point_result.is_successful():
            abs_point = self.convert_points([point_result.get_match()])
            point_x = abs_point[0].x
            point_y = abs_point[0].y

            # Parse color
            color_result = self.parse_color(point_result.get_remainder(),
                                            self.color_parser)
            if color_result.is_successful():
                color = color_result.get_match()
                return Success(
                    PrintDotCommand(self._controller, point_x, point_y, color),
                    '')
            else:
                return Failure(color_result.get_expected(),
                               point_result.get_remainder())

        return Failure("dot <POINT>", cli_input)
예제 #19
0
    def parse_input(first_parser: NumberParser, second_parser: NumberParser,
                    cli_input: str) -> ParseResult:
        """ 
        Parse point from input using given NumberParsers. Both NumberParser must be of the same type!
        :param first_parser: NumberParser
        :param second_parser: NumberParser
        :param cli_input: string
        :return: Success([X coordinate, Y coordinate], string) if input contains a number within
        range, Failure(string, string) otherwise
        """
        # Parse a number using comma and only comma as a delimiter"
        result1 = first_parser.parse_input(cli_input)
        if result1.is_successful():
            # Parse a number using space or end of string as a delimiter"
            result2 = second_parser.parse_input(result1.get_remainder())
            if result2.is_successful():
                x = result1.get_match()
                y = result2.get_match()
                return Success([x, y], result2.get_remainder())

        return Failure('x,y or (+-)x,(+-)y', cli_input)
예제 #20
0
    def parse_color(self, cli_input: str) -> ParseResult:
        failure = Failure("rgb([0,255],[0,255],[0,255])", cli_input)

        # Parse prefix \"rgb(\"
        prefix_parse_result = self.string_parser.parse_input(cli_input)
        if not prefix_parse_result.is_successful():
            return failure

        # Parse red (first number)
        red_parse_result = self.first_nat_parser.parse_input(
            prefix_parse_result.get_remainder())
        if not red_parse_result.is_successful():
            return failure

        red = red_parse_result.get_match()

        # Parse green (second number)
        green_parse_result = self.first_nat_parser.parse_input(
            red_parse_result.get_remainder())
        if not green_parse_result.is_successful():
            return failure

        green = green_parse_result.get_match()

        # Parse blue (third number)
        blue_parse_result = self.second_nat_parser.parse_input(
            green_parse_result.get_remainder())
        if not blue_parse_result.is_successful():
            return failure

        blue = blue_parse_result.get_match()

        # Check if provided values form valid RGB color
        if 0 <= red <= 255 and 0 <= green <= 255 and 0 <= blue <= 255:
            return Success((red, green, blue),
                           blue_parse_result.get_remainder())
        else:
            return failure
예제 #21
0
 def parse_params(self, cli_input: str) -> ParseResult:
     if cli_input == '':
         return Success(LoadCommand(self._controller), '')
     else:
         return Success(LoadCommand(self._controller, cli_input), '')
예제 #22
0
def test_nat_parser():
    """
    Test NatParser's method "parse_input" used for parsing natural numbers (^\d+(\s+|$)) from a string.
    """
    parser = NatParser()

    # Test invalid inputs without a delimiter
    invalid_inputs = [
        '+10',
        '-10',
        '+1 ',
        '-1',
        '+10.5',
        '10.5',
        '+ 10',
        '- 10',
        '+-10',
        '+- 10',
        '1-0',
        '10+',
        '+10+10',
        'k10',
        'k 10',
        'k+10',
        'k +10',
        'k + 10',
        'k1k0',
        '1k0',
        'k 10+',
        'k1',
        ' +10',
        '10k',
        '10-k',
        '1k',
        '+10lalala',
        "",
        "lala",
        " ",
        "  ",
        "+",
        '10#',
        '10$',
        '10^^',
        '10^4',
        '10>',  # special characters
        '10.',
        '10:',
        '10-',
        '1/',
        '1\\',
        '10\"',
        "10\'",
        '10?',
        '1!',  # word delimiters
        '10(',
        '10)',
        '10{',
        '10}',
        '10[',
        '10]'
    ]  # brackets
    for cli_input in invalid_inputs:
        result = parser.parse_input(cli_input)
        assert isinstance(result, Failure)

    # Test invalid inputs with a delimiter
    invalid_inputs = [('+10_', '.'), ('10_', ','), ('10.$', '$'),
                      ('10, 20', ' ')]
    for cli_input, delimiter in invalid_inputs:
        parser = NatParser(delimiter)
        result = parser.parse_input(cli_input)
        assert isinstance(result, Failure)

    # Test valid inputs
    valid_inputs = [
        ('10,+20', ',', 10, '+20'),
        ('10 some string +10 yes', ' ', 10, 'some string +10 yes'),
        ('10A delimiterA remainder', 'A delimiter', 10, 'A remainder'),
        ('10', '', 10, ''), ('   10 ', '', 10, ''), ('    10', '', 10, ''),
        ('10  ', '', 10, ''), ('10, 12, ', ',', 10, '12, '),
        ('   10 , 20', ',', 10, '20'), ('   10,20', ',', 10, '20'),
        (' 10 ,20 ', ',', 10, '20 '), ('  10,   20', ',', 10, '20'),
        ('10, ', ',', 10, '')
    ]
    for cli_input, delimiter, expected, remainder in valid_inputs:
        parser = NatParser(delimiter)
        result = parser.parse_input(cli_input)
        assert result == Success(expected, remainder)