""" Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ from test.testlib.testcase import BaseTestCase import regex as re import cfnlint.decode.cfn_yaml # pylint: disable=E0401 from cfnlint.core import DEFAULT_RULESDIR # pylint: disable=E0401 from cfnlint.exceptions import DuplicateRuleError from cfnlint.rules import CloudFormationLintRule, RulesCollection from cfnlint.template import Template class TestRulesCollection(BaseTestCase): """Test Template RulesCollection in cfnlint""" def setUp(self): """SetUp template object""" self.rules = RulesCollection() self.rules.include_rules = ["I", "W", "E"] rulesdirs = [DEFAULT_RULESDIR] for rulesdir in rulesdirs: self.rules.create_from_directory(rulesdir) def test_rule_ids_unique(self): """Test Rule IDs are Unique""" existing_rules = [] for rule in self.rules: self.assertFalse(rule.id in existing_rules) existing_rules.append(rule.id) def test_rule_ids_are_formatted_correctly(self): """Test Rule IDs are property formmated""" for rule in self.rules: self.assertIn(rule.id[0], ["W", "I", "E"]) self.assertEqual(len(rule.id), 5) self.assertTrue(isinstance(int(rule.id[1:]), int)) def test_success_run(self): """Test Run Logic""" filename = "test/fixtures/templates/good/generic.yaml" template = cfnlint.decode.cfn_yaml.load(filename) cfn = Template(filename, template, ["us-east-1"]) matches = [] matches.extend(self.rules.run(filename, cfn)) assert matches == [] def test_fail_run(self): """Test failure run""" filename = "test/fixtures/templates/bad/generic.yaml" template = cfnlint.decode.cfn_yaml.load(filename) cfn = Template(filename, template, ["us-east-1"]) expected_err_count = 33 matches = [] matches.extend(self.rules.run(filename, cfn)) assert ( len(matches) == expected_err_count ), "Expected {} failures, got {}".format(expected_err_count, len(matches)) def test_fail_sub_properties_run(self): """Test failure run""" filename = "test/fixtures/templates/bad/resources/properties/onlyone.yaml" template = cfnlint.decode.cfn_yaml.load(filename) cfn = Template(filename, template, ["us-east-1"]) matches = [] matches.extend(self.rules.run(filename, cfn)) self.assertEqual( 4, len(matches), "Expected {} failures, got {}".format(4, len(matches)) ) def test_success_filtering_of_rules_default(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_w0000(CloudFormationLintRule): """Warning Rule""" id = "W0000" class rule_i0000(CloudFormationLintRule): """Info Rule""" id = "I0000" rules_to_add = [rule_e0000(), rule_w0000(), rule_i0000()] rules = RulesCollection(ignore_rules=None, include_rules=None) rules.extend(rules_to_add) self.assertEqual(len(rules), 2) for rule in rules: self.assertIn(rule.id, ["W0000", "E0000"]) def test_success_filtering_of_rules_include_info(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_w0000(CloudFormationLintRule): """Warning Rule""" id = "W0000" class rule_i0000(CloudFormationLintRule): """Info Rule""" id = "I0000" rules_to_add = [rule_e0000(), rule_w0000(), rule_i0000()] rules = RulesCollection(ignore_rules=None, include_rules=["I"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 3) for rule in rules: self.assertIn(rule.id, ["I0000", "W0000", "E0000"]) def test_success_filtering_of_rules_exclude(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_w0000(CloudFormationLintRule): """Warning Rule""" id = "W0000" class rule_i0000(CloudFormationLintRule): """Info Rule""" id = "I0000" rules_to_add = [rule_e0000(), rule_w0000(), rule_i0000()] rules = RulesCollection(ignore_rules=["E"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 1) for rule in rules: self.assertIn(rule.id, ["W0000"]) def test_success_filtering_of_rules_exclude_long(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_e0010(CloudFormationLintRule): """Error Rule""" id = "E0010" class rule_e0002(CloudFormationLintRule): """Error Rule""" id = "E0002" rules_to_add = [rule_e0000(), rule_e0010(), rule_e0002()] rules = RulesCollection(ignore_rules=["E000"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 1) for rule in rules: self.assertIn(rule.id, ["E0010"]) def test_success_filtering_of_rules_exclude_longer(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_e0010(CloudFormationLintRule): """Error Rule""" id = "E0010" class rule_e0002(CloudFormationLintRule): """Error Rule""" id = "E0002" rules_to_add = [rule_e0000(), rule_e0010(), rule_e0002()] rules = RulesCollection(ignore_rules=["E0002"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 2) for rule in rules: self.assertIn(rule.id, ["E0000", "E0010"]) def test_success_filtering_of_rules_exclude_mandatory(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_w0000(CloudFormationLintRule): """Warning Rule""" id = "W0000" class rule_i0000(CloudFormationLintRule): """Info Rule""" id = "I0000" rules_to_add = [rule_e0000(), rule_w0000(), rule_i0000()] rules = RulesCollection(ignore_rules=["E"], mandatory_rules=["E"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 2) for rule in rules: self.assertIn(rule.id, ["E0000", "W0000"]) def test_success_filtering_of_rules_exclude_mandatory_long(self): """Test extend function""" class rule_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule_e0010(CloudFormationLintRule): """Error Rule""" id = "E0010" class rule_e0002(CloudFormationLintRule): """Error Rule""" id = "E0002" class rule_w0000(CloudFormationLintRule): """Warning Rule""" id = "W0000" rules_to_add = [rule_e0000(), rule_e0010(), rule_e0002(), rule_w0000()] rules = RulesCollection(ignore_rules=["E"], mandatory_rules=["E000"]) rules.extend(rules_to_add) self.assertEqual(len(rules), 3) for rule in rules: self.assertIn(rule.id, ["E0000", "E0002", "W0000"]) def test_duplicate_rules(self): """Test extend function""" class rule0_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" class rule1_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" rules_to_add = [rule0_e0000(), rule1_e0000()] rules = RulesCollection() self.assertRaises(DuplicateRuleError, rules.extend, rules_to_add) def test_repr(self): class rule0_e0000(CloudFormationLintRule): """Error Rule""" id = "E0000" shortdesc = "Rule A" description = "First rule" class rule1_e0001(CloudFormationLintRule): """Error Rule""" id = "E0001" shortdesc = "Rule B" description = "Second rule" rules = RulesCollection() rules.extend([rule0_e0000(), rule1_e0001()]) retval = repr(rules) pattern = r"\AE0000: Rule A\nFirst rule\nE0001: Rule B\nSecond rule\Z" match = re.match(pattern, retval) assert match, f"{retval} does not match {pattern}" class TestCreateFromModule(BaseTestCase): """Test loading a rules collection from a module""" def test_create_from_module(self): """Load rules from a module""" rules = RulesCollection() rules.create_from_module("cfnlint.rules.templates.Base") self.assertIn("E1001", (r.id for r in rules))