def testFileTypes(self):
        # Check all of the filetypes
        for fileType in LAUNCH_FILE_TYPES:
            launchFile = "examples/fake_package/launch/filetype%s" % fileType

            status, output, graph = roslaunch_to_dot(launchFile)

            # Should not have failed
            self.assertEqual(status, 0)

            # No errors present
            numErrors = output.count("ERROR")
            self.assertEqual(numErrors, 0)

        # Test some filetypes that are NOT supported
        for fileType in [".txt", ".lunch"]:  # lunch is correct
            launchFile = "examples/fake_package/launch/filetype%s" % fileType

            status, output, graph = roslaunch_to_dot(launchFile)

            # Should have failed
            self.assertNotEqual(status, 0)

            # Invalid filetype error is present
            numErrors = output.count(ErrorMsg.InvalidFiletype)
            self.assertEqual(numErrors, 1)
Example #2
0
    def testOverrideValueArg(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"
        args = [
            "%s:=example" % self.UndefinedArg,  # Keep this so things work
            "%s:=example" % self.DefaultArg,  # Keep this so things work
            "%s:=example" % self.ValueArg,  # Keep this so things work
        ]

        # The override for the arg that has its "value" specified should
        # fail because roslaunch would error in this case saying that
        # the argument already has its value specified

        status, output, graph = roslaunch_to_dot(launchFile, args=args)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Should not be able to find one launch files (one for value arg)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 1)

        # Should not be able to override the value of the 'value' arg since
        # its value has already been specified
        numInvalid = output.count(ErrorMsg.InvalidOverride % self.ValueArg)
        self.assertEqual(numInvalid, 1)

        # The example launch file should have been included twice
        example = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(graph)
    def testCycle(self):
        launchFile = "examples/fake_package/launch/example.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)

        # The output should contain the cycle error message TWICE:
        #    once for a cycle between cycle.launch and itself, and another
        #    for the cycle between cycle.launch and example.launch
        numErrors = output.count(ErrorMsg.Cycle)
        self.assertEqual(numErrors, 2)

        # Make sure the proper nodes exist
        exampleLaunch = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(exampleLaunch)

        cycleLaunch = graph.get_node("launch_fake_package_cycle")
        self.assertIsNotNone(cycleLaunch)

        # Make sure the proper edges exist
        cycle2Cycle = graph.get_edge(cycleLaunch, cycleLaunch)
        self.assertIsNotNone(cycle2Cycle)

        cycle2Example = graph.get_edge(cycleLaunch, exampleLaunch)
        self.assertIsNotNone(cycle2Example)

        # Make sure both edges are colored "red"
        self.assertEqual(cycle2Cycle.attr["color"], Color.CycleLine)
        self.assertEqual(cycle2Example.attr["color"], Color.CycleLine)
    def testOverrideRosParamArg(self):
        robotValue = "a_different_robot"

        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
            ]
        args = [
            "robot:=%s" % robotValue,
            ]

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options, args=args)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include rosparam nodes
        defaults = graph.get_node("yaml_fake_package_defaults_yaml")
        robot = graph.get_node("yaml_fake_package_%s_yaml" % robotValue)

        # Both rosparam files should exist
        self.assertIsNotNone(defaults)
        self.assertIsNotNone(robot)

        # Assert the correct labels on the yaml nodes
        self.assertEqual(defaults.attr["label"], "defaults.yaml")
        self.assertEqual(robot.attr["label"], "%s.yaml" % robotValue)

        # The robot rosparam node should be solid colored to indicate
        # that it is missing
        self.assertEqual(robot.attr["color"], Color.MissingFile)
        self.assertEqual(robot.attr["style"], "filled")
