def test_move_shape_parser(controller: Controller, cli_parser: CliParser): # Test invalid inputs, two points as parameters invalid_inputs = [ "move 10,-20 30,40", "move 10,20 30,+40", "move 10,20 30.40", "move 10 20 30,40", "move10,20 30,40", "move 10,20", "movee 10,20 30,40", "move something", ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, two points as parameters valid_inputs = [ ("move 10,20 30,40", MoveShapeCommand(controller, 10, 20, 30, 40)), ("move 10,20 -10,-20", MoveShapeCommand(controller, 10, 20, 0, 0)), ("move 10 ,20 30, 40", MoveShapeCommand(controller, 10, 20, 30, 40)), (" move 10, 20 30 ,40 ", MoveShapeCommand(controller, 10, 20, 30, 40)), ("move 10 , 20 30 , 40", MoveShapeCommand(controller, 10, 20, 30, 40)), ("move -5,-5 +5,+5", MoveShapeCommand(controller, -5, -5, 0, 0)), ("move -5,-5 10,20", MoveShapeCommand(controller, -5, -5, 10, 20)) ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def test_dot_parser(controller: Controller, cli_parser: CliParser): """ :return: """ # Test invalid inputs invalid_inputs = [ "dot 10,-20", "dot +10,20", "dot 10.20", "dot 10 20", "dot10,20", "dot 10,20 30,40", "dott 10,20", "dot something", "dot 10,20 rgb(0,0,-1)", "dot 10,20 30,40 rgb(0,0,0", "dot 10,20 rgb 0,0,0", "dot 10,20 rgb(0,1)", "dot 10,20rgb(0,1,2)", "dot 10,20 rgb(1a,2,3)", "dot 10,20,rgb(0,2,3)", "dot 10,20 rgb(256,0,1)", "dot 10,20 rgb(2.0.1)", "dot 10,20 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs valid_inputs = [ ("dot 10, 20", PrintDotCommand(controller, 10, 20, (0, 0, 0))), ("dot -10 ,+20", PrintDotCommand(controller, -10, +20, (0, 0, 0))), (" dot -5,-5 ", PrintDotCommand(controller, -5, -5, (0, 0, 0))), ("dot 10,20 rgb (10,20,30) ", PrintDotCommand(controller, 10, 20, (10, 20, 30))), ("dot -10 , -20 rgb ( 0 , 0, 0 ) ", PrintDotCommand(controller, -10, -20, (0, 0, 0))) ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def __init__(self): self._gui = MainWindow(self) self._command_engine = CommandEngine(self) self._printer = CanvasPrinter(self._gui.canvas) self._shapes = ShapesStore(self) # import CliParser this late to avoid import loop from app.parsers.cli_parser import CliParser self._cli_parser = CliParser(self, RgbColorParser())
def test_quit_parser(controller: Controller, cli_parser: CliParser): # Test valid inputs assert cli_parser.parse_input("quit") == QuitCommand(controller) assert cli_parser.parse_input(" quit") == QuitCommand(controller) assert cli_parser.parse_input(" quit ") == QuitCommand(controller) # Test invalid inputs assert cli_parser.parse_input("quit something") == InvalidCommand( controller) assert cli_parser.parse_input("quitsomething") == InvalidCommand( controller)
def test_clear_parser(controller: Controller, cli_parser: CliParser): # Test valid inputs assert cli_parser.parse_input("clear") == ClearCommand(controller) assert cli_parser.parse_input(" clear") == ClearCommand(controller) assert cli_parser.parse_input(" clear ") == ClearCommand(controller) # Test invalid inputs assert cli_parser.parse_input("clear something") == InvalidCommand( controller) assert cli_parser.parse_input("clearsomething") == InvalidCommand( controller)
def test_remove_shape_parser(controller: Controller, cli_parser: CliParser): # Test invalid inputs invalid_inputs = [ "remove 10,-20", "remove +10,20", "remove 10.20", "remove 10 20", "remove10,20", "remove 10,20 30,40", "removet 10,20", "remove something", "remove 10,20 something" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs valid_inputs = [ ("remove 10,20", RemoveShapeCommand(controller, 10, 20)), ("remove 10, 20", RemoveShapeCommand(controller, 10, 20)), (" remove 10 ,20 ", RemoveShapeCommand(controller, 10, 20)), (" remove 10 , 20", RemoveShapeCommand(controller, 10, 20)), ("remove -10,+20", RemoveShapeCommand(controller, -10, +20)), ("remove -5,-5", RemoveShapeCommand(controller, -5, -5)) ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def test_list_shape_parser(controller: Controller, cli_parser: CliParser): # Test invalid inputs invalid_inputs = [ "ls 10,-20", "ls +10,20", "ls 10.20", "ls 10 20", "ls10,20", "ls 10,20 30,40", "lst 10,20", "ls 10,20 something", "ls something", "l s" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs valid_inputs = [("ls 10,20", ListShapeCommand(controller, 10, 20)), ("ls 10 ,20 ", ListShapeCommand(controller, 10, 20)), (" ls 10 , 20", ListShapeCommand(controller, 10, 20)), ("ls -10,+20", ListShapeCommand(controller, -10, +20)), ("ls -5,-5", ListShapeCommand(controller, -5, -5)), ("ls", ListShapeCommand(controller)), ("ls ", ListShapeCommand(controller)), (" ls ", ListShapeCommand(controller))] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def test_load_parser(controller: Controller, cli_parser: CliParser): # Test valid inputs assert cli_parser.parse_input("load") == LoadCommand(controller) assert cli_parser.parse_input(" load") == LoadCommand(controller) assert cli_parser.parse_input(" load ") == LoadCommand(controller) assert cli_parser.parse_input("load filename") == LoadCommand( controller, "filename") assert cli_parser.parse_input(" load filename something") == LoadCommand( controller, "filename something") # Test invalid inputs assert cli_parser.parse_input("loadsomething") == InvalidCommand( controller)
def test_save_parser(controller: Controller, cli_parser: CliParser): # Test valid inputs assert cli_parser.parse_input("save") == SaveCommand(controller) assert cli_parser.parse_input(" save") == SaveCommand(controller) assert cli_parser.parse_input(" save ") == SaveCommand(controller) assert cli_parser.parse_input("save filename") == SaveCommand( controller, "filename") assert cli_parser.parse_input(" save filename something") == SaveCommand( controller, "filename something") # Test invalid inputs assert cli_parser.parse_input("savesomething") == InvalidCommand( controller)
class Controller: """ Main class of this application. Holds all crucial pieces together. It represents an observer in the observer design pattern. """ def __init__(self): self._gui = MainWindow(self) self._command_engine = CommandEngine(self) self._printer = CanvasPrinter(self._gui.canvas) self._shapes = ShapesStore(self) # import CliParser this late to avoid import loop from app.parsers.cli_parser import CliParser self._cli_parser = CliParser(self, RgbColorParser()) def add_shapes(self, *shapes: Shape): for shape in shapes: self.print_to_history(str(shape)) self._shapes.add_shapes(*shapes) def move_shapes(self, move_from: Point, move_to: Point, divergence: bool = False) -> Dict[str, List[Shape]]: return self._shapes.move_shapes(move_from, move_to, divergence) def replace_shapes_store(self, shapes: List[Shape]): self._shapes = ShapesStore(self, shapes) self.update() def remove_last_shape(self): self._shapes.remove_last_shape() def remove_shapes_at(self, point: Point, divergence: bool = False) -> Dict[str, List[Shape]]: return self._shapes.remove_shapes_at(point, divergence) def preview_shape(self, shape: Shape): self._shapes.set_preview(shape) def end_preview(self): self._shapes.set_preview(None) def parse_command(self, command_text: str): command = self._cli_parser.parse_input(command_text) self.execute_command(command, command_text=command_text) def execute_command(self, command: Command, from_redo: bool = False, command_text: str = None): history_line = ' > ' + (command_text or str(command)) self._gui.print_lines_to_history(history_line) self._command_engine.execute_command(command, from_redo=from_redo) def remove_last_command(self): self._command_engine.remove_last_command() def print_to_history(self, lines: str): self._gui.print_lines_to_history(lines) def delete_from_history(self, number_of_lines: int = 1): self._gui.delete_from_history(number_of_lines) def shapes_at(self, point: Point = None, divergence: bool = False) -> List[Shape]: return self._shapes.shapes_at(point, divergence) def print_shapes_to_history(self, point: Point): for shape in self.shapes_at(point): self.print_to_history(str(shape)) def print_all_shapes(self, printer: Printer = None) -> List[Shape]: return self._shapes.print_all(printer or self._printer) def update(self): self._printer.update(self) def undo(self): self._command_engine.undo() def redo(self): self._command_engine.redo() def enable_undo(self): self._gui.enable_undo() def enable_redo(self): self._gui.enable_redo() def disable_undo(self): self._gui.disable_undo() def disable_redo(self): self._gui.disable_redo() def save_dialog(self, path_to_file: str): self._gui.save_dialog(path_to_file) def load_dialog(self, path_to_file: str): self._gui.load_dialog(path_to_file) def save(self, file: str): commands = self._command_engine.get_all_commands() with open(file, 'w+', encoding='utf-8') as f: [f.write(str(c) + '\n') for c in commands['undos']] self._gui.set_status('File saved!') def load(self, file: str): with open(file, 'r', encoding='utf-8') as f: # Getting rid of the newline `\n` at the end of every line commands = [line[:-1] for line in f.readlines()] for command_text in commands: command = self._cli_parser.parse_input(command_text) self.execute_command(command, command_text=command_text) self._gui.set_status('File loaded!') def run_app(self): # Run the whole app self._gui.show() def clear_dialog(self) -> bool: return self._gui.clear_dialog() def restart(self): self._shapes.restart() def quit(self): self._gui.close()
def test_line_parser(controller: Controller, cli_parser: CliParser): invalid_inputs = [ "line 10,-20 30,40", "line 10,20 30,+40", "line 10,20 30.40", "line 10 20 30,40", "line10,20 30,40", "line 10,20", "linet 10,20 30,40", "line something", "line 10,20 30,40 rgb(0,0,-1)", "line 10,20 30,40 rgb(0,0,0", "line 10,20 30,40 rgb 0,0,0", "line 10,20 30,40 rgb(0,1)", "line 10,20 30,40rgb(0,1,2)", "line 10,20 30,40 rgb(1a,2,3)", "line 10,20 30,40,rgb(0,2,3)", "line 10,20 30,40 rgb(256,0,1)", "line 10,20 30,40 rgb(2.0.1)", "line 10,20 30,40 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, two points valid_inputs = [("line 10 ,20 30,40", PrintLineCommand(controller, 10, 20, 30, 40, (0, 0, 0))), ("line 10, 20 -10, -20", PrintLineCommand(controller, 10, 20, 0, 0, (0, 0, 0))), (" line -5,-5 +5,+5 ", PrintLineCommand(controller, -5, -5, 0, 0, (0, 0, 0))), ("line -5,-5 10,20", PrintLineCommand(controller, -5, -5, 10, 20, (0, 0, 0))), (" line 10, 20 30, 40 rgb(10,20, 30)", PrintLineCommand(controller, 10, 20, 30, 40, (10, 20, 30))), ("line 10, 20 -10 , -20 rgb ( 0, 0 , 0 ) ", PrintLineCommand(controller, 10, 20, 0, 0, (0, 0, 0)))] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected # Test invalid inputs, three points invalid_inputs = [ "line 10,20 30,40 50,-60", "line 10,20 30,40 50,+60", "line 10,20 30,40 50.60", "line 10,20 30,40 50 60", "line 10,20 30,40 something", "line 10,20 30,40 50,60 rgb(0,0,-1)", "line 10,20 30,40 50,60 rgb(0,0,0", "line 10,20 30,40 rgb 0,0,0", "line 10,20 30,40 50,60 rgb(0,1)", "line 10,20 30,40 50,60 rgb(1a,2,3)", "line 10,20 30,40,50,60 rgb(0,2,3)", "line 10,20 30,40 50,60 rgb(256,0,1)", "line 10,20 30,40 50,60 rgb(2.0.1)", "line 10,20 30,40 50,60rgb(0,1,2)", "line 10,20 30,40 50,60 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, three points valid_inputs = [ ("line 10,20 30 ,40 50, 60", PrintPolylineCommand(controller, [(10, 20), (30, 40), (50, 60)], (0, 0, 0))), (" line 10 ,20 -10,-20 10,20", PrintPolylineCommand(controller, [(10, 20), (0, 0), (10, 20)], (0, 0, 0))), ("line -5, -5 +5,+5 5 ,5", PrintPolylineCommand(controller, [(-5, -5), (0, 0), (5, 5)], (0, 0, 0))), ("line -5 , -5 10,20 -10,-20", PrintPolylineCommand(controller, [(-5, -5), (10, 20), (0, 0)], (0, 0, 0))), ("line 10,20 30 ,40 50,60 rgb (10 ,20,30)", PrintPolylineCommand(controller, [(10, 20), (30, 40), (50, 60)], (10, 20, 30))), ("line 10 ,20 -10, -20 +30 ,+40 rgb ( 0, 0 , 0 ) ", PrintPolylineCommand(controller, [(10, 20), (0, 0), (30, 40)], (0, 0, 0))), ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected # Test invalid inputs, four points invalid_inputs = [ "line 10,20 30,40 50,60 70,-80", "line 10,20 30,40 50,60 70,+80", "line 10,20 30,40 50,60 70.80", "line 10,20 30,40 50,60 70 80", "line 10,20 30,40 50,60 something", "line 10,20 30,40 50,60 70,80 rgb(0,0,-1)", "line 10,20 30,40 50,60 70,80 rgb(0,0,0", "line 10,20 30,40 50,60 70,80 rgb 0,0,0", "line 10,20 30,40 50,60 70,80 rgb(0,1)", "line 10,20 30,40 50,60 70,80 rgb(1a,2,3)", "line 10,20 30,40,50,60 70,80 rgb(0,2,3)", "line 10,20 30,40 50,60 70,80 rgb(256,0,1)", "line 10,20 30,40 50,60 70,80 rgb(2.0.1)", "line 10,20 30,40 50,60 70,80rgb(0,1,2)", "line 10,20 30,40 50,60 70,80 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, four points valid_inputs = [ ("line 10,20 30,40 50,60 70,80", PrintPolylineCommand(controller, [(10, 20), (30, 40), (50, 60), (70, 80)], (0, 0, 0))), ("line 10,20 -10,-20 10,20 -10,-20 ", PrintPolylineCommand(controller, [(10, 20), (0, 0), (10, 20), (0, 0)], (0, 0, 0))), ("line -5,-5 +5 , +5 5 ,5 -5,-5", PrintPolylineCommand(controller, [(-5, -5), (0, 0), (5, 5), (0, 0)], (0, 0, 0))), ("line -5 ,-5 10,20 -10,-20 10,20", PrintPolylineCommand(controller, [(-5, -5), (10, 20), (0, 0), (10, 20)], (0, 0, 0))), ("line 10,20 30,40 50,60 70,80 rgb(10,20,30)", PrintPolylineCommand(controller, [(10, 20), (30, 40), (50, 60), (70, 80)], (10, 20, 30))), (" line 10, 20 -10 , -20 +30,+40 -30 , -40 rgb (0 ,0 ,0 )", PrintPolylineCommand(controller, [(10, 20), (0, 0), (30, 40), (0, 0)], (0, 0, 0))), ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def test_rect_parser(controller: Controller, cli_parser: CliParser): """ :return: """ # Test invalid inputs, two points as parameters invalid_inputs = [ "rect 10,-20 30,40", "rect 10,20 30,+40", "rect 10,20 30.40", "rect 10 20 30,40", "rect10,20 30,40", "rect 10,20", "rectt 10,20 30,40", "rect something", "rect 10,20 30,40 rgb(0,0,-1)", "rect 10,20 30,40 rgb(0,0,0", "rect 10,20 30,40 rgb 0,0,0", "rect 10,20 30,40 rgb(0,1)", "rect 10,20 30,40rgb(0,1,2)", "rect 10,20 30,40 rgb(1a,2,3)", "rect 10,20 30,40,rgb(0,2,3)", "rect 10,20 30,40 rgb(256,0,1)", "rect 10,20 30,40 rgb(2.0.1)", "rect 10,20 30,40 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, two points as parameters valid_inputs = [("rect 10,20 30,40", PrintRectCommand(controller, 10, 20, (0, 0, 0), end_x=30, end_y=40)), ("rect 10 , 20 -10 ,-20", PrintRectCommand(controller, 10, 20, (0, 0, 0), end_x=0, end_y=0)), (" rect -5 ,-5 +5,+5 ", PrintRectCommand(controller, -5, -5, (0, 0, 0), end_x=0, end_y=0)), ("rect -5,-5 10, 20", PrintRectCommand(controller, -5, -5, (0, 0, 0), end_x=10, end_y=20)), ("rect 10,20 30,40 rgb (10,20,30)", PrintRectCommand(controller, 10, 20, (10, 20, 30), end_x=30, end_y=40)), (" rect 10,20 -10 , -20 rgb(0 , 0 ,0 ) ", PrintRectCommand(controller, 10, 20, (0, 0, 0), end_x=0, end_y=0))] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected # Test invalid inputs, one point and two natural numbers (width and height) as parameters invalid_inputs = [ "rect 10,-20 30 40", "rect 10,20 30 +40", "rect 10,20 -30 40", "rect 10 20 30 40", "rect10,20 30 40", "rect 10,20", "rect 10,20 30", "rectt 10,20 30 40", "rect 10,20 something", "rect 10,20 30 something", "rect 10,20 30 40 rgb(0,0,-1)", "rect 10,20 30 40 rgb(0,0,0", "rect 10,20 30 40 rgb 0,0,0", "rect 10,20 30 40 rgb(0,1)", "rect 10,20 30 40rgb(0,1,2)", "rect 10,20 30 40 rgb(1a,2,3)", "rect 10,20 30 40,rgb(0,2,3)", "rect 10,20 30 40 rgb(256,0,1)", "rect 10,20 30 40 rgb(2.0.1)", "rect 10,20 30 40 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, one point and two natural numbers (width and height) as parameters valid_inputs = [ ("rect 10 ,20 20 20", PrintRectCommand(controller, 10, 20, (0, 0, 0), DimensionsRectFactory, width=20, height=20)), ("rect -10, -20 10 20", PrintRectCommand(controller, -10, -20, (0, 0, 0), DimensionsRectFactory, width=10, height=20)), (" rect +10, +20 0 5 ", PrintRectCommand(controller, 10, 20, (0, 0, 0), DimensionsRectFactory, width=0, height=5)), ("rect +10, -20 20 20 rgb( 10,20,30 )", PrintRectCommand(controller, 10, -20, (10, 20, 30), DimensionsRectFactory, width=20, height=20)), ("rect -10 , +20 1000 2 rgb ( 0 , 0 ,0 )", PrintRectCommand(controller, -10, 20, (0, 0, 0), DimensionsRectFactory, width=1000, height=2)), ] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def test_circle_parser(controller: Controller, cli_parser: CliParser): # Test invalid inputs, two points as parameters invalid_inputs = [ "circle 10,-20 30,40", "circle 10,20 30,+40", "circle 10,20 30.40", "circle 10 20 30,40", "circle10,20 30,40", "circle 10,20", "circlee 10,20 30,40", "circle something", "circle 10,20 30,40 rgb(0,0,-1)", "circle 10,20 30,40 rgb(0,0,0", "circle 10,20 30,40 rgb 0,0,0", "circle 10,20 30,40 rgb(0,1)", "circle 10,20 30,40rgb(0,1,2)", "circle 10,20 30,40 rgb(1a,2,3)", "circle 10,20 30,40,rgb(0,2,3)", "circle 10,20 30,40 rgb(256,0,1)", "circle 10,20 30,40 rgb(2.0.1)", "circle 10,20 30,40 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, two points as parameters valid_inputs = [("circle 10,20 30,40", PrintCircleCommand(controller, 10, 20, (0, 0, 0), end_x=30, end_y=40)), ("circle 10, 20 -10,-20", PrintCircleCommand(controller, 10, 20, (0, 0, 0), end_x=0, end_y=0)), ("circle -5,-5 +5, +5", PrintCircleCommand(controller, -5, -5, (0, 0, 0), end_x=0, end_y=0)), ("circle -5 ,-5 10,20 ", PrintCircleCommand(controller, -5, -5, (0, 0, 0), end_x=10, end_y=20)), ("circle 10 ,20 30, 40 rgb (10,20,30)", PrintCircleCommand(controller, 10, 20, (10, 20, 30), end_x=30, end_y=40)), (" circle 10,20 -10, -20 rgb( 0, 0 , 0 ) ", PrintCircleCommand(controller, 10, 20, (0, 0, 0), end_x=0, end_y=0))] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected # Test invalid inputs, one point and one natural number (radius) as parameters invalid_inputs = [ "circle 10,20 30 40", "circle 10,20 +30", "circle 10,20 -30", "circle 10,20", "circle10,20 30", "circlee 10,20 30", "circle 10,20 something", "circle 10,20 30 rgb(0,0,-1)", "circle 10,20 30 rgb(0,0,0", "circle 10,20 30 rgb 0,0,0", "circle 10,20 30 rgb(0,1)", "circle 10,20 30rgb(0,1,2)", "circle 10,20 30 rgb(1a,2,3)", "circle 10,20 30,rgb(0,2,3)", "circle 10,20 30 rgb(256,0,1)", "circle 10,20 30 rgb(2.0.1)", "circle 10,20 30 rgb(123)" ] for cli_input in invalid_inputs: command = cli_parser.parse_input(cli_input) assert command == InvalidCommand(controller) # Test valid inputs, one point and one natural number (radius) as parameters valid_inputs = [("circle 10, 20 30", PrintCircleCommand(controller, 10, 20, (0, 0, 0), DimensionsCircleFactory, radius=30)), ("circle -5 ,-5 30 ", PrintCircleCommand(controller, -5, -5, (0, 0, 0), DimensionsCircleFactory, radius=30)), (" circle 10 , 20 30 rgb (10, 20,30)", PrintCircleCommand(controller, 10, 20, (10, 20, 30), DimensionsCircleFactory, radius=30)), ("circle 10, 20 30 rgb (0, 0 , 0 ) ", PrintCircleCommand(controller, 10, 20, (0, 0, 0), DimensionsCircleFactory, radius=30))] for cli_input, expected in valid_inputs: command = cli_parser.parse_input(cli_input) assert command == expected
def cli_parser() -> CliParser: controller: Controller = "controller" return CliParser(controller, RgbColorParser())