diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74643df5..d54d080d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,8 +33,18 @@ actively welcome your pull requests: file. 4. If you've added code that should be tested, add tests. All new parsers should have several sample outputs and tests. - - Templates: Use the [tests/templates/_test_foo.py](https://github.com/kellyjonbrazil/jc/blob/master/tests/templates/_test_foo.py) - or [tests/templates/_test_foo_s.py (streaming)](https://github.com/kellyjonbrazil/jc/tree/master/tests/templates) files as a template + - Templates: + - [tests/templates/_test_foo.py](https://github.com/kellyjonbrazil/jc/blob/master/tests/templates/_test_foo.py) as a template for a test. + - [tests/templates/_test_foo_s.py (streaming)](https://github.com/kellyjonbrazil/jc/tree/master/tests/templates/_test_foo_s.py) as a template for a streaming test. + - [tests/templates/_test_foo_simple.py](https://github.com/kellyjonbrazil/jc/tree/master/tests/templates/_test_foo_simple.py) as a template if you only have test with fixtures. + Execute these steps for standard tests: + - Save this file as `text_{parser_name}.py` since the helper methods extract parser names from the filename. + - Organize fixtures in `text/fixtures` for optimal structure. + - Format fixtures as follows (using double dashes): + - `{parser_name}--{some_test_description}.out` for command output. + - `{parser_name}--{some_test_description}.json` for expected JSON after parsing. + + - Fixtures: Tests typically consist of an input file and an expected output JSON file. Add the data files to the appropriate folder under [tests/fixtures](https://github.com/kellyjonbrazil/jc/tree/master/tests/fixtures) 5. Documentation is auto-generated from docstrings, so ensure they are clear and diff --git a/tests/templates/_test_foo_simple.py b/tests/templates/_test_foo_simple.py new file mode 100644 index 00000000..5a33c19e --- /dev/null +++ b/tests/templates/_test_foo_simple.py @@ -0,0 +1,28 @@ +import unittest + +from tests import utils_for_test as test_utils + +# Execute these steps for standard tests: +# - Save this file as `text_{parser_name}.py` since the helper methods extract parser names from the filename. +# - Organize fixtures in `text/fixtures` for optimal structure. +# - Format fixtures as follows (using double dashes): +# - `{parser_name}--{some_test_description}.out` for command output. +# - `{parser_name}--{some_test_description}.json` for expected JSON after parsing. + +class MyTests(unittest.TestCase): + + def test_path_nodata(self): + """ + Test 'my_parser_name' with no data + """ + test_utils.run_no_data(self, __file__, {}) + + def test_all_fixtures(self): + """ + Test 'my_parser_name' with various fixtures + """ + test_utils.run_all_fixtures(self, __file__) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_path.py b/tests/test_path.py index 28a15d5b..14c9e6ba 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -1,59 +1,21 @@ -import os -import json import unittest -from typing import Dict -from jc.parsers.path import parse -THIS_DIR = os.path.dirname(os.path.abspath(__file__)) - -FIXTURES_DIR = 'fixtures/generic/' - - -def open_file(name, ext): - return open(get_path(name, ext), 'r', encoding='utf-8') - - -def get_path(name, ext): - return os.path.join(THIS_DIR, name + '.' + ext) +from tests import utils_for_test as test_utils class MyTests(unittest.TestCase): - f_in: Dict = {} - f_json: Dict = {} - - fixtures = { - 'path--one': 'fixtures/generic/path--one', - 'path--long': 'fixtures/generic/path--long', - 'path--windows': 'fixtures/generic/path--windows', - 'path--with-spaces': 'fixtures/generic/path--with-spaces', - } - - @classmethod - def setUpClass(cls): - - for file, filepath in cls.fixtures.items(): - with open_file(filepath, 'out') as in_file, \ - open_file(filepath, 'json') as json_file: - cls.f_in[file] = in_file.read() - cls.f_json[file] = json.loads(json_file.read()) def test_path_nodata(self): """ Test 'path' with no data """ - self.assertEqual(parse('', quiet=True), {}) + test_utils.run_no_data(self, __file__, {}) - def test_path(self): + def test_all_fixtures(self): """ Test 'path' with various logs """ - for file in self.fixtures: - with self.subTest("fixture: " + file): - self.assertEqual( - parse(self.f_in[file], quiet=True), - self.f_json[file], - "Should be equal for test files: {0}.*".format(file) - ) + test_utils.run_all_fixtures(self, __file__) if __name__ == '__main__': diff --git a/tests/test_path_list.py b/tests/test_path_list.py index 81c03e65..a87fcc17 100644 --- a/tests/test_path_list.py +++ b/tests/test_path_list.py @@ -1,62 +1,23 @@ -import os -import json import unittest -from typing import Dict -from jc.parsers.path_list import parse -THIS_DIR = os.path.dirname(os.path.abspath(__file__)) - -FIXTURES_DIR = 'fixtures/generic/' - - -def open_file(name, ext): - return open(get_path(name, ext), 'r', encoding='utf-8') - - -def get_path(name, ext): - return os.path.join(THIS_DIR, name + '.' + ext) +from tests import utils_for_test as test_utils class MyTests(unittest.TestCase): - f_in: Dict = {} - f_json: Dict = {} - - fixtures = { - 'path_list--one': 'fixtures/generic/path_list--one', - 'path_list--two': 'fixtures/generic/path_list--two', - 'path_list--long': 'fixtures/generic/path_list--long', - 'path_list--windows': 'fixtures/generic/path_list--windows', - 'path_list--windows-long': 'fixtures/generic/path_list--windows-long', - 'path_list--windows-environment': 'fixtures/generic/path_list--windows-environment', - 'path_list--with-spaces': 'fixtures/generic/path_list--with-spaces', - } - - @classmethod - def setUpClass(cls): - - for file, filepath in cls.fixtures.items(): - with open_file(filepath, 'out') as in_file, \ - open_file(filepath, 'json') as json_file: - cls.f_in[file] = in_file.read() - cls.f_json[file] = json.loads(json_file.read()) def test_path_nodata(self): """ - Test 'path' with no data + Test 'path_list' with no data """ - self.assertEqual(parse('', quiet=True), []) + # self.assertEqual(parse('', quiet=True), []) + test_utils.run_no_data(self, __file__, []) - def test_path(self): + def test_all_fixtures(self): """ - Test 'path' with various logs + Test 'path_list' with various logs """ - for file in self.fixtures: - with self.subTest("fixture: " + file): - self.assertEqual( - parse(self.f_in[file], quiet=True), - self.f_json[file], - "Should be equal for test files: {0}.*".format(file) - ) + + test_utils.run_all_fixtures(self, __file__) if __name__ == '__main__': diff --git a/tests/utils_for_test.py b/tests/utils_for_test.py new file mode 100644 index 00000000..a016dfc5 --- /dev/null +++ b/tests/utils_for_test.py @@ -0,0 +1,65 @@ +"""jc - JSON test utils""" +import inspect +import json +import os +from pathlib import Path + +import jc + + +def open_file(file_path, ext): + return open(Path(file_path).with_suffix(ext), 'r', encoding='utf-8') + + +def get_base_dir(file_path): + THIS_DIR = os.path.dirname(os.path.abspath(file_path)) + return THIS_DIR + + +def get_parser_name(): + # Get the calling file name from the stack + stack = inspect.stack() + calling_frame = stack[1] + calling_file_path = calling_frame[1] + + return get_parser_name_from_path(calling_file_path) + + +def get_parser_name_from_path(parser_path): + return Path(parser_path).stem[len('test_'):] + + +def get_fixtures(base_dir, parser_name): + fixtures = {x.stem: str(x.with_suffix('')) for x in + (list(Path(base_dir).glob(f"**/{parser_name}--*.*")))} + return fixtures + + +def run_no_data(self, test_parser_path, expected): + parser_name = get_parser_name_from_path(test_parser_path) + + # expected = jc.get_parser(parser_name).info.default_no_data + + with self.subTest(f"'no data test' for parser '{parser_name}': "): + self.assertEqual(jc.parse(parser_name, '', quiet=True), expected) + + +def run_all_fixtures(self, test_parser_path): + parser_name = get_parser_name_from_path(test_parser_path) + base_dir = get_base_dir(test_parser_path) + + print() + print(f"'run all fixtures' for parser '{parser_name}':") + for file, file_path in get_fixtures(base_dir, parser_name).items(): + print(f"- test '{parser_name}' parser with fixture: '{file}'") + with self.subTest(f"fixture: '{file}'"): + with open_file(file_path, '.out') as in_file, \ + open_file(file_path, '.json') as json_file: + f_in = in_file.read() + f_json = json.loads(json_file.read()) + + self.assertEqual( + jc.parse(parser_name, f_in, quiet=True), + f_json, + f"Should be equal for test files: '{file}.*'" + )