Example #5
0
    def testOverrideRosParamArg(self):
        robotValue = "a_different_robot"

        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
        ]
        args = [
            "robot:=%s" % robotValue,
        ]

        status, output, graph = roslaunch_to_dot(launchFile,
                                                 options=options,
                                                 args=args)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include rosparam nodes
        defaults = graph.get_node("yaml_fake_package_defaults_yaml")
        robot = graph.get_node("yaml_fake_package_%s_yaml" % robotValue)

        # Both rosparam files should exist
        self.assertIsNotNone(defaults)
        self.assertIsNotNone(robot)

        # Assert the correct labels on the yaml nodes
        self.assertEqual(defaults.attr["label"], "defaults.yaml")
        self.assertEqual(robot.attr["label"], "%s.yaml" % robotValue)

        # The robot rosparam node should be solid colored to indicate
        # that it is missing
        self.assertEqual(robot.attr["color"], Color.MissingFile)
        self.assertEqual(robot.attr["style"], "filled")
Example #6
0
    def testOverrideValueArg(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"
        args = [
            "%s:=example" % self.UndefinedArg,  # Keep this so things work
            "%s:=example" % self.DefaultArg,  # Keep this so things work
            "%s:=example" % self.ValueArg,  # Keep this so things work
        ]

        # The override for the arg that has its "value" specified should
        # fail because roslaunch would error in this case saying that
        # the argument already has its value specified

        status, output, graph = roslaunch_to_dot(launchFile, args=args)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Should not be able to find one launch files (one for value arg)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 1)

        # Should not be able to override the value of the 'value' arg since
        # its value has already been specified
        numInvalid = output.count(ErrorMsg.InvalidOverride % self.ValueArg)
        self.assertEqual(numInvalid, 1)

        # The example launch file should have been included twice
        example = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(graph)
    def testOptEnvDefined(self):
        launchFile = "examples/fake_package/launch/optenv_error.launch"

        # Define the environment variable
        prefix = "%s=robot" % self.SecondEnvVar

        status, output, graph = roslaunch_to_dot(launchFile, prefix=prefix)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Shoudl be able to find first environment variable
        numErrors = output.count(ErrorMsg.MissingEnvVar % self.FirstEnvVar)
        self.assertEqual(numErrors, 0)

        # Should be able to find second environment variable
        numErrors = output.count(ErrorMsg.MissingEnvVar % self.SecondEnvVar)
        self.assertEqual(numErrors, 0)

        # Should not be able to locate the launch file that is created using
        # the no default value argument (whose value is the second
        # environment variable)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 1)
Example #8
0
    def testDirname(self):
        launchFile = "examples/fake_package/launch/dirname.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)
Example #9
0
    def testTestNode(self):
        launchFile = "examples/fake_package/launch/test_node.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)
        self.assertIsNotNone(graph)

        # The test node should be included in the graph
        node = graph.get_node("node_fake_package_test_node_a_node")
        self.assertIsNotNone(node)
Example #10
0
    def testArgUndefined(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Error should not be able to resolve the undefined argument
        numErrors = output.count(ErrorMsg.MissingArg % self.UndefinedArg)
        self.assertEqual(numErrors, 1)
    def testNoRosParamNodes(self):
        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include ANY rosparam nodes
        for node in graph.nodes():
            # The name of all rosparam file nodes starts with yaml_
            self.assertFalse(node.name.startswith("yaml_"))
    def testNoCommandLineArguments(self):
        launchFile = "examples/fake_package/launch/example.launch"
        args = []

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)

        # There should not be a command line arguments node in this case
        with self.assertRaises(Exception):
            graph.get_node(self.ClaNodeName)
Example #13
0
    def testNoRosParamNodes(self):
        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include ANY rosparam nodes
        for node in graph.nodes():
            # The name of all rosparam file nodes starts with yaml_
            self.assertFalse(node.name.startswith("yaml_"))
