diff --git a/tests/common.py b/tests/common.py index 8cbb341..65af63b 100644 --- a/tests/common.py +++ b/tests/common.py @@ -13,7 +13,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import contextlib import os +import shutil import tempfile import unittest @@ -68,3 +70,17 @@ def build_temp_workspace(files): f.write(content) return tempdir + + +@contextlib.contextmanager +def temp_workspace(files): + """Provide a temporary workspace that is automatically cleaned up.""" + backup_wd = os.getcwd() + wd = build_temp_workspace(files) + + try: + os.chdir(wd) + yield + finally: + os.chdir(backup_wd) + shutil.rmtree(wd) diff --git a/tests/rules/test_key_ordering.py b/tests/rules/test_key_ordering.py index f71af02..7d17603 100644 --- a/tests/rules/test_key_ordering.py +++ b/tests/rules/test_key_ordering.py @@ -116,7 +116,7 @@ class KeyOrderingTestCase(RuleTestCase): self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None)) try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') - except locale.Error: + except locale.Error: # pragma: no cover self.skipTest('locale en_US.UTF-8 not available') conf = ('key-ordering: enable') self.check('---\n' @@ -135,7 +135,7 @@ class KeyOrderingTestCase(RuleTestCase): self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None)) try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') - except locale.Error: + except locale.Error: # pragma: no cover self.skipTest('locale en_US.UTF-8 not available') conf = ('key-ordering: enable') self.check('---\n' diff --git a/tests/rules/test_octal_values.py b/tests/rules/test_octal_values.py index 8e8f5e4..be5b039 100644 --- a/tests/rules/test_octal_values.py +++ b/tests/rules/test_octal_values.py @@ -32,6 +32,7 @@ class OctalValuesTestCase(RuleTestCase): ' forbid-explicit-octal: false\n' 'new-line-at-end-of-file: disable\n' 'document-start: disable\n') + self.check('after-tag: !custom_tag 010', conf) self.check('user-city: 010', conf, problem=(1, 15)) self.check('user-city: abc', conf) self.check('user-city: 010,0571', conf) diff --git a/tests/test_cli.py b/tests/test_cli.py index 8bce87a..3ac5b09 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -23,7 +23,7 @@ import sys import tempfile import unittest -from tests.common import build_temp_workspace +from tests.common import build_temp_workspace, temp_workspace from yamllint import cli from yamllint import config @@ -58,7 +58,7 @@ def utf8_available(): locale.setlocale(locale.LC_ALL, 'C.UTF-8') locale.setlocale(locale.LC_ALL, (None, None)) return True - except locale.Error: + except locale.Error: # pragma: no cover return False @@ -281,6 +281,16 @@ class CommandLineTestCase(unittest.TestCase): self.assertEqual(ctx.stdout, '') self.assertRegex(ctx.stderr, r'^invalid config: not a dict') + def test_run_with_implicit_extends_config(self): + path = os.path.join(self.wd, 'warn.yaml') + + with RunContext(self) as ctx: + cli.run(('-d', 'default', '-f', 'parsable', path)) + expected_out = ('%s:1:1: [warning] missing document start "---" ' + '(document-start)\n' % path) + self.assertEqual( + (ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, '')) + def test_run_with_config_file(self): with open(os.path.join(self.wd, 'config'), 'w') as f: f.write('rules: {trailing-spaces: disable}') @@ -320,6 +330,19 @@ class CommandLineTestCase(unittest.TestCase): cli.run((os.path.join(self.wd, 'a.yaml'), )) self.assertEqual(ctx.returncode, 1) + def test_run_with_user_xdg_config_home_in_env(self): + self.addCleanup(os.environ.__delitem__, 'XDG_CONFIG_HOME') + + with tempfile.TemporaryDirectory('w') as d: + os.environ['XDG_CONFIG_HOME'] = d + os.makedirs(os.path.join(d, 'yamllint')) + with open(os.path.join(d, 'yamllint', 'config'), 'w') as f: + f.write('extends: relaxed') + with RunContext(self) as ctx: + cli.run(('-f', 'parsable', os.path.join(self.wd, 'warn.yaml'))) + + self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', '')) + def test_run_with_user_yamllint_config_file_in_env(self): self.addCleanup(os.environ.__delitem__, 'YAMLLINT_CONFIG_FILE') @@ -345,7 +368,7 @@ class CommandLineTestCase(unittest.TestCase): # as the first two runs don't use setlocale() try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') - except locale.Error: + except locale.Error: # pragma: no cover self.skipTest('locale en_US.UTF-8 not available') locale.setlocale(locale.LC_ALL, (None, None)) @@ -546,6 +569,19 @@ class CommandLineTestCase(unittest.TestCase): self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) + def test_run_format_colored_warning(self): + path = os.path.join(self.wd, 'warn.yaml') + + with RunContext(self) as ctx: + cli.run((path, '--format', 'colored')) + expected_out = ( + '\033[4m%s\033[0m\n' + ' \033[2m1:1\033[0m \033[33mwarning\033[0m ' + 'missing document start "---" \033[2m(document-start)\033[0m\n' + '\n' % path) + self.assertEqual( + (ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, '')) + def test_run_format_github(self): path = os.path.join(self.wd, 'a.yaml') @@ -641,3 +677,27 @@ class CommandLineTestCase(unittest.TestCase): '\n' % path) self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) + + +class CommandLineConfigTestCase(unittest.TestCase): + def test_config_file(self): + workspace = {'a.yml': 'hello: world\n'} + conf = ('---\n' + 'extends: relaxed\n') + + for conf_file in ('.yamllint', '.yamllint.yml', '.yamllint.yaml'): + with self.subTest(conf_file): + with temp_workspace(workspace): + with RunContext(self) as ctx: + cli.run(('-f', 'parsable', '.')) + + self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), + (0, './a.yml:1:1: [warning] missing document ' + 'start "---" (document-start)\n', '')) + + with temp_workspace({**workspace, **{conf_file: conf}}): + with RunContext(self) as ctx: + cli.run(('-f', 'parsable', '.')) + + self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), + (0, '', '')) diff --git a/tests/test_config.py b/tests/test_config.py index 105ae18..3618a30 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -189,6 +189,41 @@ class SimpleConfigTestCase(unittest.TestCase): config.validate_rule_conf, Rule, {'multiple': ['item4']}) + def test_invalid_rule(self): + with self.assertRaisesRegex( + config.YamlLintConfigError, + 'invalid config: rule "colons": should be either ' + '"enable", "disable" or a dict'): + config.YamlLintConfig('rules:\n' + ' colons: invalid\n') + + def test_invalid_ignore(self): + with self.assertRaisesRegex( + config.YamlLintConfigError, + 'invalid config: ignore should contain file patterns'): + config.YamlLintConfig('ignore: yes\n') + + def test_invalid_rule_ignore(self): + with self.assertRaisesRegex( + config.YamlLintConfigError, + 'invalid config: ignore should contain file patterns'): + config.YamlLintConfig('rules:\n' + ' colons:\n' + ' ignore: yes\n') + + def test_invalid_locale(self): + with self.assertRaisesRegex( + config.YamlLintConfigError, + 'invalid config: locale should be a string'): + config.YamlLintConfig('locale: yes\n') + + def test_invalid_yaml_files(self): + with self.assertRaisesRegex( + config.YamlLintConfigError, + 'invalid config: yaml-files should be a list of file ' + 'patterns'): + config.YamlLintConfig('yaml-files: yes\n') + class ExtendedConfigTestCase(unittest.TestCase): def test_extend_on_object(self): @@ -333,6 +368,16 @@ class ExtendedConfigTestCase(unittest.TestCase): self.assertEqual(c.rules['colons']['max-spaces-before'], 0) self.assertEqual(c.rules['colons']['max-spaces-after'], 1) + def test_extended_ignore(self): + with tempfile.NamedTemporaryFile('w') as f: + f.write('ignore: |\n' + ' *.template.yaml\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n') + + self.assertEqual(c.ignore.match_file('test.template.yaml'), True) + self.assertEqual(c.ignore.match_file('test.yaml'), False) + class ExtendedLibraryConfigTestCase(unittest.TestCase): def test_extend_config_disable_rule(self): diff --git a/tests/test_linter.py b/tests/test_linter.py index 51714fe..686068b 100644 --- a/tests/test_linter.py +++ b/tests/test_linter.py @@ -54,3 +54,13 @@ class LinterTestCase(unittest.TestCase): u'# الأَبْجَدِيَّة العَرَبِيَّة\n') linter.run(s, self.fake_config()) linter.run(s.encode('utf-8'), self.fake_config()) + + def test_linter_problem_repr_without_rule(self): + problem = linter.LintProblem(1, 2, 'problem') + + self.assertEqual(str(problem), '1:2: problem') + + def test_linter_problem_repr_with_rule(self): + problem = linter.LintProblem(1, 2, 'problem', 'rule-id') + + self.assertEqual(str(problem), '1:2: problem (rule-id)')