diff --git a/.gitignore b/.gitignore index 72b59d2..94e4d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,62 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python build/ +develop-eggs/ dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# IntelliJ project files +.idea +*.iml +out + .pytest_cache/** .eggs/** *.egg-info/** **/.pytest_cache/** **/__pycache__/** fmfexporter.log -.idea **/.pyc -venv diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..08587f3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,45 @@ +sudo: false +language: python +python: + - "3.6" + #- "3.7-dev" + +install: + - pip install wheel codecov coverage tox-travis + - python setup.py bdist_wheel + - pip install ./dist/fmfexporter-*.whl + +stages: + - name: tests + - name: deploy + +jobs: + fast_finish: true + include: + - stage: tests + script: tox + after_script: + - codecov + - stage: deploy + name: "Deploy fmfexporter to Test PyPi" + python: 3.6 + install: true + script: skip + after_success: true + deploy: + - provider: pypi + user: rh-messaging-qe + server: https://testpypi.python.org/pypi + password: + secure: "TFxPZnlE6piKSv8EbLxX4yrlyuIFuEjzvNA/aEXSqpq3qTLJtEBDdfzLyIqXLW5UFtmKsjPur/L5cdrVN+5Pw5yHdxWA7amUpm60GOf7J3Kk9RcSbfEZ2wISWuhSqIbEeounIiuRcleClPysiZOrLc9sqWXqDUjT4IxDvMIlJy3/4FIRG+0Vbj2NktMsaj0v2Byp34Ju174mFDSA/UgIw78vj4F6OEI2f18DUx17MPOFXMc9klFeGCmlM1Je1cnFIlKX/YaasHXsxeLXu+y0btACORKAAVmOkFRPt3vgxgqBw3T2I1u10Ufbj9xySLBMcXxeYJMmQGursOxAI6lXPZ3TgKPigqERb1+0XJeftr+7+b3lVcAFpa6IthIAfUed51UcmvtJEzWzj1jv5AaDYbpaK4wWrX/Rgxh7tEIJ93GxF+5D6oHyqM7bDxEzSNt4wnq83DKyE1Imq2o+9Ks/jmrT8Vk0j8yUf+BKDLuRJwjP0ZJhmpF3EBihG/DC7VXgs/a7k2DPHwi0cn8tOSlz2meDsHG6wbOVKTr9iS7uDe/MJSJRzDR5Cnbk4bM7mLJ4qm3uI42pJgEPyr3CnKZBkvMnQ+9RDNDzDp+hyhx+tlKq3EpGf/Sf68gyNLT7ACgX08om8CshXxR52JeIbF6cb5xS2UUHvHfolNvPDnvk0UA=" + distributions: bdist_wheel + on: + all_branches: true + - provider: pypi + user: rh-messaging-qe + password: + secure: "hYxFSBJBKcYYmU/dfKzjLCh6Gpw8X2pCIQls0HTcm1wmuYa9O+HGxQivwhLWmaJAjIkdfGAQmUCF1h7H5nDQUQj/FxSZN00qwQY+vPanu0XcJ6aIv4yobM1Z67w2mylYJNQRk10qiDQ5Xm+p+cbBFgNcgrQfFkwvlN3JmuIzhIl0+iVo+mIPQu6xiXDT5Lxus6yKIhG9UNhkdytV1R2KLBKn5sOu5bUYsC6Ayqn0yyro+ncab2IMfeMFDscMNVLDk75S4JD+FzIcRGxUjg32SixTFMUvbdRBbxgupB7DQDhX+De7rHWWp8hRyMylxBFvmHE17drq3Vv57a8gA/pIS/CytTlWxPUsI5rbnznoyCxiqmE4S7QBex/Pp6ZcE14oZD6YYPS1cbzYy/JU0QpLrruqcDyklOIjRYeDASZFbwhBX9gvB+Ve9G9SlPmDzrITPxQiGh0ud/1UkQZl/j3WuQ2hiXIpvMOVK0DBb0uMWEKd9iAQcSFMKE/v+bO4reIx3fSXQ+W4zAc2EWDknusesnK9fFH1nJZl53Zv9qY3nGuh3xqnY0FZl77prnhRNR/HXzFVGvL/gHnzNzSWhrxxdPkIHcMFGu0wpWxFzxbIWTLduFPsR+GCOn/8277JSjf1dcl8UDhhlVQ5XeLSDst52/lIw+yo59g0ResRYVROF4k=" + distributions: bdist_wheel + on: + branch: master + tags: true \ No newline at end of file diff --git a/Makefile b/Makefile index 7a39688..dd4db6b 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,6 @@ upload: clean: python setup.py clean - rm -rf build dist fmfexporter.egg-info .eggs + rm -rf build dist fmfexporter.egg-info .eggs .tox find . -type f -name "*.py[co]" -delete find . -type d -name "__pycache__" -delete diff --git a/README.md b/README.md index 914b8bb..a041b85 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # fmfexporter +[![Build Status](https://img.shields.io/travis/rh-messaging-qe/fmfexporter.svg?style=for-the-badge)](https://travis-ci.org/rh-messaging-qe/fmfexporter) +[![Code coverage](https://img.shields.io/codecov/c/github/rh-messaging-qe/fmfexporter.svg?style=for-the-badge)](https://codecov.io/gh/rh-messaging-qe/fmfexporter) + FMF (Flexible Metadata Format) test case exporter tool. This tool can be used to convert and export Test Cases defined @@ -13,7 +16,7 @@ Format for defining the test case is YAML (Simple example available -- *WIP* -- ## Pre-requisites -* python 3.6+ +* Python 3.6+ * recommended to install fmfexporter or its requirements in a virtualenv ## Usage diff --git a/setup.cfg b/setup.cfg index c370951..1d17378 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,6 @@ [aliases] test = pytest + [tool:pytest] addopts = -s -vvv -python_files = test/*.py +python_files = tests/*.py diff --git a/setup.py b/setup.py index b6fe1af..e90f12d 100644 --- a/setup.py +++ b/setup.py @@ -14,14 +14,15 @@ install_requires=['fmf', 'requests', 'urllib3'], setup_requires=['pytest-runner', 'fmf', 'requests', 'urllib3'], tests_require=['pytest'], - author="Fernando Giorgetti, Dominik Lenoch", - author_email="fgiorget@redhatcom, dlenoch@redhat.com", + author='Fernando Giorgetti, Dominik Lenoch', + author_email='fgiorget@redhatcom, dlenoch@redhat.com', license="Apache-2.0", description="Flexible Metadata Format test-case exporter tool", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/rhmessagingqe/fmfexporter", - packages=setuptools.find_packages(), + packages=setuptools.find_packages(where="src"), + package_dir={'': 'src'}, provides=['fmfexporter'], classifiers=[ "Programming Language :: Python :: 3.6", diff --git a/fmfexporter/__init__.py b/src/fmfexporter/__init__.py similarity index 70% rename from fmfexporter/__init__.py rename to src/fmfexporter/__init__.py index 98f2c5b..5f452cb 100644 --- a/fmfexporter/__init__.py +++ b/src/fmfexporter/__init__.py @@ -1,2 +1,4 @@ from fmfexporter.fmf_testcase import FMFTestCase from fmfexporter.fmf_adapter import FMFAdapter + +__all__ = ['FMFTestCase', 'FMFAdapter'] diff --git a/fmfexporter/adapters/__init__.py b/src/fmfexporter/adapters/__init__.py similarity index 54% rename from fmfexporter/adapters/__init__.py rename to src/fmfexporter/adapters/__init__.py index 214fe01..8383b07 100644 --- a/fmfexporter/adapters/__init__.py +++ b/src/fmfexporter/adapters/__init__.py @@ -2,4 +2,6 @@ # All concrete adapters should be imported here, otherwise they # won't be recognized as subclasses of FMFAdapter (__subclasses__()). # -from fmfexporter.adapters.polarion.fmf_adapter_polarion import * +from fmfexporter.adapters.polarion.fmf_adapter_polarion import FMFAdapterPolarion + +__all__ = ['FMFAdapterPolarion'] diff --git a/fmfexporter/adapters/polarion/__init__.py b/src/fmfexporter/adapters/polarion/__init__.py similarity index 100% rename from fmfexporter/adapters/polarion/__init__.py rename to src/fmfexporter/adapters/polarion/__init__.py diff --git a/fmfexporter/adapters/polarion/args/__init__.py b/src/fmfexporter/adapters/polarion/args/__init__.py similarity index 100% rename from fmfexporter/adapters/polarion/args/__init__.py rename to src/fmfexporter/adapters/polarion/args/__init__.py diff --git a/fmfexporter/adapters/polarion/args/polarion_args_parser.py b/src/fmfexporter/adapters/polarion/args/polarion_args_parser.py similarity index 99% rename from fmfexporter/adapters/polarion/args/polarion_args_parser.py rename to src/fmfexporter/adapters/polarion/args/polarion_args_parser.py index bd5e087..60dc285 100644 --- a/fmfexporter/adapters/polarion/args/polarion_args_parser.py +++ b/src/fmfexporter/adapters/polarion/args/polarion_args_parser.py @@ -4,10 +4,12 @@ from fmfexporter.adapters.polarion.utils.polarion_config import PolarionConfig from fmfexporter.fmf_adapter import FMFAdapterArgParser + """ Argument parser for the FMF Polarion Adapter. """ + class PolarionArgParser(FMFAdapterArgParser): """ Argument parser that is used when polarion adapter is selected. diff --git a/fmfexporter/adapters/polarion/fmf_adapter_polarion.py b/src/fmfexporter/adapters/polarion/fmf_adapter_polarion.py similarity index 100% rename from fmfexporter/adapters/polarion/fmf_adapter_polarion.py rename to src/fmfexporter/adapters/polarion/fmf_adapter_polarion.py diff --git a/fmfexporter/adapters/polarion/polarion_reporter.py b/src/fmfexporter/adapters/polarion/polarion_reporter.py similarity index 100% rename from fmfexporter/adapters/polarion/polarion_reporter.py rename to src/fmfexporter/adapters/polarion/polarion_reporter.py diff --git a/fmfexporter/adapters/polarion/polarion_test_case.py b/src/fmfexporter/adapters/polarion/polarion_test_case.py similarity index 88% rename from fmfexporter/adapters/polarion/polarion_test_case.py rename to src/fmfexporter/adapters/polarion/polarion_test_case.py index 441f69c..31b25e0 100644 --- a/fmfexporter/adapters/polarion/polarion_test_case.py +++ b/src/fmfexporter/adapters/polarion/polarion_test_case.py @@ -1,6 +1,6 @@ from fmfexporter import FMFTestCase import re -import xml.etree.ElementTree as etree +import xml.etree.ElementTree as ElTree from xml.dom import minidom from fmfexporter.adapters.polarion.utils.polarion_xml import PolarionXmlUtils @@ -16,7 +16,7 @@ class PolarionTestCase(object): """ # Used to define file name for test case based on # classname.name (keeping just characters, numbers and dot) - RE_FILE_NAME = re.compile(r'[^A-Za-z0-9_\.]') + RE_FILE_NAME = re.compile(r'[^A-Za-z0-9_.]') # # Regular expression used to match user part of an e-mail address @@ -172,18 +172,18 @@ def to_xml(self): on current state of this instance. :return: str representing the test case xml """ - xmltree = etree.ElementTree(element=etree.Element('testcases')) + xmltree = ElTree.ElementTree(element=ElTree.Element('testcases')) # root element - testcases and attributes xmlroot = xmltree.getroot() xmlroot.attrib['project-id'] = self.project # properties - properties = etree.SubElement(xmlroot, 'properties') + properties = ElTree.SubElement(xmlroot, 'properties') PolarionXmlUtils.new_property_sub_element(properties, 'lookup-method', self.lookup_method) # testcase and attributes - tc = etree.SubElement(xmlroot, 'testcase') + tc = ElTree.SubElement(xmlroot, 'testcase') tc.set('assignee-id', self.assignee) if self.approvals: tc.set('approver-ids', ",".join([ap + ":approved" for ap in self.approvals])) @@ -192,11 +192,11 @@ def to_xml(self): # testcase child elements # testcase/title - tc_title = etree.SubElement(tc, 'title') + tc_title = ElTree.SubElement(tc, 'title') tc_title.text = self.title # testcase/description - tc_description = etree.SubElement(tc, 'description') + tc_description = ElTree.SubElement(tc, 'description') tc_description.text = PolarionTestCase.DESC_PREFIX_SUFFIX if self.description: tc_description.text += "
" @@ -205,7 +205,7 @@ def to_xml(self): tc_description.text += PolarionTestCase.DESC_PREFIX_SUFFIX # testcase/custom-fields - tc_custom = etree.SubElement(tc, 'custom-fields') + tc_custom = ElTree.SubElement(tc, 'custom-fields') PolarionXmlUtils.new_custom_field(tc_custom, 'casecomponent', self.component) PolarionXmlUtils.new_custom_field(tc_custom, 'subcomponent', self.sub_component) PolarionXmlUtils.new_custom_field(tc_custom, 'testtype', self.type) @@ -218,15 +218,17 @@ def to_xml(self): # testcase/linked-work-items if self.verifies: - tc_linked = etree.SubElement(tc, 'linked-work-items') - for verify in [verify for verify in self.verifies if isinstance(verify, dict)]: - PolarionXmlUtils.new_linked_work_item(tc_linked, - verify.get('polarion', verify.get('jira', '')), - 'verifies') + tc_linked = ElTree.SubElement(tc, 'linked-work-items') + for verify in [verify for verify in self.verifies + if isinstance(verify, dict)]: + PolarionXmlUtils.new_linked_work_item( + tc_linked, + verify.get('polarion', verify.get('jira', '')), + 'verifies') # testcase/test-steps if self.steps: - tc_steps = etree.SubElement(tc, 'test-steps') + tc_steps = ElTree.SubElement(tc, 'test-steps') # If test case has parameters, add them if self.parameters: @@ -235,6 +237,6 @@ def to_xml(self): for step in self.steps: PolarionXmlUtils.new_test_step(tc_steps, step.step, step.result) - xml_str = minidom.parseString(etree.tostring(xmlroot)).toprettyxml() + xml_str = minidom.parseString(ElTree.tostring(xmlroot)).toprettyxml() return xml_str diff --git a/fmfexporter/adapters/polarion/utils/__init__.py b/src/fmfexporter/adapters/polarion/utils/__init__.py similarity index 100% rename from fmfexporter/adapters/polarion/utils/__init__.py rename to src/fmfexporter/adapters/polarion/utils/__init__.py diff --git a/fmfexporter/adapters/polarion/utils/polarion_config.py b/src/fmfexporter/adapters/polarion/utils/polarion_config.py similarity index 100% rename from fmfexporter/adapters/polarion/utils/polarion_config.py rename to src/fmfexporter/adapters/polarion/utils/polarion_config.py diff --git a/fmfexporter/adapters/polarion/utils/polarion_xml.py b/src/fmfexporter/adapters/polarion/utils/polarion_xml.py similarity index 65% rename from fmfexporter/adapters/polarion/utils/polarion_xml.py rename to src/fmfexporter/adapters/polarion/utils/polarion_xml.py index db7b1d4..76b4fb7 100644 --- a/fmfexporter/adapters/polarion/utils/polarion_xml.py +++ b/src/fmfexporter/adapters/polarion/utils/polarion_xml.py @@ -3,7 +3,7 @@ sending them to the Polarion Importer. """ -import xml.etree.ElementTree as etree +import xml.etree.ElementTree as ElTree from typing import List @@ -15,24 +15,30 @@ class PolarionXmlUtils(object): """ @staticmethod - def new_linked_work_item(linked_work_item_parent: etree.Element, workitem_id: str, - role_id: str = 'verifies') -> None: + def new_linked_work_item( + linked_work_item_parent: ElTree.Element, + workitem_id: str, + role_id: str = 'verifies') -> None: """ - Creates sub-element named 'linked-work-item' within the given 'linked-work-items' parent. - It will also set the 'workitem-id' property using the id value provided. + Creates sub-element named 'linked-work-item' within the given + 'linked-work-items' parent. It will also set the 'workitem-id' + property using the id value provided. :param linked_work_item_parent: :param workitem_id: + :param role_id: :return: """ if workitem_id is None: return - sub_elem = etree.SubElement(linked_work_item_parent, 'linked-work-item') + sub_elem = ElTree.SubElement(linked_work_item_parent, + 'linked-work-item') sub_elem.set('workitem-id', workitem_id) sub_elem.set('lookup-method', 'id') sub_elem.set('role-id', role_id) @staticmethod - def new_custom_field(custom_fields_parent: etree.Element, id_field: str, content: str) -> None: + def new_custom_field(custom_fields_parent: ElTree.Element, + id_field: str, content: str) -> None: """ Creates sub-element named 'custom-field' within the given 'custom-fields' parent. It will also set the 'id' and 'content' attributes on the 'custom-field' element. @@ -44,12 +50,13 @@ def new_custom_field(custom_fields_parent: etree.Element, id_field: str, content """ if content is None: return - sub_elem = etree.SubElement(custom_fields_parent, 'custom-field') + sub_elem = ElTree.SubElement(custom_fields_parent, 'custom-field') sub_elem.set('id', id_field) sub_elem.set('content', content) @staticmethod - def new_test_step(test_steps_parent: etree.Element, step: str, result: str) -> None: + def new_test_step(test_steps_parent: ElTree.Element, + step: str, result: str) -> None: """ Create a test-step element within the provided test-steps (parent) and inside of it, two child elements named test-step-column will be created. The first one with @@ -65,31 +72,32 @@ def new_test_step(test_steps_parent: etree.Element, step: str, result: str) -> N return # The test-step that holds step and expectedResult - test_step = etree.SubElement(test_steps_parent, 'test-step') + test_step = ElTree.SubElement(test_steps_parent, 'test-step') # Step element - step_elem = etree.SubElement(test_step, 'test-step-column') + step_elem = ElTree.SubElement(test_step, 'test-step-column') step_elem.set('id', 'step') step_elem.text = step # Expected result element - result_elem = etree.SubElement(test_step, 'test-step-column') + result_elem = ElTree.SubElement(test_step, 'test-step-column') result_elem.set('id', 'expectedResult') result_elem.text = result @staticmethod - def new_test_step_params(test_steps_parent: etree.Element, params: List[str], scope: str="local") -> None: + def new_test_step_params(test_steps_parent: ElTree.Element, + params: List[str], scope: str = "local") -> None: if params is None: return # The test-step that holds all test parameters - test_step = etree.SubElement(test_steps_parent, 'test-step') + test_step = ElTree.SubElement(test_steps_parent, 'test-step') # Step element - step_elem = etree.SubElement(test_step, 'test-step-column', id='step') + step_elem = ElTree.SubElement(test_step, 'test-step-column', id='step') step_elem.text = 'Parameters: ' for (idx, param) in enumerate(params): - param_elem = etree.Element("parameter", name=param, scope=scope) + param_elem = ElTree.Element("parameter", name=param, scope=scope) if idx > 0: step_elem.text += ", " step_elem.text += param @@ -97,7 +105,7 @@ def new_test_step_params(test_steps_parent: etree.Element, params: List[str], sc step_elem.text += " => " @staticmethod - def new_property_sub_element(parent: etree.Element, name: str, value: str) -> None: + def new_property_sub_element(parent: ElTree.Element, name: str, value: str) -> None: """ Creates sub-element named 'property' within the given parent. It will also set the 'name' and 'value' attributes on the 'property' element. @@ -108,6 +116,6 @@ def new_property_sub_element(parent: etree.Element, name: str, value: str) -> No """ if value is None: return - sub_elem = etree.SubElement(parent, 'property') + sub_elem = ElTree.SubElement(parent, 'property') sub_elem.set('name', name) sub_elem.set('value', value) diff --git a/fmfexporter/args/__init__.py b/src/fmfexporter/args/__init__.py similarity index 100% rename from fmfexporter/args/__init__.py rename to src/fmfexporter/args/__init__.py diff --git a/fmfexporter/args/args_parser.py b/src/fmfexporter/args/args_parser.py similarity index 65% rename from fmfexporter/args/args_parser.py rename to src/fmfexporter/args/args_parser.py index 7dafdaa..71b90fe 100644 --- a/fmfexporter/args/args_parser.py +++ b/src/fmfexporter/args/args_parser.py @@ -4,7 +4,6 @@ import fmf from fmfexporter.fmf_adapter import FMFAdapter -from fmfexporter.adapters import * """ Common arguments for the fmfexporter tool. """ @@ -17,22 +16,34 @@ class FMFExporterArgParser(object): external adapter is used. """ - def __init__(self, *args, **kwargs): + def __init__(self): self._parser = argparse.ArgumentParser(prog='fmfexporter') # Common arguments adapters = FMFAdapter.get_available_adapters() - self._parser.add_argument("-p", "--path", required=True, - help="FMF Tree path containing your test cases") - self._parser.add_argument("--tc", action="append", - help="FMF Test Case filter (by name)") - self._parser.add_argument("--log-level", choices=['WARNING', 'INFO', 'DEBUG'], default='INFO', - help="Specify logging level to use") + self._parser.add_argument( + "-p", "--path", + required=True, + help="FMF Tree path containing your test cases" + ) + self._parser.add_argument( + "--tc", + action="append", + help="FMF Test Case filter (by name)" + ) + self._parser.add_argument( + "--log-level", + choices=['WARNING', 'INFO', 'DEBUG'], + default='INFO', + help="Specify logging level to use" + ) # Sub-commands from available adapters - sp = self._parser.add_subparsers(title='Adapter', help='Adapter help', dest='adapter') + sp = self._parser.add_subparsers( + title='Adapter', help='Adapter help', dest='adapter' + ) for adapter in adapters: parser = sp.add_parser(adapter, add_help=True) FMFAdapter.get_adapter_class(adapter).get_args_parser().add_arguments(parser) @@ -51,12 +62,14 @@ def parse_args(self, args=None, namespace=None): self._parsed_args = self._parser.parse_args(args, namespace) # Give a change for adapter's arg parser - adapter_parser = FMFAdapter.get_adapter_class(self.parsed_args.adapter).get_args_parser() + adapter_parser = FMFAdapter.get_adapter_class( + self.parsed_args.adapter).get_args_parser() adapter_parser.parse_arguments(self._parsed_args) # Validate if parsed arguments are ok try: - self._adapter = FMFAdapter.get_adapter(self._parsed_args.adapter, self._parsed_args.path) + self._adapter = FMFAdapter.get_adapter( + self._parsed_args.adapter, self._parsed_args.path) except fmf.utils.FileError: print("Invalid FMF Tree path: %s" % self._parsed_args.path) sys.exit(1) diff --git a/fmfexporter/fmf_adapter.py b/src/fmfexporter/fmf_adapter.py similarity index 99% rename from fmfexporter/fmf_adapter.py rename to src/fmfexporter/fmf_adapter.py index 13af5c8..34cf5be 100644 --- a/fmfexporter/fmf_adapter.py +++ b/src/fmfexporter/fmf_adapter.py @@ -143,7 +143,7 @@ def convert_from_list(self, fmf_testcase_list: List[FMFTestCase]): def submit_testcase_list(self, fmf_testcase_list: list): """ Submit a list of FMFAdapterTestCase objects (based on adapter's version of a test case). - :param fmf_adapter_testcase_list: + :param fmf_testcase_list: :return: """ print("Submitting %d test cases to %s" % (len(fmf_testcase_list), self.adapter_id())) diff --git a/fmfexporter/fmf_testcase.py b/src/fmfexporter/fmf_testcase.py similarity index 92% rename from fmfexporter/fmf_testcase.py rename to src/fmfexporter/fmf_testcase.py index e66368d..0ad036a 100644 --- a/fmfexporter/fmf_testcase.py +++ b/src/fmfexporter/fmf_testcase.py @@ -96,7 +96,8 @@ def __init__(self): @staticmethod def from_fmf_testcase_node(fmf_node: Tree): """ - This method is used to create an instance of an FMFTestCase based on a given node in the FMF Tree. + This method is used to create an instance of an FMFTestCase + based on a given node in the FMF Tree. :param fmf_node: :return: FMFTestCase instance """ @@ -140,8 +141,13 @@ def get_fmf_data(node, data, _default): fmf_tc.estimate = get_fmf_data(fmf_node, 'estimate', '') # Relationships - fmf_tc.defects = [FMFTestCaseRelationship(defect) for defect in get_fmf_data(fmf_node, 'defects', [])] - fmf_tc.requirements = [FMFTestCaseRelationship(req) for req in get_fmf_data(fmf_node, 'requirements', [])] + fmf_tc.defects = [ + FMFTestCaseRelationship(defect) for defect + in get_fmf_data(fmf_node, 'defects', []) + ] + fmf_tc.requirements = [ + FMFTestCaseRelationship(req) for req + in get_fmf_data(fmf_node, 'requirements', [])] # Steps fmf_tc.test_steps = get_fmf_data(fmf_node, 'test-steps', []) diff --git a/test/.fmf/version b/tests/.fmf/version similarity index 100% rename from test/.fmf/version rename to tests/.fmf/version diff --git a/test/fmfexporter.config.ini b/tests/fmfexporter.config.ini similarity index 100% rename from test/fmfexporter.config.ini rename to tests/fmfexporter.config.ini diff --git a/test/test_fmf_testcase_parser.py b/tests/test_fmf_testcase_parser.py similarity index 97% rename from test/test_fmf_testcase_parser.py rename to tests/test_fmf_testcase_parser.py index 86e7a03..c0f2135 100644 --- a/test/test_fmf_testcase_parser.py +++ b/tests/test_fmf_testcase_parser.py @@ -9,15 +9,16 @@ Validates if FMF Test Cases are being parsed as expected. """ + @pytest.fixture(scope="module") -def testcase(request) -> FMFTestCase: +def testcase() -> FMFTestCase: """ Generate a testcase fixture containing a static test case. - :param request: :return: """ fmf_adapter = FMFAdapterTest(os.path.dirname(os.path.abspath(__file__))) - tc = fmf_adapter.get_testcase('test_path.some_test_class.foo_test.TestFoo', 'test_foo_sample_01') + tc = fmf_adapter.get_testcase('test_path.some_test_class.foo_test.TestFoo', + 'test_foo_sample_01') return tc diff --git a/test/test_path/some_test_class/foo_test.fmf b/tests/test_path/some_test_class/foo_test.fmf similarity index 100% rename from test/test_path/some_test_class/foo_test.fmf rename to tests/test_path/some_test_class/foo_test.fmf diff --git a/test/test_polarion_config_parser.py b/tests/test_polarion_config_parser.py similarity index 85% rename from test/test_polarion_config_parser.py rename to tests/test_polarion_config_parser.py index 77439f6..4f683ed 100644 --- a/test/test_polarion_config_parser.py +++ b/tests/test_polarion_config_parser.py @@ -8,11 +8,10 @@ @pytest.fixture(scope="module") -def polarion_config(request): +def polarion_config(): """ Creates a polarion_config fixture based on a pre-populated config file for the Polarion adapter. - :param request: :return: """ return PolarionConfig(os.path.dirname(os.path.abspath(__file__)) + '/fmfexporter.config.ini') @@ -20,7 +19,8 @@ def polarion_config(request): def test_polarion_config_parser(polarion_config): """ - Asserts that the polarion adapater configuration keys and values have been parsed correctly. + Asserts that the polarion adapter configuration keys and values have been + parsed correctly. :param polarion_config: :return: """ diff --git a/test/test_polarion_fmftestcase_parser.py b/tests/test_polarion_fmftestcase_parser.py similarity index 95% rename from test/test_polarion_fmftestcase_parser.py rename to tests/test_polarion_fmftestcase_parser.py index adeba23..ee3e0ee 100644 --- a/test/test_polarion_fmftestcase_parser.py +++ b/tests/test_polarion_fmftestcase_parser.py @@ -10,15 +10,15 @@ @pytest.fixture(scope="module") -def testcase(request): +def testcase(): """ Creates a testcase fixture which is an instance of a PolarionTestCase class, and it is created from a generic FMF Test Case metadata. - :param request: :return: """ fmf_adapter = FMFAdapterPolarion(os.path.dirname(os.path.abspath(__file__))) - tc = fmf_adapter.get_testcase('test_path.some_test_class.foo_test.TestFoo', 'test_foo_sample_01') + tc = fmf_adapter.get_testcase('test_path.some_test_class.foo_test.TestFoo', + 'test_foo_sample_01') ptc = PolarionTestCase.from_fmf_testcase(tc) return ptc @@ -48,8 +48,10 @@ def test_polarion_fmftestcase_parser_authoring(testcase): def test_polarion_fmftestcase_parser_relationship(testcase): """ - Asserts that the Polarion Test Case verifies elements are mapped correctly from an FMF Test Case - TODO Probably need to be split into other fields for Polarion. Currently everything becomes "verifies". + Asserts that the Polarion Test Case verifies elements are mapped + correctly from an FMF Test Case + TODO Probably need to be split into other fields for Polarion. + Currently everything becomes "verifies". :param testcase: :return: """ diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..212125b --- /dev/null +++ b/tox.ini @@ -0,0 +1,57 @@ +[tox] +envlist = check,py36,py37,flake8,coverage-report + +[testenv] +commands = pytest +deps = + -rrequirements.txt + pytest-pep8 + pytest-cov +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes + +[testenv:flake8] +commands = flake8 . +deps = flake8 + +[pytest] +addopts = -s -vvv --cov=fmfexporter --cov=examples --cov=bin +testpaths = tests +python_files = tests/*.py +python_functions = test_ + +[flake8] +exclude = + .git, + .tox, + .pytest_cache, + build, + dist, + venv, + __pycache__, + .tox, + .eggs, + *.egg +skip_install = true +commands = flake8 . +deps = flake8 +max-line-length = 100 + +[testenv:clean] +commands = coverage erase +skip_install = true +usedevelop = false +deps = coverage + +[testenv:coverage-report] +deps = coverage +skip_install = true +commands = + coverage report + +[testenv:check] +skip_install = true +usedevelop = false +commands = + python setup.py check --strict --metadata \ No newline at end of file