blob: 9a1a8c1c3caa26d3a1a6954e816657ade7605de8 [file] [log] [blame]
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#
#
'''
Test harness for running jinja_pylint.py across the templates.
'''
from __future__ import absolute_import, division, print_function, \
unicode_literals
import os, re, subprocess, sys, unittest
ME = os.path.abspath(__file__)
# Make CAmkES importable
sys.path.append(os.path.join(os.path.dirname(ME), '../../..'))
from camkes.internal.tests.utils import CAmkESTest
class TestPyLint(CAmkESTest):
def setUp(self):
super(TestPyLint, self).setUp()
self.lint = os.path.join(os.path.dirname(ME),
'../../../tools/jinja_pylint.py')
self.assertTrue(os.access(self.lint, os.X_OK),
'jinja_pylint.py not found or not executable')
# Pylint always generates errors when run on Jinja files. Some of these are
# spurious. Regexes to suppress spurious errors are given here.
to_ignore = frozenset([
# Pylint header.
re.compile(r'\*+\sModule\s\w+$'),
# Pylint always warns about missing Jinja supports.
re.compile(r'E:\s*\d+,\s*\d+:\s+Undefined variable\s+\'(environment|dummy)\'\s+\(undefined-variable\)$'),
# Jinja sometimes re-uses internal function names.
re.compile(r'E:\s*\d+,\s*\d+:\s+function already defined line \d+ \(function-redefined\)$'),
# Output from jinja_pylint.py (the other one, not us) itself.
re.compile('compiling to [^\s]+?\.\.\.$'),
re.compile('running pylint on [^\s]+?\.\.\.$'),
# Blank lines.
re.compile('$'),
])
def _lint(self, path):
'''
Generic lint invoker that we'll curry below.
'''
p = subprocess.Popen([self.lint, path, '--errors-only'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
# Pylint errors come out on stdout. Why? Who knows.
stdout, _ = p.communicate()
errors = []
for line in [x.strip() for x in stdout.split('\n')]:
if any((x.match(line) for x in to_ignore)):
continue
errors.append(line)
self.assertListEqual(errors, [], '\n'.join(['%s:' % path] + errors))
regex = re.compile(r'[^\w]')
template_dir = os.path.abspath(os.path.join(os.path.dirname(ME), '..'))
tests_dir = os.path.dirname(ME)
# Find all the templates.
for root, _, filenames in os.walk(template_dir):
if root.startswith(tests_dir):
# Don't analyse the test files.
continue
# For each template, monkey patch a test for it onto the test class.
for f in filenames:
if f.lower().endswith('.py'):
# Skip Python sources.
continue
name = 'test_%s' % regex.sub('_', f)
path = os.path.join(root, f)
setattr(TestPyLint, name, lambda self, path=path: _lint(self, path))
if __name__ == '__main__':
unittest.main()