U e4@sdZddlZddlZddlmZzddlmZWn ek rPddlmZYnXddgZddl m Z Gdd d e Z zdd l mZe ZWnek reZYnXGd dde ZGd d d e ZddZddZddZddZddZddZddZedkrddlZedS)a_ Testing Plugins =============== The plugin interface is well-tested enough to safely unit test your use of its hooks with some level of confidence. However, there is also a mixin for unittest.TestCase called PluginTester that's designed to test plugins in their native runtime environment. Here's a simple example with a do-nothing plugin and a composed suite. >>> import unittest >>> from nose.plugins import Plugin, PluginTester >>> class FooPlugin(Plugin): ... pass >>> class TestPluginFoo(PluginTester, unittest.TestCase): ... activate = '--with-foo' ... plugins = [FooPlugin()] ... def test_foo(self): ... for line in self.output: ... # i.e. check for patterns ... pass ... ... # or check for a line containing ... ... assert "ValueError" in self.output ... def makeSuite(self): ... class TC(unittest.TestCase): ... def runTest(self): ... raise ValueError("I hate foo") ... return [TC('runTest')] ... >>> res = unittest.TestResult() >>> case = TestPluginFoo('test_foo') >>> _ = case(res) >>> res.errors [] >>> res.failures [] >>> res.wasSuccessful() True >>> res.testsRun 1 And here is a more complex example of testing a plugin that has extra arguments and reads environment variables. >>> import unittest, os >>> from nose.plugins import Plugin, PluginTester >>> class FancyOutputter(Plugin): ... name = "fancy" ... def configure(self, options, conf): ... Plugin.configure(self, options, conf) ... if not self.enabled: ... return ... self.fanciness = 1 ... if options.more_fancy: ... self.fanciness = 2 ... if 'EVEN_FANCIER' in self.env: ... self.fanciness = 3 ... ... def options(self, parser, env=os.environ): ... self.env = env ... parser.add_option('--more-fancy', action='store_true') ... Plugin.options(self, parser, env=env) ... ... def report(self, stream): ... stream.write("FANCY " * self.fanciness) ... >>> class TestFancyOutputter(PluginTester, unittest.TestCase): ... activate = '--with-fancy' # enables the plugin ... plugins = [FancyOutputter()] ... args = ['--more-fancy'] ... env = {'EVEN_FANCIER': '1'} ... ... def test_fancy_output(self): ... assert "FANCY FANCY FANCY" in self.output, ( ... "got: %s" % self.output) ... def makeSuite(self): ... class TC(unittest.TestCase): ... def runTest(self): ... raise ValueError("I hate fancy stuff") ... return [TC('runTest')] ... >>> res = unittest.TestResult() >>> case = TestFancyOutputter('test_fancy_output') >>> _ = case(res) >>> res.errors [] >>> res.failures [] >>> res.wasSuccessful() True >>> res.testsRun 1 N)warn)StringIO PluginTesterrun)getpidc@sJeZdZdZddZddZddZdd Zdd d Zd dZ ddZ dS)MultiProcessFilea\ helper for testing multiprocessing multiprocessing poses a problem for doctests, since the strategy of replacing sys.stdout/stderr with file-like objects then inspecting the results won't work: the child processes will write to the objects, but the data will not be reflected in the parent doctest-ing process. The solution is to create file-like objects which will interact with multiprocessing in a more desirable way. All processes can write to this object, but only the creator can read. This allows the testing system to see a unified picture of I/O. cCs&t|_t|_t|_d|_dSNr)r_MultiProcessFile__masterManagerQueue_MultiProcessFile__queuer_MultiProcessFile__buffer softspaceselfrE/opt/hc_python/lib/python3.8/site-packages/nose/plugins/plugintest.py__init__~s zMultiProcessFile.__init__cCst|jkrdSddlm}ddlm}|t}z|j\}}Wn|k rZYqzYnX|dkrhd}|||7<q0t |D]}|j ||qdS)Nr)Empty) defaultdictr)g}Ô%IT) rr queuer collectionsrstrr get_nowaitsortedr write)rrrcachepiddatarrrbuffers     zMultiProcessFile.buffercCs(ddlm}|j}|j||fdS)Nr)current_process)multiprocessingr Z _identityr put)rrr rrrrrs zMultiProcessFile.writecCs||jS)zgetattr doesn't work for iter())rr rrrr__iter__szMultiProcessFile.__iter__rcCs||j||SN)rr seek)roffsetwhencerrrr%szMultiProcessFile.seekcCs||jSr$)rr getvaluerrrrr(szMultiProcessFile.getvaluecCs t|j|Sr$)getattrr )rattrrrr __getattr__szMultiProcessFile.__getattr__N)r) __name__ __module__ __qualname____doc__rrrr#r%r(r+rrrrrns r)r c@sDeZdZdZdZdZdZiZdZgZ dZ ddZ ddZ ddZ dS) ra%A mixin for testing nose plugins in their runtime environment. Subclass this and mix in unittest.TestCase to run integration/functional tests on your plugin. When setUp() is called, the stub test suite is executed with your plugin so that during an actual test you can inspect the artifacts of how your plugin interacted with the stub test suite. - activate - the argument to send nosetests to activate the plugin - suitepath - if set, this is the path of the suite to test. Otherwise, you will need to use the hook, makeSuite() - plugins - the list of plugins to make available during the run. Note that this does not mean these plugins will be *enabled* during the run -- only the plugins enabled by the activate argument or other settings in argv or env will be enabled. - args - a list of arguments to add to the nosetests command, in addition to the activate argument - env - optional dict of environment variables to send nosetests NcCstdS)areturns a suite object of tests to run (unittest.TestSuite()) If self.suitepath is None, this must be implemented. The returned suite object will be executed with all plugins activated. It may return None. Here is an example of a basic suite object you can return :: >>> import unittest >>> class SomeTest(unittest.TestCase): ... def runTest(self): ... raise ValueError("Now do something, plugin!") ... >>> unittest.TestSuite([SomeTest()]) # doctest: +ELLIPSIS ]> N)NotImplementedErrorrrrr makeSuiteszPluginTester.makeSuitecCsddlm}ddlm}ddlm}d}t}||j|||jdd}|j dk rX|j |_ |j sf| }||j ||dd |_ t||_dS) z7execute the plugin on the internal test suite. rConfig) TestProgram PluginManagerNplugins)envstreamr8F)argvconfigsuiteexit) nose.configr3Z nose.corer4nose.plugins.managerr6Bufferr9r8 ignoreFiles suitepathr1r;noseAccessDecoratoroutput)rr3r4r6r=r:confrrr _execPlugins"      zPluginTester._execPlugincCs@d|jg|_|jr |j|j|jr4|j|j|dS)zUruns nosetests with the specified test suite, all plugins activated. nosetestsN)activater;argsextendrCappendrHrrrrsetUps  zPluginTester.setUp)r,r-r.r/rJrCrKr9r;r8rBr1rHrNrrrrrs!c@s4eZdZdZdZddZddZddZdd ZdS) rENcCs(||_|d||_|ddSr)r:r%read_buf)rr:rrrrs  zAccessDecorator.__init__cCs ||jkSr$rP)rvalrrr __contains__szAccessDecorator.__contains__cCs t|jSr$)iterr:rrrrr#szAccessDecorator.__iter__cCs|jSr$rQrrrr__str__szAccessDecorator.__str__) r,r-r.r:rPrrSr#rUrrrrrEs rEccsbg}|dD]>}|||}|r<|dr|dsd|Vg}q|r^d|VdS)z9a bunch of === characters is also considered a blank lineTz====N) splitlinesrMstrip startswithjoin)textblocklinerrrblankline_separated_blocks#s  r_cCsHtdtjtjBtjB}g}t|D]}||d|q&d|S)NaD # Grab the traceback header. Different versions of Python have # said different things on the first traceback line. ^(?P Traceback\ \( (?: most\ recent\ call\ last | innermost\ last ) \) : ) \s* $ # toss trailing whitespace on the header. (?P .*?) # don't blink: absorb stuff until... ^(?=\w) # a line *starts* with alphanum. .*?(?P \w+ ) # exception name (?P [:\n] .*) # the rest z"\g\n...\n\g\grW) recompileVERBOSE MULTILINEDOTALLr_rMsubr[)outZ traceback_reblocksr]rrrremove_stack_traces0s  rhcCs tdtjtjB}|d|S)Nz # Cut the file and line no, up to the warning name ^.*:\d+:\s (?P\w+): \s+ # warning category (?P.+) $ \n? # warning message ^ .* $ # stack frame z\g: \g)r`rarbrcre)rfZwarn_rerrrsimplify_warningsFs ricCstdd|S)NzRan (\d+ tests?) in [0-9.]+szRan \1 in ...s)r`rerfrrrremove_timingsQs rkcCs t|}t|}t|}|S)z6Modify nose output to make it easy to use in doctests.)rhrirkrYrjrrrmunge_nose_output_for_doctestVsrlc Osddlm}ddlm}ddlm}t}d|krn|dg}t|t rR||d}|di}|||d |d<d |krd d g|d <||d_ t j }t j } |d dr|t _ t _ d} nd} tdtddz|||W5| r|t _ | t _ X|} tt| dS)a Specialized version of nose.run for use inside of doctests that test test runs. This version of run() prints the result output to stdout. Before printing, the output is processed by replacing the timing information with an ellipsis (...), removing traceback stacks, and removing trailing whitespace. Use this version of run wherever you are writing a doctest that tests nose (or unittest) test result output. Note: do not use doctest: +ELLIPSIS when testing nose output, since ellipses ("test_foo ... ok") in your expected test runner output may match multiple lines of output, causing spurious test passes! rrr2r5r<r8r7r9)r9r8r;rIz-v buffer_allFTaThe behavior of nose.plugins.plugintest.run() will change in the next release of nose. The current behavior does not correctly account for output to stdout and stderr. To enable correct behavior, use run_buffered() instead, or pass the keyword argument buffer_all=True to run().) stacklevelN)rDrr?r3r@r6rApop isinstancelistr:sysstderrstdoutrDeprecationWarningr(printrl) argkwrr3r6rr8r9rurvrestorerfrrrr^s<           cOsd|d<t||dS)NTrnrm)ryrzrrr run_bufferedsr|__main__)r/r`rtwarningsrior ImportError__all__osrobjectrr!r rArrEr_rhrirkrlrr|r,doctesttestmodrrrrs6a  ?  `  <