def get_requirements(): """ Extracts the requirements from the moose/test/tests directory. This is only a temporary solution to a larger effort. """ directories = [os.path.join(MooseDocs.ROOT_DIR, 'test', 'tests')] spec = 'tests' out = set() for location in directories: for base, _, files in os.walk(location): for fname in files: if fname == spec: full_file = os.path.join(base, fname) root = mooseutils.hit_load(full_file) for child in root.children[0]: if 'requirement' in child: design = child['design'] if 'design' in child else None issues = child['issues'] if 'issues' in child else None req = Requirement(name=child.name, path=os.path.relpath(full_file, MooseDocs.ROOT_DIR), filename=full_file, requirement=child['requirement'], design=design, issues=issues) out.add(req) return out
def testAddSectionWithParameters(self): root = mooseutils.hit_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 _add_requirements(out, location, filename): """Opens tests specification and extracts requirement items.""" root = mooseutils.hit_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) for child in root.children[0]: if 'requirement' in child: 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=unicode(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', False) req.validation = child.get('validation', False) group = os.path.relpath(filename, location).split('/')[0] prereq = child.get('prereq', None) if prereq is not None: req.prerequisites = set(prereq.split(' ')) out[group].append(req)
def _add_requirements(out, location, filename): """Opens tests specification and extracts requirement items.""" root = mooseutils.hit_load(filename) design = root.children[0].get('design', None) issues = root.children[0].get('issues', None) for child in root.children[0]: if 'requirement' in child: local_design = child.get('design', design) 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) 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 #)." LOG.error(msg, child.name, filename) local_issues = '' req = Requirement(name=child.name, path=os.path.relpath(os.path.dirname(filename), location), filename=filename, text=unicode(child['requirement']), design=local_design.split(), issues=local_issues.split()) group = os.path.relpath(filename, location).split('/')[0] out[group].append(req)
def testRender(self): root = mooseutils.hit_load( os.path.join('..', '..', 'test_files', 'test.hit')) out = root.render() self.assertIn('[A]', out) self.assertIn('param = bar', out) self.assertIn('comment', out)
def _get_requirements(): """ Helper for examining test specification for "requirements." TODO: This should be updated to accept an arbitrary directories and re-factored a bit to avoid the six levels of nesting. """ directories = [os.path.join(MooseDocs.ROOT_DIR, 'test', 'tests')] spec = 'tests' out = set() for location in directories: for base, _, files in os.walk(location): for fname in files: if fname == spec: full_file = os.path.join(base, fname) root = mooseutils.hit_load(full_file) for child in root.children[0]: #TODO: Make 'issues' optional? if ('requirement' in child) and ( 'design' in child) and ('issues' in child): req = Requirement(name=child.name, path=os.path.relpath( base, location), filename=full_file, requirement=child['requirement'], design=child['design'], issues=child['issues']) out.add(req) return out
def check_requirement(filename): """Check spec file for requirement documentation.""" messages = [] root = mooseutils.hit_load(filename) design = root.children[0].get('design', None) issues = root.children[0].get('issues', None) for child in root.children[0]: if 'requirement' not in child: messages.append( " 'requirement' parameter is missing in '{}' block.".format( child.name)) if child.get('design', design) is None: messages.append( " 'design' parameter is missing in '{}' block.".format( child.name)) if child.get('issues', issues) is None: messages.append( " 'issues' parameter is missing in '{}' block.".format( child.name)) if messages: print 'ERROR in {}'.format(filename) print '\n'.join(messages) + '\n' return 1 return 0
def testAddParam(self): root = mooseutils.hit_load( os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(len(root(1)), 2) self.assertIsNone(root(1).get('year')) root(1).addParam('year', 1980) self.assertEqual(len(root(1)), 2) self.assertEqual(root(1).get('year'), 1980)
def testAddSection(self): root = mooseutils.hit_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.assertIsNone(sec.get('year')) sec.addParam('year', 1980) self.assertEqual(sec.get('year'), 1980)
def _addRequirement(self, parent, info, page, req, requirements): 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, MooseDocs.INLINE, info.line, report=False) for token in anytree.PreOrderIter(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, MooseDocs.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 = mooseutils.hit_load(req.filename) h = hit_root.find(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) 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)
def extractInputBlocks(filename, blocks): hit = mooseutils.hit_load(filename) out = [] for block in blocks.split(' '): node = hit.find(block) if node is None: msg = "Unable to find block '{}' in {}." raise exceptions.TokenizeException(msg, block, filename) out.append(unicode(node.render())) return '\n'.join(out)
def extractInputBlocks(filename, blocks): """Remove input file block(s)""" hit = mooseutils.hit_load(filename) out = [] for block in blocks.split(' '): node = hit.find(block) if node is None: msg = "Unable to find block '{}' in {}." raise exceptions.MooseDocsException(msg, block, filename) out.append(unicode(node.render())) return '\n'.join(out)
def extractInputBlocks(filename, blocks): """Remove input file block(s)""" hit = mooseutils.hit_load(filename) out = [] for block in blocks.split(' '): node = hit.find(block) if node is None: msg = "Unable to find block '{}' in {}." raise exceptions.MooseDocsException(msg, block, filename) out.append(str(node.render())) return '\n'.join(out)
def testFind(self): root = mooseutils.hit_load(os.path.join('..', '..', 'test_files', 'test.hit')) self.assertIs(root.find('A'), root.children[0]) self.assertEqual(root.findall('A'), [root.children[0], root.children[0].children[0]]) self.assertEqual(root.findall('-1'), [root.children[0].children[0], root.children[1].children[0], root.children[1].children[0].children[0]]) self.assertEqual(root.children[1].findall('-1'), [root.children[1].children[0], root.children[1].children[0].children[0]])
def _add_requirements(out, location, filename): """Opens tests specification and extracts requirement items.""" root = mooseutils.hit_load(filename) design = root.children[0].get('design', None) issues = root.children[0].get('issues', None) for child in root.children[0]: if 'requirement' in child: local_design = child.get('design', design) 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) 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=unicode(text), design=local_design.split(), issues=local_issues.split(), satisfied=satisfied) req.verification = child.get('verification', False) req.validation = child.get('validation', False) group = os.path.relpath(filename, location).split('/')[0] prereq = child.get('prereq', None) if prereq is not None: req.prerequisites = set(prereq.split(' ')) out[group].append(req)
def testBasic(self): root = mooseutils.hit_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 check_requirement(filename): """Check spec file for requirement documentation.""" messages = [] root = mooseutils.hit_load(filename) design = root.children[0].get('design', None) issues = root.children[0].get('issues', None) for child in root.children[0]: if 'requirement' not in child: messages.append(" 'requirement' parameter is missing in '{}' block.".format(child.name)) if child.get('design', design) is None: messages.append(" 'design' parameter is missing in '{}' block.".format(child.name)) if child.get('issues', issues) is None: messages.append(" 'issues' parameter is missing in '{}' block.".format(child.name)) if messages: print 'ERROR in {}'.format(filename) print '\n'.join(messages) + '\n' return 1 return 0
def report_requirement_stats(location, specs): """ Report requirement statistics for the test spec files with the supplied location. """ requirements = 0 tests = 0 for filename in mooseutils.git_ls_files(location): if not os.path.isfile(filename): continue fname = os.path.basename(filename) if fname in specs: root = mooseutils.hit_load(filename) for child in root.children[0]: tests += 1 if child.get('requirement', None): requirements += 1 complete = float(requirements)/float(tests) print 'Requirement Definitions ({:2.1f}% complete):'.format(complete*100) print ' Location: {}'.format(location) print ' Specs: {}'.format(' '.join(specs)) print ' Total Number of Tests: {}'.format(tests) print ' Tests with Requirements: {}'.format(requirements)
def report_requirement_stats(location, specs): """ Report requirement statistics for the test spec files with the supplied location. """ requirements = 0 tests = 0 for filename in mooseutils.git_ls_files(location): if not os.path.isfile(filename): continue fname = os.path.basename(filename) if fname in specs: root = mooseutils.hit_load(filename) for child in root.children[0]: tests += 1 if child.get('requirement', None): requirements += 1 complete = float(requirements) / float(tests) print 'Requirement Definitions ({:2.1f}% complete):'.format(complete * 100) print ' Location: {}'.format(location) print ' Specs: {}'.format(' '.join(specs)) print ' Total Number of Tests: {}'.format(tests) print ' Tests with Requirements: {}'.format(requirements)
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 = mooseutils.hit_load(os.path.join(location, 'tests')) for block in node.find('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 = testing.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 testIterParam(self): root = mooseutils.hit_load(os.path.join('..', '..', 'test_files', 'test.hit')) for k, v in root.children[0].iterparams(): self.assertEqual(k, 'param') self.assertEqual(v, 'foo')
def getGetParam(self): root = mooseutils.hit_load( os.path.join('..', '..', 'test_files', 'test.hit')) p = root.get('nope', 'default') self.assertEqual(p, 'default')
def testIterParam(self): root = mooseutils.hit_load( os.path.join('..', '..', 'test_files', 'test.hit')) for k, v in root.children[0].iterparams(): self.assertEqual(k, 'param') self.assertEqual(v, 'foo')
def testRemoveParam(self): root = mooseutils.hit_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 = mooseutils.hit_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 app_syntax(exe, remove=None, allow_test_objects=False, hide=None, alias=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. """ common.check_type('exe', exe, str) common.check_type('remove', remove, (type(None), dict, list, set)) common.check_type('hide', hide, (type(None), dict, list, set)) common.check_type('allow_test_objects', allow_test_objects, bool) try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) raw = mooseutils.runExe(exe, ['--registry-hit']) raw = raw.split('### START REGISTRY DATA ###\n')[1] raw = raw.split('### END REGISTRY DATA ###')[0] reg = mooseutils.hit_load(raw) except Exception as e: #pylint: disable=broad-except LOG.error("Failed to execute the MOOSE executable '%s':\n%s", exe, e.message) sys.exit(1) root = SyntaxNode(None, '') for key, value in tree['blocks'].iteritems(): node = SyntaxNode(root, key) __syntax_tree_helper(node, value) hidden = set() if isinstance(hide, dict): for value in hide.itervalues(): hidden.update(value) elif isinstance(hide, (list, set)): hidden.update(hide) if hidden: for node in anytree.PreOrderIter(root): if node.fullpath in hidden: node.hidden = True #TODO: When the new registration methods are added to the --json dump, this will not be needed. # Add groups from --registry-hit output object_groups = collections.defaultdict(set) action_groups = collections.defaultdict(set) for node in reg.children[0].children[0]: object_groups[node['name']].add(node['label'].replace('App', '')) for node in reg.children[0].children[1]: action_groups[node['name']].add(node['label'].replace('App', '')) action_groups[node['class']].add(node['label'].replace('App', '')) for node in anytree.PreOrderIter(root): if isinstance(node, MooseObjectNode): node._groups.update(object_groups[node.name]) #pylint: disable=protected-access elif isinstance(node, ActionNode): node._groups.update(action_groups[node.name]) #pylint: disable=protected-access for task in node.tasks: node._groups.update(action_groups[task]) #pylint: disable=protected-access # Remove removed = set() if isinstance(remove, dict): for value in remove.itervalues(): removed.update(value) elif isinstance(remove, (list, set)): removed.update(remove) if removed: for node in anytree.PreOrderIter(root): if any(n.fullpath == prefix for n in node.path for prefix in removed): node.removed = True if not allow_test_objects: for node in anytree.PreOrderIter(root): if all([group.endswith('Test') for group in node.groups]): node.removed = True # Alias if alias: for node in anytree.PreOrderIter(root): for k, v in alias.iteritems(): if node.fullpath == k: node.alias = unicode(v) return root
def testRender(self): root = mooseutils.hit_load(os.path.join('..', '..', 'test_files', 'test.hit')) out = root.render() self.assertIn('[A]', out) self.assertIn('param = bar', out) self.assertIn('comment', out)
def getGetParam(self): root = mooseutils.hit_load(os.path.join('..', '..', 'test_files', 'test.hit')) p = root.get('nope', 'default') self.assertEqual(p, 'default')
def testRemoveSection(self): root = mooseutils.hit_load( os.path.join('..', '..', 'test_files', 'test.hit')) self.assertEqual(len(root), 2) root(1).remove() self.assertEqual(len(root), 1)