def testAddParam(self): root = pyhit.load('test.hit') self.assertEqual(len(root(1)), 2) self.assertIsNone(root(1).get('year')) root(1)['year'] = 1980 self.assertEqual(len(root(1)), 2) self.assertEqual(root(1).get('year'), 1980)
def test(self): # MOOSEDOCS:example-begin # Load the packages import pyhit import moosetree # Read the file root = pyhit.load('input.i') # Locate and modify "x_max" parameter for the mesh mesh = moosetree.find(root, func=lambda n: n.fullpath == '/Mesh/gen') mesh["x_max"] = 4 # Set the comment on altered parameter mesh.setComment("x_max", "Changed from 3 to 4") # Write the modified file pyhit.write("input_modified.i", root) # MOOSEDOCS:example-end self.assertEqual(mesh["x_max"], 4) self.assertEqual(mesh.comment("x_max"), "Changed from 3 to 4") out = mesh.render() self.assertIn("x_max = 4", out) self.assertIn("Changed from 3 to 4", out)
def _add_requirements(out, location, filename): """ Opens tests specification and extracts requirement items. """ root = pyhit.load(filename) design = root.children[0].get('design', None) design_line = root.children[0].line('design', None) issues = root.children[0].get('issues', None) issues_line = root.children[0].line('issues', None) deprecated = root.children[0].get('deprecated', False) deprecated_line = root.children[0].line('deprecated', None) group = os.path.relpath(filename, location).split('/')[0] path = os.path.relpath(os.path.dirname(filename), location) for child in root.children[0]: req = _create_requirement(child, path, filename, design, design_line, issues, issues_line, deprecated, deprecated_line) out[group].append(req) # Get "detail" parameter from nested tests for grandchild in child.children: detail = _create_requirement(grandchild, path, filename, None, None, None, None, None, None) req.details.append(detail)
def check(self, location): # List of errors messages = [] # Load the test spec and create a list of PythonUnitTest files tested = set() spec = os.path.join(location, 'tests') if not os.path.exists(spec): if glob.glob(os.path.join(spec, '*.py')): messages.append("Missing a test spec file in '{}'".format(os.path.dirname(spec))) else: node = pyhit.load(os.path.join(location, 'tests')) for block in moosetree.find(node, lambda n: n.name=='Tests'): if block['type'] == 'PythonUnitTest': tested.add(block['input']) # Loop through python files in this directory for filename in glob.glob(os.path.join(location, '*.py')): # Local filename base = os.path.basename(filename) # Load the module (tried this with os.chdir, but that didn't work) sys.path.append(location) mod = __import__(base[:-3]) sys.path.remove(location) # Get a lit of unittest.TestCase objects, if they exist this file should be in spec tests = get_parent_objects(mod, unittest.TestCase) if tests and (base not in tested): msg = "The test script '{}' is not included in the tests spec '{}'." messages.append(msg.format(base, spec)) return messages
def sqa_check_requirement_duplicates( working_dir=os.getcwd(), specs=['tests'], skip=[]): """Check that no duplicate requirements exist.""" import pyhit requirements = collections.defaultdict(list) for root, dirs, files in os.walk(working_dir): for fname in files: filename = os.path.join(root, fname) if fname in specs and not any(s in filename for s in skip): node = pyhit.load(filename) for child in node.children[0]: req = child.get('requirement', None) if req is not None: requirements[req.strip()].append( (filename, child.fullpath, child.line('requirement'))) count = 0 for key, value in requirements.items(): if len(value) > 1: if count == 0: print(colorText('Duplicate Requirements Found:\n', 'YELLOW')) count += 1 if len(key) > 80: print(colorText('{}...'.format(key[:80]), 'YELLOW')) for filename, path, line in value: print(' {}:{}'.format(filename, line)) return count
def testAddParam(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(len(root(1)), 2) self.assertIsNone(root(1).get('year')) root(1)['year'] = 1980 self.assertEqual(len(root(1)), 2) self.assertEqual(root(1).get('year'), 1980)
def testAppend(self): root = pyhit.load(os.path.join('test_files', 'test.hit')) self.assertEqual(len(root(1)), 2) sec = root(1).append('B-3') self.assertEqual(len(root(1)), 3) self.assertIs(root(1)(2), sec) self.assertIsNone(sec.get('year')) sec['year'] = 1980 self.assertEqual(sec.get('year'), 1980)
def testInsert(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(len(root(1)), 2) sec = root(1).insert(0, 'B-3') self.assertEqual(len(root(1)), 3) self.assertIs(root(1)(0), sec) self.assertIsNone(sec.get('year')) sec['year'] = 1980 self.assertEqual(sec.get('year'), 1980)
def testSetComment(self): root = pyhit.load('test.hit') root(1).setComment('update section comment') self.assertEqual(root(1).comment(), "update section comment") root(0, 0).setComment('update sub-section comment') self.assertEqual(root(0, 0).comment(), "update sub-section comment") root(1, 0, 0).setComment('type', 'update param comment') self.assertEqual(root(1, 0, 0).comment('type'), "update param comment")
def testSetComment(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) root(1).setComment('update section comment') self.assertEqual(root(1).comment(), "update section comment") root(0, 0).setComment('update sub-section comment') self.assertEqual(root(0, 0).comment(), "update sub-section comment") root(1, 0, 0).setComment('type', 'update param comment') self.assertEqual(root(1, 0, 0).comment('type'), "update param comment")
def check_requirement(filename): """Check spec file for requirement documentation.""" import pyhit messages = [] root = pyhit.load(filename) design = root.children[0].get('design', '') issues = root.children[0].get('issues', '') deprecated = root.children[0].get('deprecated', False) for child in root.children[0]: if child.get('deprecated', deprecated): continue if 'requirement' not in child: messages.append( " 'requirement' parameter is missing or empty in '{}' block." .format(child.name)) if not child.get('design', design).strip(): messages.append( " 'design' parameter is missing or empty in '{}' block.". format(child.name)) if not child.get('issues', issues).strip(): messages.append( " 'issues' parameter is missing or empty in '{}' block.". format(child.name)) for grandchild in child.children: if 'detail' not in grandchild: messages.append( " 'detail' parameter is missing or empty in '{}' block." .format(grandchild.name)) if 'requirement' in grandchild: messages.append( " 'requirement' parameter in block '{}' must not be used within a group, use 'detail' instead." .format(grandchild.name)) if 'design' in grandchild: messages.append( " 'design' parameter in block '{}' must not be used within a group." .format(grandchild.name)) if 'issues' in grandchild: messages.append( " 'issues' parameter in block '{}' must not be used within a group." .format(grandchild.name)) if messages: print('ERROR in {}'.format(filename)) print('\n'.join(messages) + '\n') return 1 return 0
def extractInputBlocks(filename, blocks): """Read input file block(s)""" hit = pyhit.load(filename) out = [] for block in blocks.split(): node = moosetree.find(hit, lambda n: n.fullpath.endswith(block.strip('/'))) if node is None: msg = "Unable to find block '{}' in {}." raise exceptions.MooseDocsException(msg, block, filename) out.append(str(node.render())) return pyhit.parse('\n'.join(out)) if out else hit
def testAddComment(self): root = pyhit.load('test.hit') root(0).setComment('Section A') self.assertEqual(root(0).comment(), "Section A") root(1, 0).setComment('Section B-1') self.assertEqual(root(1, 0).comment(), "Section B-1") root(0, 0).setComment('param', "inline comment") self.assertEqual(root(0, 0).comment('param'), "inline comment")
def testAddComment(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) root(0).setComment('Section A') self.assertEqual(root(0).comment(), "Section A") root(1, 0).setComment('Section B-1') self.assertEqual(root(1, 0).comment(), "Section B-1") root(0, 0).setComment('param', "inline comment") self.assertEqual(root(0, 0).comment('param'), "inline comment")
def testRemoveComment(self): root = pyhit.load('test.hit') self.assertIn("type = test # param comment", root.render()) self.assertIn("# section comment", root.render()) root(1, 0, 0).setComment("type", None) self.assertIsNone(root(1, 0, 0).comment()) self.assertNotIn("type = test # param comment", root.render()) root(1).setComment(None) self.assertIsNone(root(1).comment()) self.assertNotIn("# section comment", root.render())
def get_requirements_from_file(filename, prefix=None, include_non_testable=False): """ Opens hit file and extracts requirement items. Input: filename[str]: The HIT file to open and extract Requirements Returns: A list of Requirement objects. """ if not os.path.isfile(filename): raise FileNotFoundError( "The supplied filename does not exist: {}".format(filename)) requirements = list() root = pyhit.load(filename) # Options available at the top-level # [Tests] # design = 'foo.md bar.md' # issues = '#12345 ab23bd34' design = root.children[0].get('design', None) design_line = root.children[0].line('design', None) issues = root.children[0].get('issues', None) issues_line = root.children[0].line('issues', None) deprecated = root.children[0].get('deprecated', False) deprecated_line = root.children[0].line('deprecated', None) collections = root.children[0].get('collections', None) collections_line = root.children[0].line('collections', None) for child in root.children[0]: req = _create_requirement(child, filename, design, design_line, issues, issues_line, collections, collections_line, deprecated, deprecated_line) req.prefix = prefix # Get "detail" parameter from nested tests for grandchild in child.children: detail = _create_detail(grandchild, filename) detail.specification = _create_specification( grandchild, '{}/{}'.format(child.name, grandchild.name), filename) req.details.append(detail) if not req.details: req.specification = _create_specification(child, child.name, filename) if req.testable or include_non_testable: requirements.append(req) return requirements
def parse(self, filename, default_values=None): self.fname = os.path.abspath(filename) try: root = pyhit.load(self.fname) except Exception as err: self.error(err) return self.root = root(0) # make the [Tests] block the root self.check() self._parseNode(filename, self.root, default_values)
def _setParallel(self): """ Read the test spec file and determine if parallel_scheduling is set. """ if self.__parallel_scheduling is not None: return self.__parallel_scheduling self.__parallel_scheduling = False job = self.getJob() if job: # We only need a single tester so we know what spec file to load. # TODO: would be nice to have access to this without needing tester.specs tester = job[0].getTester() root = pyhit.load( os.path.join(tester.specs['test_dir'], tester.specs['spec_file'])) self.__parallel_scheduling = root.children[0].get( 'parallel_scheduling', False) return self.__parallel_scheduling
def testBasic(self): root = pyhit.load(os.path.join('test_files', 'test.hit')) self.assertEqual(root.children[0].name, 'A') self.assertEqual(root.children[0]['param'], 'foo') self.assertEqual(root.children[0].children[0].name, 'A-1') self.assertIn('param', root.children[0].children[0]) self.assertEqual(root.children[0].children[0]['param'], 'bar') self.assertEqual(root.children[1].name, 'B') self.assertEqual(root.children[1].children[0].name, 'B-1') self.assertEqual(root.children[1].children[0].children[0].name, 'B-1-1') self.assertIn('type', root.children[1].children[0].children[0]) self.assertEqual(root.children[1].children[0].children[0]['type'], 'test') self.assertEqual(root.children[1].children[1].name, 'B-2') gold = ['A', 'B'] for i, child in enumerate(root): self.assertEqual(child.name, gold[i])
def get_test_specification(filename, block): """ Create a TestSpecification object from the HIT file and block name. Input: filename[str]: Complete filename of a HIT file containing test specification(s) block[str]: The name of the block to use for creating the TestSpecification object This function exists to allow for requirements to be defined outside of the test specifications, but still reference tests for the purpose of SQA traceability. Support for this was added to allow for non-functional requirements to be defined outside of the test specifications. """ root = pyhit.load(filename) # Locate the desired block node = moosetree.find(root, lambda n: n.fullpath.endswith(block)) if node is None: raise KeyError("Unable to locate '{}' in {}".format(block, filename)) # Build/return TestSpecification object name = node.name if node.parent.parent.is_root else '{}/{}'.format(node.parent.name, node.name) return _create_specification(node, name, filename, mooseutils.git_root_dir(os.path.dirname(filename)))
def _add_requirements(out, location, filename): """ Opens tests specification and extracts requirement items. """ root = pyhit.load(filename) # Options available at the top-level # [Tests] # design = 'foo.md bar.md' # issues = '#12345 ab23bd34' design = root.children[0].get('design', None) design_line = root.children[0].line('design', None) issues = root.children[0].get('issues', None) issues_line = root.children[0].line('issues', None) deprecated = root.children[0].get('deprecated', False) deprecated_line = root.children[0].line('deprecated', None) collections = root.children[0].get('collections', None) collections_line = root.children[0].line('collections', None) group = os.path.relpath(filename, location).split('/')[0] path = os.path.relpath(os.path.dirname(filename), location) for child in root.children[0]: req = _create_requirement(child, path, filename, design, design_line, issues, issues_line, collections, collections_line, deprecated, deprecated_line) out[group].append(req) # Get "detail" parameter from nested tests for grandchild in child.children: detail = _create_detail(grandchild, path, filename) detail.specification = _create_specification(grandchild, '{}/{}'.format(child.name, grandchild.name), path, filename) req.details.append(detail) if not req.details: req.specification = _create_specification(child, child.name, path, filename)
def testTestRoot(self): root = pyhit.load(os.path.join('..', '..', 'testroot')) self.assertIn('app_name', root) self.assertEqual(root['app_name'], 'moose_python')
def testAddSectionWithParameters(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(len(root(1)), 2) sec = root(1).append('B-3', year=1980) self.assertEqual(len(root(1)), 3) self.assertEqual(sec.get('year'), 1980)
def testComment(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(root(1).comment(), "section comment") self.assertEqual(root(0, 0).comment(), "sub-section comment") self.assertEqual(root(1, 0, 0).comment('type'), "param comment")
def testIterParam(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) for k, v in root.children[0].params(): self.assertEqual(k, 'param') self.assertEqual(v, 'foo')
def testGetParam(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) p = root.get('nope', 'default') self.assertEqual(p, 'default')
def _addRequirement(self, parent, info, page, req, requirements, category): reqname = "{}:{}".format(req.path, req.name) if req.path != '.' else req.name item = SQARequirementMatrixItem(parent, label=req.label, reqname=reqname, satisfied=req.satisfied) text = SQARequirementText(item) self.reader.tokenize(text, req.text, page, MarkdownReader.INLINE, info.line, report=False) for token in moosetree.iterate(item): if token.name == 'ErrorToken': msg = common.report_error("Failed to tokenize SQA requirement.", req.filename, req.text_line, req.text, token['traceback'], 'SQA TOKENIZE ERROR') LOG.critical(msg) if req.details: details = SQARequirementDetails(item) for detail in req.details: ditem = SQARequirementDetailItem(details) text = SQARequirementText(ditem) self.reader.tokenize(text, detail.text, page, MarkdownReader.INLINE, info.line, \ report=False) if self.settings['link']: if self.settings['link-spec']: p = SQARequirementSpecification(item, spec_path=req.path, spec_name=req.name) hit_root = pyhit.load(req.filename) h = moosetree.find(hit_root, lambda n: n.name==req.name) content = h.render() floats.create_modal_link(p, title=reqname, string=reqname, content=core.Code(None, language='text', content=content)) if self.settings['link-design'] and req.design: p = SQARequirementDesign(item, filename=req.filename, design=req.design, line=req.design_line) if self.settings['link-issues'] and req.issues: p = SQARequirementIssues(item, filename=req.filename, issues=req.issues, line=req.issues_line, url=self.extension.remote(category)) if self.settings.get('link-prerequisites', False) and req.prerequisites: labels = [] for prereq in req.prerequisites: for other in requirements: if (other.name == prereq) and (other.path == req.path): labels.append((other.path, other.name, other.label)) for detail in other.details: if (detail.name == prereq) and (detail.path == req.path): labels.append((other.path, other.name, other.label)) SQARequirementPrequisites(item, specs=labels) if self.settings.get('link-results', False): keys = list() for detail in req.details: keys.append('{}.{}/{}'.format(req.path, req.name, detail.name)) if not keys: keys.append('{}.{}'.format(req.path, req.name)) if self.extension.hasCivetExtension(): civet.CivetTestBadges(item, tests=keys)
def testRemoveParam(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(root(0)['param'], 'foo') root(0).removeParam('param') self.assertIsNone(root(0).get('param'))
def _add_requirements(out, location, filename): """Opens tests specification and extracts requirement items.""" root = pyhit.load(filename) design = root.children[0].get('design', None) design_line = root.children[0].line('design', None) issues = root.children[0].get('issues', None) issues_line = root.children[0].line('issues', None) deprecated = root.children[0].get('deprecated', False) deprecated_line = root.children[0].line('deprecated', None) for child in root.children[0]: if 'requirement' in child: requirement_line = child.line('requirement') # Deprecation local_deprecated = child.get('deprecated', deprecated) local_deprecated_line = child.line('deprecated', deprecated_line) if local_deprecated: msg = "%s:%s\nThe 'requirement' parameter is specified for %s, but the test is " \ "marked as deprecated on line %s." LOG.error(msg, filename, requirement_line, child.name, local_deprecated_line) continue # Deprecation local_deprecated = child.get('deprecated', deprecated) local_deprecated_line = child.line('deprecated', deprecated_line) if local_deprecated: msg = "The 'requirment' parameter is specified for %s, but the test is marked as " \ "deprecated on line %s." LOG.error(msg, child.name, local_deprecated_line) continue local_design = child.get('design', design) local_design_line = child.line('design', design_line) if local_design is None: msg = "The 'design' parameter is missing from '%s' in %s. It must be defined at " \ "the top level and/or within the individual test specification. It " \ "should contain a space separated list of filenames." LOG.error(msg, child.name, filename) local_design = '' local_issues = child.get('issues', issues) local_issues_line = child.line('issues', issues_line) if local_issues is None: msg = "The 'issues' parameter is missing from '%s' in %s. It must be defined at " \ "the top level and/or within the individual test specification. It " \ "should contain a space separated list of issue numbers (include the #) or " \ "a git commit SHA." LOG.error(msg, child.name, filename) local_issues = '' text = child['requirement'] if 'MOOSE_TEST_NAME' in text: idx = filename.index('/tests/') name = os.path.join(os.path.dirname(filename[idx + 7:]), child.name) text = text.replace('MOOSE_TEST_NAME', name) satisfied = False if (child['skip'] or child['deleted']) else True req = Requirement(name=child.name, path=os.path.relpath(os.path.dirname(filename), location), filename=filename, text=str(text), text_line=child.line('requirement', None), design=local_design.split(), design_line=local_design_line, issues=local_issues.split(), issues_line=local_issues_line, satisfied=satisfied) req.verification = child.get('verification', None) req.validation = child.get('validation', None) group = os.path.relpath(filename, location).split('/')[0] prereq = child.get('prereq', None) if prereq is not None: req.prerequisites = set(prereq.split(' ')) for grandchild in child.children: detail = grandchild.get('detail', None) if detail is None: msg = "The 'detail' parameters is missing from '%s' in %s. It must be defined "\ "for all sub-blocks within a test group." LOG.error(msg, grandchild.name, filename) _check_extra_param(grandchild, 'requirement', filename) _check_extra_param(grandchild, 'issues', filename) _check_extra_param(grandchild, 'design', filename) req.details.append( Detail(name=grandchild.name, path=req.path, filename=filename, text=str(detail), text_line=grandchild.line('detail'))) out[group].append(req)
def testRender(self): root = pyhit.load(os.path.join('..', '..', 'test_files', 'test.hit')) out = root.render() self.assertIn('[A]', out) self.assertIn('param = bar', out) self.assertIn('comment', out)