Test Utilities
**************

Helper functions for testing.

Our **stylistic_issues**, **pyflakes_issues**, and
**type_check_issues** respect a ‘exclude_paths’ in our test config,
excluding any absolute paths matching those regexes. Issue strings can
start or end with an asterisk to match just against the prefix or
suffix. For instance…

   exclude_paths .*/stem/test/data/.*

New in version 1.2.0.

   TimedTestRunner - test runner that tracks test runtimes
   test_runtimes - provides runtime of tests excuted through TimedTestRunners
   clean_orphaned_pyc - delete *.pyc files without corresponding *.py

   is_pyflakes_available - checks if pyflakes is available
   is_pycodestyle_available - checks if pycodestyle is available

   pyflakes_issues - static checks for problems via pyflakes
   stylistic_issues - checks for PEP8 and other stylistic issues

class stem.util.test_tools.AsyncResult(type, msg)

   Bases: "tuple"

   msg

      Alias for field number 1

   type

      Alias for field number 0

stem.util.test_tools.assert_equal(expected, actual, msg=None)

   Function form of a TestCase’s assertEqual.

   New in version 1.6.0.

   Parameters:
      * **expected** (*object*) – expected value

      * **actual** (*object*) – actual value

      * **msg** (*str*) – message if assertion fails

   Raises:
      **AssertionError** if values aren’t equal

stem.util.test_tools.assert_in(expected, actual, msg=None)

   Asserts that a given value is within this content.

   New in version 1.6.0.

   Parameters:
      * **expected** (*object*) – expected value

      * **actual** (*object*) – actual value

      * **msg** (*str*) – message if assertion fails

   Raises:
      **AssertionError** if the expected value isn’t in the actual

stem.util.test_tools.skip(msg)

   Function form of a TestCase’s skipTest.

   New in version 1.6.0.

   Parameters:
      **msg** (*str*) – reason test is being skipped

   Raises:
      **unittest.case.SkipTest** for this reason

stem.util.test_tools.asynchronous(func)

class stem.util.test_tools.AsyncTest(runner, args=None, threaded=False)

   Bases: "object"

   Test that’s run asychronously. These are functions (no self
   reference) performed like the following…

      class MyTest(unittest.TestCase):
        @staticmethod
        def run_tests():
          MyTest.test_addition = stem.util.test_tools.AsyncTest(MyTest.test_addition).method

        @staticmethod
        def test_addition():
          if 1 + 1 != 2:
            raise AssertionError('tisk, tisk')

      MyTest.run()

   New in version 1.6.0.

   run(*runner_args, **kwargs)

   pid()

   join()

   result(test)

class stem.util.test_tools.Issue

   Bases: "stem.util.test_tools.Issue"

   Issue encountered by pyflakes or pycodestyle.

   Variables:
      * **line_number** (*int*) – line number the issue occured on

      * **message** (*str*) – description of the issue

      * **line** (*str*) – content of the line the issue is about

class stem.util.test_tools.TimedTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False)

   Bases: "unittest.runner.TextTestRunner"

   Test runner that tracks the runtime of individual tests. When tests
   are run with this their runtimes are made available through
   "stem.util.test_tools.test_runtimes()".

   New in version 1.6.0.

   run(test)

      Run the given test case or test suite.

stem.util.test_tools.test_runtimes()

   Provides the runtimes of tests executed through TimedTestRunners.

   Returns:
      **dict** of fully qualified test names to floats for the runtime
      in seconds

   New in version 1.6.0.

stem.util.test_tools.clean_orphaned_pyc(paths)

   Deletes any file with a *.pyc extention without a corresponding
   *.py. This helps to address a common gotcha when deleting python
   files…

   * You delete module ‘foo.py’ and run the tests to ensure that you
     haven’t broken anything. They pass, however there *are* still
     some ‘import foo’ statements that still work because the bytecode
     (foo.pyc) is still around.

   * You push your change.

   * Another developer clones our repository and is confused because
     we have a bunch of ImportErrors.

   Parameters:
      **paths** (*list*) – paths to search for orphaned pyc files

   Returns:
      list of absolute paths that were deleted

stem.util.test_tools.is_pyflakes_available()

   Checks if pyflakes is availalbe.

   Returns:
      **True** if we can use pyflakes and **False** otherwise

stem.util.test_tools.is_pycodestyle_available()

   Checks if pycodestyle is availalbe.

   Returns:
      **True** if we can use pycodestyle and **False** otherwise

