Exemplo n.º 1
0
 def test_import_relative(self):
     """Tests if relative imports are tracked on the module object."""
     path = os.path.join(BASEDIR, 'selftests', 'functional', 'test_basic.py')
     module = PythonModule(path)
     for _ in module.iter_classes():
         pass
     self.assertIn('TestCaseTmpDir', module.imported_symbols)
Exemplo n.º 2
0
 def test_is_avocado_test(self):
     passtest_path = os.path.join(BASEDIR, 'examples', 'tests', 'passtest.py')
     passtest_module = PythonModule(passtest_path)
     classes = [klass for klass in passtest_module.iter_classes()]
     # there's only one class and one *worthy* Test import in passtest.py
     self.assertEqual(len(classes), 1)
     self.assertEqual(len(passtest_module.klass_imports), 1)
     self.assertEqual(len(passtest_module.mod_imports), 0)
     self.assertTrue(passtest_module.is_matching_klass(classes[0]))
Exemplo n.º 3
0
    def test_import_of_all_module_level(self):
        """
        Checks if all levels of a module import are taken into account

        This specific source file imports unittest.mock, and we want to
        make sure that unittest is accounted for.
        """
        path = os.path.join(BASEDIR, 'selftests', 'unit', 'test_loader.py')
        module = PythonModule(path, 'unittest', 'TestCase')
        for _ in module.iter_classes():
            pass
        self.assertIn('unittest', module.mod_imports)
Exemplo n.º 4
0
class PythonModuleSelf(unittest.TestCase):
    """
    Has tests based on this source code file
    """

    def setUp(self):
        self.path = os.path.abspath(os.path.dirname(get_this_file()))
        self.module = PythonModule(self.path)

    def test_add_imported_empty(self):
        self.assertEqual(self.module.imported_symbols, {})

    def test_add_imported_symbols_from_module(self):
        import_stm = ast.ImportFrom(module='foo', names=[ast.Name(name='bar',
                                                                  asname=None)])
        self.module.add_imported_symbol(import_stm)
        self.assertEqual(self.module.imported_symbols['bar'].module_path, 'foo')
        self.assertEqual(self.module.imported_symbols['bar'].symbol, 'bar')

    def test_add_imported_object_from_module_asname(self):
        import_stm = ast.ImportFrom(module='foo', names=[ast.Name(name='bar',
                                                                  asname='baz')])
        self.module.add_imported_symbol(import_stm)
        self.assertEqual(self.module.imported_symbols['baz'].module_path, 'foo')
        self.assertEqual(self.module.imported_symbols['baz'].symbol, 'bar')

    def test_is_not_avocado_test(self):
        self.assertFalse(self.module.is_matching_klass(ast.ClassDef()))

    def test_is_not_avocado_tests(self):
        for klass in self.module.iter_classes():
            self.assertFalse(self.module.is_matching_klass(klass))
Exemplo n.º 5
0
 def setUp(self):
     self.path = os.path.abspath(os.path.dirname(get_this_file()))
     self.module = PythonModule(self.path)
