mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-21 00:19:42 +02:00
Feature: generic fixtures tests (#529)
* add generic test runners * extract generic test runners * beautify messages, remove unused return value * add template and info do CONTRIBUTING * typo --------- Co-authored-by: Kelly Brazil <kellyjonbrazil@gmail.com>
This commit is contained in:
@ -33,8 +33,18 @@ actively welcome your pull requests:
|
|||||||
file.
|
file.
|
||||||
4. If you've added code that should be tested, add tests. All new parsers should
|
4. If you've added code that should be tested, add tests. All new parsers should
|
||||||
have several sample outputs and tests.
|
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)
|
- Templates:
|
||||||
or [tests/templates/_test_foo_s.py (streaming)](https://github.com/kellyjonbrazil/jc/tree/master/tests/templates) files as a template
|
- [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
|
- 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)
|
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
|
5. Documentation is auto-generated from docstrings, so ensure they are clear and
|
||||||
|
28
tests/templates/_test_foo_simple.py
Normal file
28
tests/templates/_test_foo_simple.py
Normal file
@ -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()
|
@ -1,59 +1,21 @@
|
|||||||
import os
|
|
||||||
import json
|
|
||||||
import unittest
|
import unittest
|
||||||
from typing import Dict
|
|
||||||
from jc.parsers.path import parse
|
|
||||||
|
|
||||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
from tests import utils_for_test as test_utils
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class MyTests(unittest.TestCase):
|
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):
|
def test_path_nodata(self):
|
||||||
"""
|
"""
|
||||||
Test 'path' with no data
|
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
|
Test 'path' with various logs
|
||||||
"""
|
"""
|
||||||
for file in self.fixtures:
|
test_utils.run_all_fixtures(self, __file__)
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -1,62 +1,23 @@
|
|||||||
import os
|
|
||||||
import json
|
|
||||||
import unittest
|
import unittest
|
||||||
from typing import Dict
|
|
||||||
from jc.parsers.path_list import parse
|
|
||||||
|
|
||||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
from tests import utils_for_test as test_utils
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class MyTests(unittest.TestCase):
|
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):
|
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):
|
test_utils.run_all_fixtures(self, __file__)
|
||||||
self.assertEqual(
|
|
||||||
parse(self.f_in[file], quiet=True),
|
|
||||||
self.f_json[file],
|
|
||||||
"Should be equal for test files: {0}.*".format(file)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
65
tests/utils_for_test.py
Normal file
65
tests/utils_for_test.py
Normal file
@ -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}.*'"
|
||||||
|
)
|
Reference in New Issue
Block a user