stem.util.test_tools.stylistic_issues(paths, check_newlines=False, check_exception_keyword=False, prefer_single_quotes=False)

   Checks for stylistic issues that are an issue according to the
   parts of PEP8 we conform to. You can suppress pycodestyle issues by
   making a ‘test’ configuration that sets ‘pycodestyle.ignore’.

   For example, with a ‘test/settings.cfg’ of…

      # pycodestyle compliance issues that we're ignoreing...
      #
      # * E111 and E121 four space indentations
      # * E501 line is over 79 characters

      pycodestyle.ignore E111
      pycodestyle.ignore E121
      pycodestyle.ignore E501

      pycodestyle.ignore run_tests.py => E402: import stem.util.enum

   … you can then run tests with…

      import stem.util.conf

      test_config = stem.util.conf.get_config('test')
      test_config.load('test/settings.cfg')

      issues = stylistic_issues('my_project')

   Changed in version 1.3.0: Renamed from get_stylistic_issues() to
   stylistic_issues(). The old name still works as an alias, but will
   be dropped in Stem version 2.0.0.

   Changed in version 1.4.0: Changing tuples in return value to be
   namedtuple instances, and adding the line that had the issue.

   Changed in version 1.4.0: Added the prefer_single_quotes option.

   Changed in version 1.6.0: Changed ‘pycodestyle.ignore’ code
   snippets to only need to match against the prefix.

   Parameters:
      * **paths** (*list*) – paths to search for stylistic issues

      * **check_newlines** (*bool*) – check that we have standard
        newlines (n), not windows (rn) nor classic mac (r)

      * **check_exception_keyword** (*bool*) – checks that we’re
        using ‘as’ for exceptions rather than a comma

      * **prefer_single_quotes** (*bool*) – standardize on using
        single rather than double quotes for strings, when reasonable

   Returns:
      dict of paths list of "stem.util.test_tools.Issue" instances

stem.util.test_tools.pyflakes_issues(paths)

   Performs static checks via pyflakes. False positives can be ignored
   via ‘pyflakes.ignore’ entries in our ‘test’ config. For instance…

      pyflakes.ignore stem/util/test_tools.py => 'pyflakes' imported but unused
      pyflakes.ignore stem/util/test_tools.py => 'pycodestyle' imported but unused

   Changed in version 1.3.0: Renamed from get_pyflakes_issues() to
   pyflakes_issues(). The old name still works as an alias, but will
   be dropped in Stem version 2.0.0.

   Changed in version 1.4.0: Changing tuples in return value to be
   namedtuple instances, and adding the line that had the issue.

   Changed in version 1.5.0: Support matching against prefix or suffix
   issue strings.

   Parameters:
      **paths** (*list*) – paths to search for problems

   Returns:
      dict of paths list of "stem.util.test_tools.Issue" instances

stem.util.test_tools.get_stylistic_issues(paths, check_newlines=False, check_exception_keyword=False, prefer_single_quotes=False)

   Checks for stylistic issues that are an issue according to the
   parts of PEP8 we conform to. You can suppress pycodestyle issues by
   making a ‘test’ configuration that sets ‘pycodestyle.ignore’.

   For example, with a ‘test/settings.cfg’ of…

      # pycodestyle compliance issues that we're ignoreing...
      #
      # * E111 and E121 four space indentations
      # * E501 line is over 79 characters

      pycodestyle.ignore E111
      pycodestyle.ignore E121
      pycodestyle.ignore E501

      pycodestyle.ignore run_tests.py => E402: import stem.util.enum

   … you can then run tests with…

      import stem.util.conf

      test_config = stem.util.conf.get_config('test')
      test_config.load('test/settings.cfg')

      issues = stylistic_issues('my_project')

   Changed in version 1.3.0: Renamed from get_stylistic_issues() to
   stylistic_issues(). The old name still works as an alias, but will
   be dropped in Stem version 2.0.0.

   Changed in version 1.4.0: Changing tuples in return value to be
   namedtuple instances, and adding the line that had the issue.

   Changed in version 1.4.0: Added the prefer_single_quotes option.

   Changed in version 1.6.0: Changed ‘pycodestyle.ignore’ code
   snippets to only need to match against the prefix.

   Parameters:
      * **paths** (*list*) – paths to search for stylistic issues

      * **check_newlines** (*bool*) – check that we have standard
        newlines (n), not windows (rn) nor classic mac (r)

      * **check_exception_keyword** (*bool*) – checks that we’re
        using ‘as’ for exceptions rather than a comma

      * **prefer_single_quotes** (*bool*) – standardize on using
        single rather than double quotes for strings, when reasonable

   Returns:
      dict of paths list of "stem.util.test_tools.Issue" instances

stem.util.test_tools.get_pyflakes_issues(paths)

   Performs static checks via pyflakes. False positives can be ignored
   via ‘pyflakes.ignore’ entries in our ‘test’ config. For instance…

      pyflakes.ignore stem/util/test_tools.py => 'pyflakes' imported but unused
      pyflakes.ignore stem/util/test_tools.py => 'pycodestyle' imported but unused

   Changed in version 1.3.0: Renamed from get_pyflakes_issues() to
   pyflakes_issues(). The old name still works as an alias, but will
   be dropped in Stem version 2.0.0.

   Changed in version 1.4.0: Changing tuples in return value to be
   namedtuple instances, and adding the line that had the issue.

   Changed in version 1.5.0: Support matching against prefix or suffix
   issue strings.

   Parameters:
      **paths** (*list*) – paths to search for problems

   Returns:
      dict of paths list of "stem.util.test_tools.Issue" instances

stem.util.test_tools.is_pep8_available()

   Checks if pycodestyle is availalbe.

   Returns:
      **True** if we can use pycodestyle and **False** otherwise