Exemplo n.º 6
0
def find_python_tests(target_module, target_class, determine_match, path):
    """
    Attempts to find Python tests from source files

    A Python test in this context is a method within a specific type
    of class (or that inherits from a specific class).

    :param target_module: the name of the module from which a class should
                          have come from.  When attempting to find a Python
                          unittest, the target_module will most probably
                          be "unittest", as per the standard library module
                          name.  When attempting to find Avocado tests, the
                          target_module will most probably be "avocado".
    :type target_module: str
    :param target_class: the name of the class that is considered to contain
                         test methods.  When attempting to find Python
                         unittests, the target_class will most probably be
                         "TestCase".  When attempting to find Avocado tests,
                         the target_class  will most probably be "Test".
    :type target_class: str
    :type determine_match: a callable that will determine if a given module
                           and class is contains valid Python tests
    :type determine_match: function
    :param path: path to a Python source code file
    :type path: str
    :returns: tuple where first item is dict with class name and additional
              info such as method names and tags; the second item is
              set of class names which look like Python tests but have been
              forcefully disabled.
    :rtype: tuple
    """
    module = PythonModule(path, target_module, target_class)
    # The resulting test classes
    result = collections.OrderedDict()
    disabled = set()

    for klass in module.iter_classes():
        docstring = ast.get_docstring(klass)
        # Looking for a class that has in the docstring either
        # ":avocado: enable" or ":avocado: disable
        if check_docstring_directive(docstring, 'disable'):
            disabled.add(klass.name)
            continue

        if check_docstring_directive(docstring, 'enable'):
            info = get_methods_info(klass.body,
                                    get_docstring_directives_tags(docstring),
                                    get_docstring_directives_requirements(
                                        docstring))
            result[klass.name] = info
            continue

        # From this point onwards we want to do recursive discovery, but
        # for now we don't know whether it is avocado.Test inherited
        # (Ifs are optimized for readability, not speed)

        # If "recursive" tag is specified, it is forced as test
        if check_docstring_directive(docstring, 'recursive'):
            match = True
        else:
            match = module.is_matching_klass(klass)
        info = get_methods_info(klass.body,
                                get_docstring_directives_tags(docstring),
                                get_docstring_directives_requirements(
                                    docstring))
        # Getting the list of parents of the current class
        parents = klass.bases

        match = _examine_same_module(parents, info, disabled, match, module,
                                     target_module, target_class, determine_match)

        # If there are parents left to be discovered, they
        # might be in a different module.
        for parent in parents:
            try:
                (parent_class,
                 imported_symbol,
                 symbol_is_module) = _get_attributes_for_further_examination(parent,
                                                                             module)

                found_spec = imported_symbol.get_importable_spec(symbol_is_module)
                if found_spec is None:
                    continue

            except ClassNotSuitable:
                continue

            _info, _dis, _match = _examine_class(target_module,
                                                 target_class,
                                                 determine_match,
                                                 found_spec.origin,
                                                 parent_class,
                                                 match)
            if _info:
                info.extend(_info)
                disabled.update(_dis)
            if _match is not match:
                match = _match

        # Only update the results if this was detected as 'avocado.Test'
        if match:
            result[klass.name] = info

    return result, disabled
Exemplo n.º 7
0
def _examine_class(target_module, target_class, determine_match, path,
                   class_name, match):
    """
    Examine a class from a given path

    :param target_module: the name of the module from which a class should
                          have come from.  When attempting to find a Python
                          unittest, the target_module will most probably
                          be "unittest", as per the standard library module
                          name.  When attempting to find Avocado tests, the
                          target_module will most probably be "avocado".
    :type target_module: str
    :param target_class: the name of the class that is considered to contain
                         test methods.  When attempting to find Python
                         unittests, the target_class will most probably be
                         "TestCase".  When attempting to find Avocado tests,
                         the target_class  will most probably be "Test".
    :type target_class: str
    :param determine_match: a callable that will determine if a match has
                            occurred or not
    :type determine_match: function
    :param path: path to a Python source code file
    :type path: str
    :param class_name: the specific class to be found
    :type path: str
    :param match: whether the inheritance from <target_module.target_class> has
                  been determined or not
    :type match: bool
    :returns: tuple where first item is a list of test methods detected
              for given class; second item is set of class names which
              look like avocado tests but are force-disabled.
    :rtype: tuple
    """
    module = PythonModule(path, target_module, target_class)
    info = []
    disabled = set()

    for klass in module.iter_classes(class_name):
        if class_name != klass.name:
            continue

        docstring = ast.get_docstring(klass)

        if match is False:
            match = module.is_matching_klass(klass)

        info = get_methods_info(klass.body,
                                get_docstring_directives_tags(docstring),
                                get_docstring_directives_requirements(
                                    docstring))

        # Getting the list of parents of the current class
        parents = klass.bases

        match = _examine_same_module(parents, info, disabled, match, module,
                                     target_module, target_class, determine_match)

        # If there are parents left to be discovered, they
        # might be in a different module.
        for parent in parents:
            try:
                (parent_class,
                 imported_symbol,
                 symbol_is_module) = _get_attributes_for_further_examination(parent,
                                                                             module)

                found_spec = imported_symbol.get_importable_spec(symbol_is_module)
                if found_spec is None:
                    continue

            except ClassNotSuitable:
                continue

            _info, _disabled, _match = _examine_class(target_module,
                                                      target_class,
                                                      determine_match,
                                                      found_spec.origin,
                                                      parent_class,
                                                      match)
            if _info:
                _extend_test_list(info, _info)
                disabled.update(_disabled)
            if _match is not match:
                match = _match

    if not match and module.interesting_klass_found:
        imported_symbol = module.imported_symbols[class_name]
        if imported_symbol:
            found_spec = imported_symbol.get_importable_spec()
            if found_spec:
                _info, _disabled, _match = _examine_class(target_module,
                                                          target_class,
                                                          determine_match,
                                                          found_spec.origin,
                                                          class_name,
                                                          match)
                if _info:
                    _extend_test_list(info, _info)
                    disabled.update(_disabled)
                if _match is not match:
                    match = _match

    return info, disabled, match