Chromium Code Reviews| Index: utils/docgen/CreateDocs.py |
| diff --git a/utils/docgen/CreateDocs.py b/utils/docgen/CreateDocs.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..e0a26e26a135404acd6345067ff39a71280cec47 |
| --- /dev/null |
| +++ b/utils/docgen/CreateDocs.py |
| @@ -0,0 +1,708 @@ |
| +#!/usr/bin/python |
| +# Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +""" Parse suite control files and make HTML documentation from included tests. |
| + |
| +This program will create a list of test cases found in suite files by parsing |
| +through each suite control file and making a list of all of the jobs called from |
| +it. Once it has a list of tests, it will parse the AutoTest control file for |
| +each test and grab the doc strings. These doc strings, along with any |
| +constraints in the suite control file, will be added to the original test |
| +script. These new scripts will be placed in a stand alone directory. Doxygen |
| +will then use these files for the sole purpose of producing HTML documentation |
| +for all of the tests. Once HTML docs are created some post processing will be |
| +done against the docs to change a few strings. |
| + |
| +If this script is executed without a --src argument, it will assume it is being |
| +executed from <ChromeOS>/src/third_party/autotest/files/utils/docgen/ directory. |
| + |
| +Classes: |
| + |
| + DocCreator |
| + This class is responsible for all processing. It requires the following: |
| + - Absolute path of suite control files. |
| + - Absolute path of where to place temporary files it constructs from the |
| + control files and test scripts. |
| + This class makes the following assumptions: |
| + - Each master suite has a README.txt file with general instructions on |
| + test preparation and usage. |
| + - The control file for each test has doc strings with labels of: |
| + - PURPOSE: one line description of why this test exists. |
| + - CRITERIA: Pass/Failure conditions. |
| + - DOC: additional test details. |
| + ReadNode |
| + This class parses a node from a control file into a key/value pair. In this |
| + context, a node represents a syntactic construct of an abstract syntax tree. |
| + The root of the tree is the module object (in this case a control file). If |
| + suite=True, it will assume the node is from a suite control file. |
| + |
| +Doxygen should already be configured with a configuration file called: |
| +doxygen.conf. This file should live in the same directory with this program. |
| +If you haven't installed doxygen, you'll need to install this program before |
| +this script is executed. This program will automatically update the doxygen.conf |
| +file to match self.src_tests and self.html. |
| + |
| +TODO: (kdlucas@google.com) Update ReadNode class to use the replacement module |
| +for the compiler module, as that has been deprecated. |
| +""" |
| + |
| +__author__ = 'kdlucas@google.com (Kelly Lucas)' |
| +__version__ = '0.8.0' |
| + |
| +import compiler |
| +import fileinput |
| +import glob |
| +import logging |
| +import optparse |
| +import os |
| +import re |
| +import shutil |
| +import subprocess |
| +import sys |
| + |
| + |
| +class DocCreator(object): |
| + """Process suite control files to combine docstrings and create HTML docs. |
| + |
| + The DocCreator class is designed to parse AutoTest suite control files to |
| + find all of the tests referenced, and build HTML documentation based on the |
| + docstrings in those files. It will cross reference the test control file |
| + and any parameters passed through the suite file, with the original test |
| + case. DocCreator relies on doxygen to actually generate the HTML documents. |
| + |
| + The workflow is as follows: |
| + - Parse the suite file(s) and generate a test list. |
| + - Locate the test source, and grab the docstrings from the associated |
| + AutoTest control file. |
| + - Combine the docstring from the control file with any parameters passed |
| + in from the suite control file, with the original test case. |
| + - Write a new test file with the combined docstrings to src_tests. |
| + - Create HTML documentation by running doxygen against the tests stored |
| + in self.src_tests. |
| + |
| + Implements the following methods: |
| + - SetLogger() - Gets a logger and sets the formatting. |
| + - GetTests() - Parse suite control files, create a dictionary of tests. |
| + - ParseControlFiles() - Runs through all tests and parses control files |
| + - _CleanDir() - Remove any files in a direcory and create an empty one. |
| + - _GetDoctString() - Parses docstrings and joins it with constraints. |
| + - _CreateTest() - Add docstrings and constraints to existing test script |
| + to form a new test script. |
| + - CreateMainPage() - Create a mainpage.txt file based on contents of the |
| + suite README file. |
| + - _ConfigDoxygen - Updates doxygen.conf to match some attributes this |
| + script was run with. |
| + - RunDoxygen() - Executes the doxygen program. |
| + - CleanDocs() - Changes some text in the HTML files to conform to our |
| + naming conventions and style. |
| + |
| + Depends upon class ReadNode. |
| + """ |
| + def __init__(self): |
| + """Parse command line arguments and set some initial variables.""" |
| + |
| + desc="""%prog will scan AutoTest suite control files to build a list of |
| + test cases called in the suite, and build HTML documentation based on |
| + the docstrings it finds in the tests, control files, and suite control |
| + files. |
| + """ |
| + |
| + self.runpath = os.path.abspath('.') |
| + src = os.path.join(self.runpath, '../../../../../') |
| + srcdir = os.path.abspath(src) |
| + |
| + parser = optparse.OptionParser(description=desc, |
| + prog='CreateDocs', |
| + version=__version__, |
| + usage='%prog') |
| + parser.add_option('--debug', |
| + help='Debug level [default: %default]', |
| + default='debug', |
| + dest='debug') |
| + parser.add_option('--docversion', |
| + help='Specify a version for the documentation' |
| + '[default: %default]', |
| + default=None, |
| + dest='docversion') |
| + parser.add_option('--doxy', |
| + help='doxygen configuration file [default: %default]', |
| + default='doxygen.conf', |
| + dest='doxyconf') |
| + parser.add_option('--html', |
| + help='path to store html docs [default: %default]', |
| + default='html', |
| + dest='html') |
| + parser.add_option('--latex', |
| + help='path to store latex docs [default: %default]', |
| + default='latex', |
| + dest='latex') |
| + parser.add_option('--layout', |
| + help='doxygen layout file [default: %default]', |
| + default='doxygenLayout.xml', |
| + dest='layout') |
| + parser.add_option('--log', |
| + help='Logfile for program output [default: %default]', |
| + default='docCreator.log', |
| + dest='logfile') |
| + parser.add_option('--readme', |
| + help='filename of suite documentation' |
| + '[default: %default]', |
| + default='README.txt', |
| + dest='readme') |
| + parser.add_option('--src', |
| + help='path to chromiumos source root' |
| + ' [default: %default]', |
| + default=srcdir, |
| + dest='src_chromeos') |
| + #TODO(kdlucas): add an all option that will parse all suites. |
| + parser.add_option('--suite', |
| + help='Directory name of suite [default: %default]', |
| + type='choice', |
| + default='suite_HWQual', |
| + choices = [ |
| + 'suite_Factory', |
| + 'suite_HWConfig', |
| + 'suite_HWQual', |
| + ], |
| + dest='suite') |
| + parser.add_option('--tests', |
| + help='Absolute path of temporary test files' |
| + ' [default: %default]', |
| + default='testsource', |
| + dest='src_tests') |
| + |
| + self.options, self.args = parser.parse_args() |
| + |
| + |
| + # Make parameters a little shorter by making the following assignments. |
| + self.debug = self.options.debug |
| + self.docversion = self.options.docversion |
| + self.doxyconf = self.options.doxyconf |
| + self.html = self.options.html |
| + self.latex = self.options.latex |
| + self.layout = self.options.layout |
| + self.logfile = self.options.logfile |
| + self.readme = self.options.readme |
| + self.src_tests = self.options.src_tests |
| + self.src = self.options.src_chromeos |
| + self.suite = self.options.suite |
| + |
| + autotest_path = 'third_party/autotest/files' |
| + sitetests = 'client/site_tests' |
| + tests = 'client/tests' |
| + self.testcase = {} |
| + |
| + self.site_dir = os.path.join(self.src, autotest_path, sitetests) |
| + self.test_dir = os.path.join(self.src, autotest_path, tests) |
| + self.suite_dir = os.path.join(self.site_dir, self.suite) |
| + |
| + self.logger = self.SetLogger('docCreator') |
| + self.logger.debug('Executing with debug level: %s', self.debug) |
| + self.logger.debug('Writing to logfile: %s', self.logfile) |
| + self.logger.debug('New test directory: %s', self.src_tests) |
| + self.logger.debug('Chrome OS src directory: %s', self.src) |
| + self.logger.debug('Test suite: %s', self.suite) |
| + |
| + self.suitename = {'suite_Factory': 'Factory Testing', |
| + 'suite_HWConfig': 'Hardware Configuration', |
| + 'suite_HWQual': 'Hardware Qualification', |
| + } |
| + |
| + def SetLogger(self, namespace): |
| + """Create a logger with some good formatting options. |
| + |
| + Args: |
| + namespace: string, name associated with this logger. |
| + Returns: |
| + Logger object. |
| + This method assumes self.logfile and self.debug are already set. |
| + This logger will write to stdout as well as a log file. |
| + """ |
| + |
| + loglevel = {'debug': logging.DEBUG, |
| + 'info': logging.INFO, |
| + 'warning': logging.WARNING, |
| + 'error': logging.ERROR, |
| + 'critical': logging.CRITICAL, |
| + } |
| + |
| + logger = logging.getLogger(namespace) |
| + c = logging.StreamHandler() |
| + h = logging.FileHandler(os.path.join(self.runpath, self.logfile)) |
| + hf = logging.Formatter( |
| + '%(asctime)s %(process)d %(levelname)s: %(message)s') |
| + cf = logging.Formatter('%(levelname)s: %(message)s') |
| + logger.addHandler(h) |
| + logger.addHandler(c) |
| + h.setFormatter(hf) |
| + c.setFormatter(cf) |
| + |
| + if self.debug in loglevel: |
| + logger.setLevel(loglevel.get(self.debug, logging.INFO)) |
|
petkov
2010/05/26 19:35:17
Remove if / else -- you don't need them any more.
|
| + else: |
| + logger.setLevel(logging.INFO) |
| + |
| + return logger |
| + |
| + |
| + def GetTests(self): |
| + """Create dictionary of tests based on suite control file contents.""" |
| + |
| + suite_search = os.path.join(self.suite_dir, 'control.*') |
| + for suitefile in glob.glob(suite_search): |
| + self.logger.debug('Scanning %s for tests', suitefile) |
| + try: |
| + suite = compiler.parseFile(suitefile) |
| + except SyntaxError, e: |
| + self.logger.error('Error parsing: %s\n%s', (suitefile, e)) |
| + raise SystemExit |
| + |
| + # Walk through each node found in the control file, which in our |
| + # case will be a call to a test. compiler.walk() will walk through |
| + # each component node, and call the appropriate function in class |
| + # ReadNode. The returned key should be a string, and the name of a |
| + # test. visitor.value should be any extra arguments found in the |
| + # suite file that are used with that test case. |
| + for n in suite.node.nodes: |
| + visitor = ReadNode(suite=True) |
| + compiler.walk(n, visitor) |
| + if len(visitor.key) > 1: |
| + self.logger.debug('Found test %s', visitor.key) |
| + filtered_input = '' |
| + # Lines in value should start with ' -' for bullet item. |
| + if visitor.value: |
| + lines = visitor.value.split('\n') |
| + for line in lines: |
| + if line.startswith(' -'): |
| + filtered_input += line + '\n' |
| + # A test could be called multiple times, so see if the key |
| + # already exists, and if so append the new value. |
| + if visitor.key in self.testcase: |
| + s = self.testcase[visitor.key] + filtered_input |
| + self.testcase[visitor.key] = s |
| + else: |
| + self.testcase[visitor.key] = filtered_input |
| + |
| + |
| + def _CleanDir(self, directory): |
| + """Ensure the directory is available and empty. |
| + |
| + Args: |
| + directory: string, path of directory |
| + """ |
| + |
| + if os.path.isdir(directory): |
| + try: |
| + shutil.rmtree(directory) |
| + except IOError, err: |
| + self.logger.error('Error cleaning %s\n%s', (directory, err)) |
| + try: |
| + os.makedirs(directory) |
| + except IOError, err: |
| + self.logger.error('Error creating %s\n%s', (directory, err)) |
| + self.logger.error('Check your permissions of %s', directory) |
| + raise SystemExit |
| + |
| + |
| + def ParseControlFiles(self): |
| + """Get docstrings from control files and add them to new test scripts. |
| + |
| + This method will cycle through all of the tests and attempt to find |
| + their control file. If found, it will parse the docstring from the |
| + control file, add this to any parameters found in the suite file, and |
| + add this combined docstring to the original test. These new tests will |
| + be written in the self.src_tests directory. |
| + """ |
| + # Clean some target directories. |
| + for d in [self.src_tests, self.html]: |
| + self._CleanDir(d) |
| + |
| + for test in self.testcase: |
| + testdir = os.path.join(self.site_dir, test) |
| + if not os.path.isdir(testdir): |
| + testdir = os.path.join(self.test_dir, test) |
| + |
| + if os.path.isdir(testdir): |
| + control_file = os.path.join(testdir, 'control') |
| + test_file = os.path.join(testdir, test + '.py') |
| + docstring = self._GetDocString(control_file, test) |
| + self._CreateTest(test_file, docstring, test) |
| + else: |
| + self.logger.warning('Cannot find test: %s', test) |
| + |
| + def _GetDocString(self, control_file, test): |
| + """Get the docstrings from control file and join to suite file params. |
| + |
| + Args: |
| + control_file: string, absolute path to test control file. |
| + test: string, name of test. |
| + Returns: |
| + string: combined docstring with needed markup language for doxygen. |
| + """ |
| + |
| + # Doxygen needs the @package marker. |
| + package_doc = '## @package ' |
| + # To allow doxygen to use special commands, we must use # for comments. |
| + comment = '# ' |
| + endlist = ' .\n' |
| + control_dict = {} |
| + output = [] |
| + temp = [] |
| + tempstring = '' |
| + docstring = '' |
| + keys = ['\\brief\n', '<H3>Pass/Fail Criteria:</H3>\n', |
| + '<H3>Author</H3>\n', '<H3>Test Duration</H3>\n', |
| + '<H3>Category</H3>\n', '<H3>Test Type</H3>\n', |
| + '<H3>Test Class</H3>\n', '<H3>Notest</H3>\n', |
| + ] |
| + |
| + try: |
| + control = compiler.parseFile(control_file) |
| + except SyntaxError, e: |
| + self.logger.error('Error parsing: %s\n%s', (control_file, e)) |
| + return None |
| + |
| + for n in control.node.nodes: |
| + visitor = ReadNode() |
| + compiler.walk(n, visitor) |
| + control_dict[visitor.key] = visitor.value |
| + |
| + for k in keys: |
| + if k in control_dict: |
| + if len(control_dict[k]) > 1: |
| + if k != test: |
| + temp.append(k) |
| + temp.append(control_dict[k]) |
| + if control_dict[k]: |
| + temp.append(endlist) |
| + # Add constraints and extra args after the Criteria section. |
| + if 'Criteria:' in k: |
| + if self.testcase[test]: |
| + temp.append('<H3>Arguments:</H3>\n') |
| + temp.append(self.testcase[test]) |
| + # '.' character at the same level as the '-' tells |
| + # doxygen this is the end of the list. |
| + temp.append(endlist) |
| + |
| + output.append(package_doc + test + '\n') |
| + tempstring = "".join(temp) |
| + lines = tempstring.split('\n') |
| + for line in lines: |
| + # Doxygen requires a '#' character to add special doxygen commands. |
| + comment_line = comment + line + '\n' |
| + output.append(comment_line) |
| + |
| + docstring = "".join(output) |
| + |
| + return docstring |
| + |
| + |
| + def _CreateTest(self, test_file, docstring, test): |
| + """Create a new test with the combined docstrings from multiple sources. |
| + |
| + Args: |
| + test_file: string, file name of new test to write. |
| + docstring: string, the docstring to add to the existing test. |
| + test: string, name of the test. |
| + |
| + This method is used to create a temporary copy of a new test, that will |
| + be a combination of the original test plus the docstrings from the |
| + control file, and any constraints from the suite control file. |
| + """ |
| + |
| + class_def = 'class ' + test |
| + pathname = os.path.join(self.src_tests, test + '.py') |
| + |
| + # Open the test and write out new test with added docstrings |
| + try: |
| + f = open(test_file, 'r') |
| + except IOError, err: |
| + self.logger.error('Error while reading %s\n%s', (test_file, err)) |
| + return |
| + lines = f.readlines() |
| + f.close() |
| + |
| + try: |
| + f = open(pathname, 'w') |
| + except IOError, err: |
| + self.logger.error('Error creating %s\n%s', (pathname, err)) |
| + return |
| + |
| + for line in lines: |
| + if class_def in line: |
| + f.write(docstring) |
| + f.write('\n') |
| + f.write(line) |
| + f.close() |
| + |
| + def CreateMainPage(self): |
| + """Create a main page to provide content for index.html. |
| + |
| + This method assumes a file named README.txt is located in your suite |
| + directory with general instructions on setting up and using the suite. |
| + If your README file is in another file, ensure you pass a --readme |
| + option with the correct filename. To produce a better looking |
| + landing page, use the '-' character for list items. This method assumes |
| + os commands start with '$'. |
| + """ |
| + |
| + # Define some strings that Doxygen uses for specific formatting. |
| + cstart = '/**' |
| + cend = '**/' |
| + mp = '@mainpage' |
| + section_begin = '@section ' |
| + vstart = '@verbatim ' |
| + vend = ' @endverbatim\n' |
| + |
| + # Define some characters we expect to delineate sections in the README. |
| + sec_char = '==========' |
| + command_prompt = '$ ' |
| + command_cont = '\\' |
| + |
| + command = False |
| + comment = False |
| + section = False |
| + sec_ctr = 0 |
| + |
| + readme_file = os.path.join(self.suite_dir, self.readme) |
| + mainpage_file = os.path.join(self.src_tests, 'mainpage.txt') |
| + |
| + try: |
| + f = open(readme_file, 'r') |
| + except IOError, err: |
| + self.logger.error('Error opening %s\n%s', (readme_file, err)) |
| + return |
| + try: |
| + fw = open(mainpage_file, 'w') |
| + except IOError, err: |
| + self.logger.error('Error opening %s\n%s', (mainpage_file, err)) |
| + return |
| + |
| + lines = f.readlines() |
| + f.close() |
| + |
| + fw.write(cstart) |
| + fw.write('\n') |
| + fw.write(mp) |
| + fw.write('\n') |
| + |
| + for line in lines: |
| + if sec_char in line: |
| + comment = True |
| + section = not section |
| + elif section: |
| + sec_ctr += 1 |
| + section_name = ' section%d ' % sec_ctr |
| + fw.write(section_begin + section_name + line) |
| + else: |
| + # comment is used to denote when we should start recording text |
| + # from the README file. Some of the initial text is not needed. |
| + if comment: |
| + if command_prompt in line: |
| + line = line.rstrip() |
| + if line[-1] == command_cont: |
| + fw.write(vstart + line[:-1]) |
| + command = True |
| + else: |
| + fw.write(vstart + line + vend) |
| + elif command: |
| + line = line.strip() |
| + if line[-1] == command_cont: |
| + fw.write(line) |
| + else: |
| + fw.write(line + vend) |
| + command = False |
| + else: |
| + fw.write(line) |
| + |
| + fw.write('\n') |
| + fw.write(cend) |
| + fw.close() |
| + |
| + def _ConfigDoxygen(self): |
| + """Set Doxygen configuration to match our options.""" |
| + |
| + doxy_config = { |
| + 'ALPHABETICAL_INDEX': 'YES', |
| + 'EXTRACT_ALL': 'YES', |
| + 'EXTRACT_LOCAL_METHODS': 'YES', |
| + 'EXTRACT_PRIVATE': 'YES', |
| + 'EXTRACT_STATIC': 'YES', |
| + 'FILE_PATTERNS': '*.py *.txt', |
| + 'FULL_PATH_NAMES ': 'YES', |
| + 'GENERATE_TREEVIEW': 'YES', |
| + 'HTML_DYNAMIC_SECTIONS': 'YES', |
| + 'HTML_FOOTER': 'footer.html', |
| + 'HTML_HEADER': 'header.html', |
| + 'HTML_OUTPUT ': self.html, |
| + 'INLINE_SOURCES': 'YES', |
| + 'INPUT ': self.src_tests, |
| + 'JAVADOC_AUTOBRIEF': 'YES', |
| + 'LATEX_OUTPUT ': self.latex, |
| + 'LAYOUT_FILE ': self.layout, |
| + 'OPTIMIZE_OUTPUT_JAVA': 'YES', |
| + 'PROJECT_NAME ': self.suitename[self.suite], |
| + 'PROJECT_NUMBER': self.docversion, |
| + 'SOURCE_BROWSER': 'YES', |
| + 'STRIP_CODE_COMMENTS': 'NO', |
| + 'TAB_SIZE': '4', |
| + 'USE_INLINE_TREES': 'YES', |
| + } |
| + |
| + doxy_layout = { |
| + 'tab type="mainpage"': 'title="%s"' % |
| + self.suitename[self.suite], |
| + 'tab type="namespaces"': 'title="Tests"', |
| + 'tab type="namespacemembers"': 'title="Test Functions"', |
| + } |
| + |
| + for line in fileinput.input(self.doxyconf, inplace=1): |
| + for k in doxy_config: |
| + if line.startswith(k): |
| + line = '%s = %s\n' % (k, doxy_config[k]) |
| + print line, |
| + |
| + for line in fileinput.input('header.html', inplace=1): |
| + if line.startswith('<H2>'): |
| + line = '<H2>%s</H2>\n' % self.suitename[self.suite] |
| + print line, |
| + |
| + for line in fileinput.input(self.layout, inplace=1): |
| + for k in doxy_layout: |
| + if line.find(k) != -1: |
| + line = line.replace('title=""', doxy_layout[k]) |
| + print line, |
| + |
| + |
| + def RunDoxygen(self, doxyargs): |
| + """Execute Doxygen on the files in the self.src_tests directory. |
| + |
| + Args: |
| + doxyargs: string, any command line args to be passed to doxygen. |
| + """ |
| + |
| + doxycmd = 'doxygen %s' % doxyargs |
| + |
| + p = subprocess.Popen(doxycmd, shell=True, stdout=subprocess.PIPE, |
| + stderr=subprocess.PIPE) |
| + p.wait() |
| + cmdoutput = p.stdout.read() |
| + |
| + if p.returncode: |
| + self.logger.error('Error while running %s', doxycmd) |
| + self.logger.error(cmdoutput) |
| + else: |
| + self.logger.info('%s successfully ran', doxycmd) |
| + |
| + |
| + def CreateDocs(self): |
| + """Configure and execute Doxygen to create HTML docuements.""" |
| + |
| + # First run doxygen with args to create default configuration files. |
| + # Create layout xml file. |
| + doxyargs = '-l %s' % self.layout |
| + self.RunDoxygen(doxyargs) |
| + |
| + # Create doxygen configuration file. |
| + doxyargs = '-g %s' % self.doxyconf |
| + self.RunDoxygen(doxyargs) |
| + |
| + # Edit the configuration files to match our options. |
| + self._ConfigDoxygen() |
| + |
| + # Run doxygen with configuration file as argument. |
| + self.RunDoxygen(self.doxyconf) |
| + |
| + |
| + def CleanDocs(self): |
| + """Run some post processing on the newly created docs.""" |
| + |
| + logo_image = 'customLogo.gif' |
| + |
| + # Key = original string, value = replacement string. |
| + replace = { |
| + '>Package': '>Test', |
| + } |
| + |
| + docpages = os.path.join(self.html, '*.html') |
| + files = glob.glob(docpages) |
| + for file in files: |
| + for line in fileinput.input(file, inplace=1): |
| + for k in replace: |
| + if line.find(k) != -1: |
| + line = line.replace(k, replace[k]) |
| + print line, |
| + |
| + shutil.copy(logo_image, self.html) |
| + |
| + self.logger.info('Sanitized documentation completed.') |
| + |
| + |
| +class ReadNode(object): |
| + """Parse a compiler node object from a control file. |
| + |
| + Args: |
| + suite: boolean, set to True if parsing nodes from a suite control file. |
| + """ |
| + |
| + def __init__(self, suite=False): |
| + self.key = '' |
| + self.value = '' |
| + self.testdef = False |
| + self.suite = suite |
| + self.bullet = ' - ' |
| + |
| + def visitName(self, n): |
| + if n.name == 'job': |
| + self.testdef = True |
| + |
| + def visitConst(self, n): |
| + if self.testdef: |
| + self.key = str(n.value) |
| + self.testdef = False |
| + else: |
| + self.value += str(n.value) + '\n' |
| + |
| + def visitKeyword(self, n): |
| + if n.name != 'constraints': |
| + self.value += self.bullet + n.name + ': ' |
| + for item in n.expr: |
| + if isinstance(item, compiler.ast.Const): |
| + for i in item: |
| + self.value += self.bullet + str(i) + '\n' |
| + self.value += ' .\n' |
| + else: |
| + self.value += str(item) + '\n' |
| + |
| + |
| + def visitAssName(self, n): |
| + # To remove section from appearing in the documentation, set value = ''. |
| + sections = { |
| + 'AUTHOR': '', |
| + 'CRITERIA': '<H3>Pass/Fail Criteria:</H3>\n', |
| + 'DOC': '<H3>Notes</H3>\n', |
| + 'NAME': '', |
| + 'PURPOSE': '\\brief\n', |
| + 'TIME': '<H3>Test Duration</H3>\n', |
| + 'TEST_CATEGORY': '<H3>Category</H3>\n', |
| + 'TEST_CLASS': '<H3>Test Class</H3>\n', |
| + 'TEST_TYPE': '<H3>Test Type</H3>\n', |
| + } |
| + |
| + if not self.suite: |
| + self.key = sections.get(n.name, n.name) |
| + |
| + |
| +def main(): |
| + doc = DocCreator() |
| + doc.GetTests() |
| + doc.ParseControlFiles() |
| + doc.CreateMainPage() |
| + doc.CreateDocs() |
| + doc.CleanDocs() |
| + |
| + |
| +if __name__ == '__main__': |
| + main() |