Example #14
0
    def testArgUndefined(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Error should not be able to resolve the undefined argument
        numErrors = output.count(ErrorMsg.MissingArg % self.UndefinedArg)
        self.assertEqual(numErrors, 1)
Example #15
0
    def testEnvUndefined(self):
        launchFile = "examples/fake_package/launch/env_error.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Error should not be able to find environment variable
        numErrors = output.count(ErrorMsg.MissingEnvVar % self.EnvVar)
        self.assertEqual(numErrors, 1)
    def testOrphanPackage(self):
        launchFile = "examples/orphan.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should definitely have failed
        self.assertNotEqual(status, 0)

        errorMsg = ErrorMsg.FailedToGetPackage % abspath(launchFile)

        # Must generate an error indicating that the package for the file
        # was not able to be found
        numErrors = output.count(errorMsg)
        self.assertEqual(numErrors, 1)
Example #17
0
    def testNoPng(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        # Delete the PNG to make sure it's gone before the command
        if exists(self.PngFile):
            remove(self.PngFile)

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # The PNG should still NOT exist at this point
        self.assertFalse(exists(self.PngFile))
    def testNodeSameName(self):
        launchFile = "examples/fake_package/launch/identical_nodes.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed
        self.assertEqual(status, 0)

        # Generate the error message string
        errorMsg = ErrorMsg.NodesWithSameName % self.IdenticalNodeName

        # The output should contain a warning indicating that there were
        # two nodes that have the same name
        numErrors = output.count(errorMsg)
        self.assertEqual(numErrors, 1)
    def testOptEnvUndefined(self):
        launchFile = "examples/fake_package/launch/optenv_error.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should have failed (the error gets propagates to the top level)
        self.assertNotEqual(status, 0)

        # Error be able to find first environment variable
        numErrors = output.count(ErrorMsg.MissingEnvVar % self.FirstEnvVar)
        self.assertEqual(numErrors, 0)

        # Should not be able to find the second environment variable
        # (which does not have a default value)
        numErrors = output.count(ErrorMsg.MissingEnvVar % self.SecondEnvVar)
        self.assertEqual(numErrors, 1)
Example #20
0
    def testNoPng(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        # Delete the PNG to make sure it's gone before the command
        if exists(self.PngFile):
            remove(self.PngFile)

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # The PNG should still NOT exist at this point
        self.assertFalse(exists(self.PngFile))
Example #21
0
    def testPassAllArgs(self):
        launchFile = "examples/fake_package/launch/pass_all_args.launch"

        status, output, graph = roslaunch_to_dot(launchFile)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Should not be able to find TWO launch files (one for default arg, and
        # one for value arg)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 2)

        # The example launch file should have been included once
        example = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(graph)
    def testDoNotShowNodeType(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Ensure that no nodes contain the type of node in their label
        for node in graph.nodes():
            # Only care about ROS nodes
            if node.name.startswith("node_"):
                label = node.attr["label"]

                # Node labels should NOT contain the type of node
                self.assertFalse("type: " in label)
Example #23
0
    def testOverrideDefaultArg(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"
        args = ["%s:=example" % self.UndefinedArg, "%s:=example" % self.DefaultArg]  # Keep this so things work

        status, output, graph = roslaunch_to_dot(launchFile, args=args)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Should not be able to find one launch files (one for value arg)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 1)

        # The example launch file should have been included twice
        example = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(graph)
Example #24
0
    def testGroupsDisabled(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = [
            "--disable-groups",
        ]

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Should have exactly zero subgraphs
        self.assertEqual(len(graph.subgraphs()), 0)

        # Ensure that all nodes contain the node's package in their label
        for node in graph.nodes():
            # Node label should contain the node's package
            self.assertTrue("pkg: " in node.attr["label"])
Example #25
0
    def testGroupsEnabled(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Should have exactly one subgraph
        self.assertEqual(len(graph.subgraphs()), 1)

        # Ensure that no nodes contain the node's package in their label
        for node in graph.nodes():
            # Only care about ROS nodes
            if node.name.startswith("node_"):
                # Node labels should NOT contain the nodes's package
                self.assertFalse("pkg: " in node.attr["label"])
    def testDoNotShowNodeType(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Ensure that no nodes contain the type of node in their label
        for node in graph.nodes():
            # Only care about ROS nodes
            if node.name.startswith("node_"):
                label = node.attr["label"]

                # Node labels should NOT contain the type of node
                self.assertFalse("type: " in label)
    def testGroupsEnabled(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = []

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Should have exactly one subgraph
        self.assertEqual(len(graph.subgraphs()), 1)

        # Ensure that no nodes contain the node's package in their label
        for node in graph.nodes():
            # Only care about ROS nodes
            if node.name.startswith("node_"):
                # Node labels should NOT contain the nodes's package
                self.assertFalse("pkg: " in node.attr["label"])
    def testGroupsDisabled(self):
        launchFile = "examples/fake_package/launch/example.launch"
        options = [
            "--disable-groups",
            ]

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # Should have exactly zero subgraphs
        self.assertEqual(len(graph.subgraphs()), 0)

        # Ensure that all nodes contain the node's package in their label
        for node in graph.nodes():
            # Node label should contain the node's package
            self.assertTrue("pkg: " in node.attr["label"])
Example #29
0
    def testOverrideDefaultArg(self):
        launchFile = "examples/fake_package/launch/arg_error.launch"
        args = [
            "%s:=example" % self.UndefinedArg,  # Keep this so things work
            "%s:=example" % self.DefaultArg,
        ]

        status, output, graph = roslaunch_to_dot(launchFile, args=args)

        # Should not have failed (the error gets caught and does not propagate
        # to the top level)
        self.assertEqual(status, 0)

        # Should not be able to find one launch files (one for value arg)
        numMissing = output.count(ErrorMsg.MissingLaunchFile)
        self.assertEqual(numMissing, 1)

        # The example launch file should have been included twice
        example = graph.get_node("launch_fake_package_example")
        self.assertIsNotNone(graph)
    def testMissingLaunchFile(self):
        # Try to access several missing files...
        missingFiles = [
            "this_does_not_exist",
            "whatever",
            "why_is_this_missing",
        ]

        for missingFile in missingFiles:
            launchFile = "examples/fake_package/launch/%s.launch" % missingFile

            status, output, graph = roslaunch_to_dot(launchFile)

            # Should have failed
            self.assertNotEqual(status, 0)

            errorMsg = ErrorMsg.CanNotFindLaunchFile % abspath(launchFile)

            # Should have issues an error about not being able to find the file
            numErrors = output.count(errorMsg)
            self.assertEqual(numErrors, 1)
    def testMissingLaunchFile(self):
        # Try to access several missing files...
        missingFiles = [
            "this_does_not_exist",
            "whatever",
            "why_is_this_missing",
            ]

        for missingFile in missingFiles:
            launchFile = "examples/fake_package/launch/%s.launch" % missingFile

            status, output, graph = roslaunch_to_dot(launchFile)

            # Should have failed
            self.assertNotEqual(status, 0)

            errorMsg = ErrorMsg.CanNotFindLaunchFile % abspath(launchFile)

            # Should have issues an error about not being able to find the file
            numErrors = output.count(errorMsg)
            self.assertEqual(numErrors, 1)
    def testRosParamMissingPackage(self):
        package = "this_package_does_not_exist"

        launchFile = \
            "examples/fake_package/launch/rosparam_unknown_pkg.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
            ]
        args = []

        status, output, graph = roslaunch_to_dot(
            launchFile, options=options, args=args)

        # Script does not fail, just generates an error
        self.assertEqual(status, 0)

        # Create the error message string
        errorMsg = ErrorMsg.CanNotLocateRosPackage % package

        # Must have an error
        numErrors = output.count(errorMsg)
        self.assertEqual(numErrors, 1)
Example #33
0
    def testNoRosParamNodes(self):
        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
        ]

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include rosparam nodes
        defaults = graph.get_node("yaml_fake_package_defaults_yaml")
        robot = graph.get_node("yaml_fake_package_robot_yaml")

        # Both rosparam files should exist
        self.assertIsNotNone(defaults)
        self.assertIsNotNone(robot)

        # Assert the correct labels on the yaml nodes
        self.assertEqual(defaults.attr["label"], "defaults.yaml")
        self.assertEqual(robot.attr["label"], "robot.yaml")
    def testNoRosParamNodes(self):
        launchFile = "examples/fake_package/launch/rosparam_nodes.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
            ]

        status, output, graph = roslaunch_to_dot(launchFile, options=options)

        # Should not have failed
        self.assertEqual(status, 0)

        # The graph should not include rosparam nodes
        defaults = graph.get_node("yaml_fake_package_defaults_yaml")
        robot = graph.get_node("yaml_fake_package_robot_yaml")

        # Both rosparam files should exist
        self.assertIsNotNone(defaults)
        self.assertIsNotNone(robot)

        # Assert the correct labels on the yaml nodes
        self.assertEqual(defaults.attr["label"], "defaults.yaml")
        self.assertEqual(robot.attr["label"], "robot.yaml")
Example #35
0
    def testInvalidArg(self):
        # Various invalid attempts to specify arguments on the command line
        argAttempts = [
            "%s==example" % self.UndefinedArg,
            "%s=example" % self.UndefinedArg,
            "%s:example" % self.UndefinedArg,
            "%s-example" % self.UndefinedArg,
            ]

        for attempt in argAttempts:
            launchFile = "examples/fake_package/launch/arg_error.launch"
            args = [attempt]

            status, output, graph = roslaunch_to_dot(launchFile, args=args)

            # Should fail -- invalid arg
            self.assertNotEqual(status, 0)

            errorMsg = ErrorMsg.InvalidArg % ("0", attempt)

            # Should have an error about invalid arg
            numInvalid = output.count(errorMsg)
            self.assertEqual(numInvalid, 1)
    def testCommandLineArguments(self):
        launchFile = "examples/fake_package/launch/example.launch"
        args = [
            "fake:=value",
            "another:=1234",
            "bool:=true",
            "foo:=bar",
        ]

        status, output, graph = roslaunch_to_dot(launchFile, args=args)

        # Should not have failed
        self.assertEqual(status, 0)

        # There must be a command line arguments node in this case
        cla = graph.get_node(self.ClaNodeName)
        self.assertIsNotNone(cla)

        # Check that each of the input command line arguments exists
        # in the label for the node
        claLabel = cla.attr['label']
        for argStr in args:
            self.assertTrue(argStr in claLabel)
Example #37
0
    def testRosParamMissingPackage(self):
        package = "this_package_does_not_exist"

        launchFile = \
            "examples/fake_package/launch/rosparam_unknown_pkg.launch"
        options = [
            "--show-rosparam-nodes",  # Include rosparam nodes
        ]
        args = []

        status, output, graph = roslaunch_to_dot(launchFile,
                                                 options=options,
                                                 args=args)

        # Script does not fail, just generates an error
        self.assertEqual(status, 0)

        # Create the error message string
        errorMsg = ErrorMsg.CanNotLocateRosPackage % package

        # Must have an error
        numErrors = output.count(errorMsg)
        self.assertEqual(numErrors, 1)
Example #38
0
    def testInvalidArg(self):
        # Various invalid attempts to specify arguments on the command line
        argAttempts = [
            "%s==example" % self.UndefinedArg,
            "%s=example" % self.UndefinedArg,
            "%s:example" % self.UndefinedArg,
            "%s-example" % self.UndefinedArg,
        ]

        for attempt in argAttempts:
            launchFile = "examples/fake_package/launch/arg_error.launch"
            args = [attempt]

            status, output, graph = roslaunch_to_dot(launchFile, args=args)

            # Should fail -- invalid arg
            self.assertNotEqual(status, 0)

            errorMsg = ErrorMsg.InvalidArg % ("0", attempt)

            # Should have an error about invalid arg
            numInvalid = output.count(errorMsg)
            self.assertEqual(numInvalid, 1)