class TestModeQuotationRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(FileModeQuotationRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_MODE_QUOTATION_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_MODE_QUOTATION_LINE) self.assertEqual(3, len(results)) def test_missing_quotes(self): results = self.runner.run_state(MODE_MISSING_QUOTATION_LINE) self.assertEqual(3, len(results)) def test_network_mode(self): """ Ensure the mode argument in the network.managed state gets ignored. See related GitHub issue: https://github.com/warpnet/salt-lint/issues/255 """ results = self.runner.run_state(NETWORK_MANAGED_MODE) self.assertEqual(0, len(results))
class TestJinjaVariableHasSpaces(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(JinjaVariableHasSpacesRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_VARIABLE_LINE) self.assertEqual(0, len(results)) def test_statement_jinja_raw_positive(self): """Check if Jinja looking variables between raw-blocks are ignored.""" results = self.runner.run_state(GOOD_VARIABLE_LINE_RAW) self.assertEqual(0, len(results)) def test_statement_jinja_raw_negative(self): """Check if Jinja looking variables between raw-blocks are ignored.""" results = self.runner.run_state(BAD_VARIABLE_LINE_RAW) # Check if the correct number of matches are found self.assertEqual(1, len(results)) # Check if the match occurred on the correct line self.assertEqual(results[0].linenumber, 5) def test_statement_negative(self): results = self.runner.run_state(BAD_VARIABLE_LINE) self.assertEqual(1, len(results)) def test_double_quoted_integer(self): results = self.runner.run_state(DOUBLE_QUOTED_INTEGER_IS_VALID) self.assertEqual(0, len(results)) def test_double_quoted_integer_trailing_space_invalid(self): results = self.runner.run_state(DOUBLE_QUOTED_INTEGER_TRAILING_SPACE_IS_INVALID) self.assertEqual(1, len(results)) def test_double_quoted_integer_leading_space_invalid(self): results = self.runner.run_state(DOUBLE_QUOTED_INTEGER_LEADING_SPACE_IS_INVALID) self.assertEqual(1, len(results)) def test_variable_bad_ends_with_integer(self): results = self.runner.run_state(BAD_VARIABLE_ENDING_IN_INTEGER) self.assertEqual(1, len(results)) def test_variable_bad_ends_with_integer_right(self): results = self.runner.run_state(BAD_VARIABLE_ENDING_IN_INTEGER_RIGHT) self.assertEqual(1, len(results)) def test_nested_literal_braces(self): """ Check if Jinja variables inside nested literal braces are identified correctly. See related GitHub issue: https://github.com/warpnet/salt-lint/issues/257 """ results = self.runner.run_state(NESTED_LITERAL_BRACES) self.assertEqual(0, len(results))
class TestLineTooLongRule(unittest.TestCase): collection = RulesCollection() collection.register(LineTooLongRule()) def setUp(self): self.runner = RunFromText(self.collection) def test_long_line(self): results = self.runner.run_state(LONG_LINE) self.assertEqual(1, len(results))
class TestTrailingWhitespaceRule(unittest.TestCase): collection = RulesCollection() collection.register(TrailingWhitespaceRule()) def setUp(self): self.runner = RunFromText(self.collection) def test_trailing_whitespace(self): results = self.runner.run_state(LINE_AND_WHITESPACE) print(results) self.assertEqual(1, len(results))
class TestLineTooLongRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(JinjaStatementHasSpacesRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_STATEMENT_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_STATEMENT_LINE) self.assertEqual(1, len(results))
class TestJinjaPillarGrainsGetFormatRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(JinjaPillarGrainsGetFormatRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_STATEMENT_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_STATEMENT_LINE) self.assertEqual(2, len(results))
class TestTypoOnchangesRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(TypoOnchangesRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_ONCHANGES_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_ONCHANGES_LINE) self.assertEqual(3, len(results))
class TestModeQuotationRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(FileModeQuotationRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_MODE_QUOTATION_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_MODE_QUOTATION_LINE) self.assertEqual(3, len(results))
class TestFileModeLeadingZeroRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(FileModeLeadingZeroRule()) def test_statement_positive(self): runner = RunFromText(self.collection) results = runner.run_state(GOOD_MODE_LEADING_ZERO_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): runner = RunFromText(self.collection) results = runner.run_state(BAD_MODE_LEADING_ZERO_LINE) self.assertEqual(3, len(results))
class TestYamlHasOctalValueRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(YamlHasOctalValueRule()) def test_statement_positive(self): runner = RunFromText(self.collection) results = runner.run_state(GOOD_NUMBER_STATE) self.assertEqual(0, len(results)) def test_statement_negative(self): runner = RunFromText(self.collection) results = runner.run_state(BAD_NUMBER_STATE) self.assertEqual(4, len(results))
class TestCmdWaitRecommendRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(CmdWaitRecommendRule()) def test_statement_positive(self): runner = RunFromText(self.collection) results = runner.run_state(GOOD_CMD_STATE) self.assertEqual(0, len(results)) def test_statement_negative(self): runner = RunFromText(self.collection) results = runner.run_state(BAD_CMD_STATE) self.assertEqual(1, len(results))
class TestNoIrregularSpacesRule(unittest.TestCase): collection = RulesCollection() collection.register(NoIrregularSpacesRule()) def setUp(self): self.runner = RunFromText(self.collection) def test_with_irregular_spaces(self): for irregular in NoIrregularSpacesRule.irregular_spaces: results = self.runner.run_state(unicode(LINE).format(space=irregular)) self.assertEqual(1, len(results)) def test_without_irregular_spaces(self): results = self.runner.run_state(LINE.format(space=" ")) self.assertEqual(0, len(results))
class TestLineTooLongRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(FileExtensionRule()) def test_file_positive(self): path = 'tests/test-extension-success.sls' runner = Runner(self.collection, path, Configuration()) self.assertEqual([], runner.run()) def test_file_negative(self): path = 'tests/test-extension-failure' runner = Runner(self.collection, path, Configuration()) errors = runner.run() self.assertEqual(1, len(errors))
class TestNoTabsRule(unittest.TestCase): collection = RulesCollection() collection.register(NoTabsRule()) def setUp(self): self.runner = RunFromText(self.collection) def test_with_tabs(self): results = self.runner.run_state(LINE_WITH_TABS) self.assertEqual(2, len(results)) def test_with_spaces(self): results = self.runner.run_state(LINE_WITH_SPACES) self.assertEqual(0, len(results)) def test_mixed_tab_space(self): results = self.runner.run_state(LINE_MIXED_TAB_SPACE) self.assertEqual(1, len(results))
class TestCmdRunQuietRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(CmdRunQuietRule()) def test_statement_positive(self): runner = RunFromText(self.collection) results = runner.run_state(GOOD_QUIET_STATE) self.assertEqual(0, len(results)) def test_statement_negative(self): runner = RunFromText(self.collection) results = runner.run_state(BAD_QUIET_STATE) self.assertEqual(2, len(results)) # Check line numbers of the results self.assertEqual(9, results[0].linenumber) self.assertEqual(14, results[1].linenumber)
class TestFileManagedReplaceContentRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(FileManagedReplaceContentRule()) def test_statement_positive(self): runner = RunFromText(self.collection) results = runner.run_state(GOOD_FILE_STATE) self.assertEqual(0, len(results)) def test_statement_negative(self): runner = RunFromText(self.collection) results = runner.run_state(BAD_FILE_STATE) self.assertEqual(3, len(results)) # Check line numbers of the results self.assertEqual(3, results[0].linenumber) self.assertEqual(10, results[1].linenumber) self.assertEqual(19, results[2].linenumber)
class TestSkipRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(LineTooLongRule()) self.collection.register(JinjaVariableHasSpacesRule()) def test_no_skip_rule(self): runner = RunFromText(self.collection) results = runner.run_state(LINE) self.assertEqual(1, len(results)) def test_skip_multiple_rules(self): runner = RunFromText(self.collection) results = runner.run_state(LINE_SKIP_MULTIPLE) self.assertEqual(0, len(results)) def test_skip_rule(self): runner = RunFromText(self.collection) results = runner.run_state(LINE_SKIP) self.assertEqual(0, len(results))
class TestSLSFileNameRule(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(SLSFileNameRule()) def test_file_positive(self): path = 'tests/test-extension-success.sls' runner = Runner(self.collection, path, Configuration()) self.assertEqual([], runner.run()) path = 'tests/test-extension-failure' runner = Runner(self.collection, path, Configuration()) self.assertEqual([], runner.run()) path = 'tests/test-extension-failure.extra.jinja' runner = Runner(self.collection, path, Configuration()) self.assertEqual([], runner.run()) def test_file_negative(self): path = 'tests/test-extension-failure.extra.sls' runner = Runner(self.collection, path, Configuration()) self.assertEqual(1, len(runner.run()))
class TestJinjaVariableHasSpaces(unittest.TestCase): collection = RulesCollection() def setUp(self): self.collection.register(JinjaVariableHasSpacesRule()) self.runner = RunFromText(self.collection) def test_statement_positive(self): results = self.runner.run_state(GOOD_VARIABLE_LINE) self.assertEqual(0, len(results)) def test_statement_negative(self): results = self.runner.run_state(BAD_VARIABLE_LINE) self.assertEqual(1, len(results)) def test_double_quoted_integer(self): results = self.runner.run_state(DOUBLE_QUOTED_INTEGER_IS_VALID) self.assertEqual(0, len(results)) def test_double_quoted_integer_trailing_space_invalid(self): results = self.runner.run_state( DOUBLE_QUOTED_INTEGER_TRAILING_SPACE_IS_INVALID) self.assertEqual(1, len(results)) def test_double_quoted_integer_leading_space_invalid(self): results = self.runner.run_state( DOUBLE_QUOTED_INTEGER_LEADING_SPACE_IS_INVALID) self.assertEqual(1, len(results)) def test_variable_bad_ends_with_integer(self): results = self.runner.run_state(BAD_VARIABLE_ENDING_IN_INTEGER) self.assertEqual(1, len(results)) def test_variable_bad_ends_with_integer_right(self): results = self.runner.run_state(BAD_VARIABLE_ENDING_IN_INTEGER_RIGHT) self.assertEqual(1, len(results))
def run(args=None): """Run the linter and return the exit code.""" # Wrap `sys.stdout` in an object that automatically encodes an unicode # string into utf-8, in Python 2 only. The default encoding for Python 3 # is already utf-8. if sys.version_info[0] < 3: sys.stdout = codecs.getwriter('utf-8')(sys.stdout) parser = init_argument_parser() options = parser.parse_args(args if args is not None else sys.argv[1:]) stdin_file = None file_names = set(options.files) checked_files = set() # Read input from STDIN if not sys.stdin.isatty(): stdin_file = tempfile.NamedTemporaryFile('w', suffix='.sls', delete=False) stdin_file.write(sys.stdin.read()) stdin_file.flush() file_names.add(stdin_file.name) # Read, parse and validate the configuration options_dict = vars(options) try: config = Configuration(options_dict) except SaltLintConfigError as exc: print(exc) return 2 # Show a help message on the screen if not file_names and not (options.listrules or options.listtags): parser.print_help(file=sys.stderr) return 1 # Collect the rules from the configuration collection = RulesCollection(config) for rulesdir in config.rulesdirs: collection.extend(RulesCollection.create_from_directory(rulesdir, config)) # Show the rules listing if options.listrules: print(collection) return 0 # Show the tags listing if options.listtags: print(collection.listtags()) return 0 formatter = initialize_formatter(config) problems = [] for file_name in file_names: runner = Runner(collection, file_name, config, checked_files) problems.extend(runner.run()) # Delete stdin temporary file if stdin_file: os.unlink(stdin_file.name) if problems: sorted_problems = sort_problems(problems) formatter.process(sorted_problems) return 2 return 0
def run(args=None): """Run the linter and return the exit code.""" parser = init_argument_parser() options = parser.parse_args(args if args is not None else sys.argv[1:]) stdin_filename = None file_names = set(options.files) checked_files = set() # Read input from STDIN if not sys.stdin.isatty(): with tempfile.NamedTemporaryFile('w', suffix='.sls', delete=False) as stdin_tmpfile: stdin_tmpfile.write(sys.stdin.read()) stdin_filename = stdin_tmpfile.name file_names.add(stdin_filename) # Read, parse and validate the configuration options_dict = vars(options) try: config = Configuration(options_dict) except SaltLintConfigError as exc: print(exc) return 2 # Show a help message on the screen if not file_names and not (options.listrules or options.listtags): parser.print_help(file=sys.stderr) return 1 # Collect the rules from the configuration collection = RulesCollection(config) for rulesdir in config.rulesdirs: collection.extend( RulesCollection.create_from_directory(rulesdir, config)) # Show the rules listing if options.listrules: print(collection) return 0 # Show the tags listing if options.listtags: print(collection.listtags()) return 0 formatter = initialize_formatter(config) problems = [] for file_name in file_names: runner = Runner(collection, file_name, config, checked_files) problems.extend(runner.run()) # Delete stdin temporary file if stdin_filename: os.unlink(stdin_filename) if problems: sorted_problems = sort_problems(problems) formatter.process(sorted_problems) return 2 return 0