diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4')
27 files changed, 2302 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/.bzrignore b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/.bzrignore new file mode 100644 index 00000000000..336aaca369d --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/.bzrignore @@ -0,0 +1,5 @@ +TAGS +tags +lib/testtools +MANIFEST +dist diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Apache-2.0 b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Apache-2.0 new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Apache-2.0 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/BSD b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/BSD new file mode 100644 index 00000000000..0e75db647b3 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/BSD @@ -0,0 +1,26 @@ +Copyright (c) Robert Collins and Testscenarios contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of Robert Collins nor the names of Subunit contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ROBERT COLLINS AND SUBUNIT CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/COPYING b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/COPYING new file mode 100644 index 00000000000..ee16c4ecaf9 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/COPYING @@ -0,0 +1,31 @@ +Testscenarios is licensed under two licenses, the Apache License, Version 2.0 +or the 3-clause BSD License. You may use this project under either of these +licenses - choose the one that works best for you. + +We require contributions to be licensed under both licenses. The primary +difference between them is that the Apache license takes care of potential +issues with Patents and other intellectual property concerns that some users +or contributors may find important. + +Generally every source file in Testscenarios needs a license grant under both +these licenses. As the code is shipped as a single unit, a brief form is used: +---- +Copyright (c) [yyyy][,yyyy]* [name or 'Testscenarios Contributors'] + +Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +license at the users choice. A copy of both licenses are available in the +project source as Apache-2.0 and BSD. You may not use this file except in +compliance with one of these two licences. + +Unless required by applicable law or agreed to in writing, software +distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +license you chose for the specific language governing permissions and +limitations under that license. +---- + +Code that has been incorporated into Testscenarios from other projects will +naturally be under its own license, and will retain that license. + +A known list of such code is maintained here: +* No entries. diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/GOALS b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/GOALS new file mode 100644 index 00000000000..68be00129b2 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/GOALS @@ -0,0 +1,25 @@ + +testscenarios goals +=================== + + * nice, declarative interface for multiplying tests by scenarios. + + * plays nice with testresources - when a scenario uses a resource, the + resource ordering logic should be able to group them together. + + * (at user discretion) plays nice with $random test discovery + + * arbitrary post-load multiplication. + + * cross-productable scenarios (for X and for Y) + + * extenable scenarios (for X using Y) + + * scenarios and the tests that use them are loosely coupled + + * tests that use scenarios should be easy to debug + + * fast + + * usable in trial, bzr, Zope testrunner, nose and the default unittest + TestRunner diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/HACKING b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/HACKING new file mode 100644 index 00000000000..0c68ee7da90 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/HACKING @@ -0,0 +1,38 @@ +Contributing to testscenarios +============================= + +Code access ++++++++++++ + +Branch from the trunk (all patches should be for trunk unless there are +exceptional circumstances):: + + bzr branch lp:testscenarios path-to-new-local-branch + +Publish your branches whereever you like, I encourage launchpad hosting though, +as it can notify me of new testscenarios branches:: + + bzr push lp:~YOURUSERNAME/testscearios/YOURBRANCHNAME + +Copyright ++++++++++ + +Testscenarios is Copyright (C) 2009 Robert Collins. I'd like to be able to +offer it up for stdlib inclusion once it has proved itself, so am asking for +copyright assignment to me - or for your contributions to be under either the +BSD or Apache-2.0 licences that Testscenarios are with (which permit inclusion +in Python). + +Coding standards +++++++++++++++++ + +PEP-8 coding style please, though I'm not nitpicky. Make sure that 'make check' +passes before sending in a patch. + +Code arrangement +++++++++++++++++ + +The ``testscenarios`` module should simply import classes and functions from +more specific modules, rather than becoming large and bloated itself. For +instance, TestWithScenarios lives in testscenarios.testcase, and is imported in +the testscenarios __init__.py. diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/MANIFEST.in b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/MANIFEST.in new file mode 100644 index 00000000000..0edefa19588 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/MANIFEST.in @@ -0,0 +1,10 @@ +include .bzrignore +include Apache-2.0 +include BSD +include COPYING +include GOALS +include HACKING +include MANIFEST.in +include Makefile +include NEWS +include doc/*.py diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Makefile b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Makefile new file mode 100644 index 00000000000..c38edf6bfe7 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/Makefile @@ -0,0 +1,19 @@ +PYTHONPATH:=$(shell pwd)/lib:${PYTHONPATH} +PYTHON ?= python + +all: check + +check: + PYTHONPATH=$(PYTHONPATH) $(PYTHON) -m testtools.run \ + testscenarios.test_suite + +clean: + find . -name '*.pyc' -print0 | xargs -0 rm -f + +TAGS: lib/testscenarios/*.py lib/testscenarios/tests/*.py + ctags -e -R lib/testscenarios/ + +tags: lib/testscenarios/*.py lib/testscenarios/tests/*.py + ctags -R lib/testscenarios/ + +.PHONY: all check clean diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/NEWS b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/NEWS new file mode 100644 index 00000000000..fc3a10c469a --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/NEWS @@ -0,0 +1,56 @@ +--------------------------- +testscenarios release notes +--------------------------- + + +IN DEVELOPMENT +~~~~~~~~~~~~~~ + +0.4 +~~~ + +IMPROVEMENTS +------------ + +* Python 3.2 support added. (Robert Collins) + +0.3 +~~~ + +CHANGES +------- + +* New function ``per_module_scenarios`` for tests that should be applied across + multiple modules providing the same interface, some of which may not be + available at run time. (Martin Pool) + +* ``TestWithScenarios`` is now backed by a mixin - WithScenarios - which can be + mixed into different unittest implementations more cleanly (e.g. unittest2). + (James Polley, Robert Collins) + +0.2 +~~~ + +CHANGES +------- + +* Adjust the cloned tests ``shortDescription`` if one is present. (Ben Finney) + +* Provide a load_tests implementation for easy use, and multiply_scenarios to + create the cross product of scenarios. (Martin Pool) + +0.1 +~~~ + +CHANGES +------- + +* Created project. The primary interfaces are + ``testscenarios.TestWithScenarios`` and + ``testscenarios.generate_scenarios``. Documentation is primarily in README. + (Robert Collins) + +* Make the README documentation doctest compatible, to be sure it works. + Also various presentation and language touchups. (Martin Pool) + (Adjusted to use doctest directly, and to not print the demo runners + output to stderror during make check - Robert Collins) diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/PKG-INFO b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/PKG-INFO new file mode 100644 index 00000000000..f3ab96a5653 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/PKG-INFO @@ -0,0 +1,335 @@ +Metadata-Version: 1.1 +Name: testscenarios +Version: 0.4 +Summary: Testscenarios, a pyunit extension for dependency injection +Home-page: https://launchpad.net/testscenarios +Author: Robert Collins +Author-email: robertc@robertcollins.net +License: UNKNOWN +Description: ***************************************************************** + testscenarios: extensions to python unittest to support scenarios + ***************************************************************** + + Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> + + Licensed under either the Apache License, Version 2.0 or the BSD 3-clause + license at the users choice. A copy of both licenses are available in the + project source as Apache-2.0 and BSD. You may not use this file except in + compliance with one of these two licences. + + Unless required by applicable law or agreed to in writing, software + distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + license you chose for the specific language governing permissions and + limitations under that license. + + + testscenarios provides clean dependency injection for python unittest style + tests. This can be used for interface testing (testing many implementations via + a single test suite) or for classic dependency injection (provide tests with + dependencies externally to the test code itself, allowing easy testing in + different situations). + + Dependencies + ============ + + * Python 2.4+ + * testtools <https://launchpad.net/testtools> + + + Why TestScenarios + ================= + + Standard Python unittest.py provides on obvious method for running a single + test_foo method with two (or more) scenarios: by creating a mix-in that + provides the functions, objects or settings that make up the scenario. This is + however limited and unsatisfying. Firstly, when two projects are cooperating + on a test suite (for instance, a plugin to a larger project may want to run + the standard tests for a given interface on its implementation), then it is + easy for them to get out of sync with each other: when the list of TestCase + classes to mix-in with changes, the plugin will either fail to run some tests + or error trying to run deleted tests. Secondly, its not as easy to work with + runtime-created-subclasses (a way of dealing with the aforementioned skew) + because they require more indirection to locate the source of the test, and will + often be ignored by e.g. pyflakes pylint etc. + + It is the intent of testscenarios to make dynamically running a single test + in multiple scenarios clear, easy to debug and work with even when the list + of scenarios is dynamically generated. + + + Defining Scenarios + ================== + + A **scenario** is a tuple of a string name for the scenario, and a dict of + parameters describing the scenario. The name is appended to the test name, and + the parameters are made available to the test instance when it's run. + + Scenarios are presented in **scenario lists** which are typically Python lists + but may be any iterable. + + + Getting Scenarios applied + ========================= + + At its heart the concept is simple. For a given test object with a list of + scenarios we prepare a new test object for each scenario. This involves: + + * Clone the test to a new test with a new id uniquely distinguishing it. + * Apply the scenario to the test by setting each key, value in the scenario + as attributes on the test object. + + There are some complicating factors around making this happen seamlessly. These + factors are in two areas: + + * Choosing what scenarios to use. (See Setting Scenarios For A Test). + * Getting the multiplication to happen. + + Subclasssing + ++++++++++++ + + If you can subclass TestWithScenarios, then the ``run()`` method in + TestWithScenarios will take care of test multiplication. It will at test + execution act as a generator causing multiple tests to execute. For this to + work reliably TestWithScenarios must be first in the MRO and you cannot + override run() or __call__. This is the most robust method, in the sense + that any test runner or test loader that obeys the python unittest protocol + will run all your scenarios. + + Manual generation + +++++++++++++++++ + + If you cannot subclass TestWithScenarios (e.g. because you are using + TwistedTestCase, or TestCaseWithResources, or any one of a number of other + useful test base classes, or need to override run() or __call__ yourself) then + you can cause scenario application to happen later by calling + ``testscenarios.generate_scenarios()``. For instance:: + + >>> import unittest + >>> try: + ... from StringIO import StringIO + ... except ImportError: + ... from io import StringIO + >>> from testscenarios.scenarios import generate_scenarios + + This can work with loaders and runners from the standard library, or possibly other + implementations:: + + >>> loader = unittest.TestLoader() + >>> test_suite = unittest.TestSuite() + >>> runner = unittest.TextTestRunner(stream=StringIO()) + + >>> mytests = loader.loadTestsFromNames(['doc.test_sample']) + >>> test_suite.addTests(generate_scenarios(mytests)) + >>> runner.run(test_suite) + <unittest...TextTestResult run=1 errors=0 failures=0> + + Testloaders + +++++++++++ + + Some test loaders support hooks like ``load_tests`` and ``test_suite``. + Ensuring your tests have had scenario application done through these hooks can + be a good idea - it means that external test runners (which support these hooks + like ``nose``, ``trial``, ``tribunal``) will still run your scenarios. (Of + course, if you are using the subclassing approach this is already a surety). + With ``load_tests``:: + + >>> def load_tests(standard_tests, module, loader): + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(standard_tests)) + ... return result + + as a convenience, this is available in ``load_tests_apply_scenarios``, so a + module using scenario tests need only say :: + + >>> from testscenarios import load_tests_apply_scenarios as load_tests + + Python 2.7 and greater support a different calling convention for `load_tests`` + <https://bugs.launchpad.net/bzr/+bug/607412>. `load_tests_apply_scenarios` + copes with both. + + With ``test_suite``:: + + >>> def test_suite(): + ... loader = TestLoader() + ... tests = loader.loadTestsFromName(__name__) + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(tests)) + ... return result + + + Setting Scenarios for a test + ============================ + + A sample test using scenarios can be found in the doc/ folder. + + See `pydoc testscenarios` for details. + + On the TestCase + +++++++++++++++ + + You can set a scenarios attribute on the test case:: + + >>> class MyTest(unittest.TestCase): + ... + ... scenarios = [ + ... ('scenario1', dict(param=1)), + ... ('scenario2', dict(param=2)),] + + This provides the main interface by which scenarios are found for a given test. + Subclasses will inherit the scenarios (unless they override the attribute). + + After loading + +++++++++++++ + + Test scenarios can also be generated arbitrarily later, as long as the test has + not yet run. Simply replace (or alter, but be aware that many tests may share a + single scenarios attribute) the scenarios attribute. For instance in this + example some third party tests are extended to run with a custom scenario. :: + + >>> import testtools + >>> class TestTransport: + ... """Hypothetical test case for bzrlib transport tests""" + ... pass + ... + >>> stock_library_tests = unittest.TestLoader().loadTestsFromNames( + ... ['doc.test_sample']) + ... + >>> for test in testtools.iterate_tests(stock_library_tests): + ... if isinstance(test, TestTransport): + ... test.scenarios = test.scenarios + [my_vfs_scenario] + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(stock_library_tests)) + + Generated tests don't have a ``scenarios`` list, because they don't normally + require any more expansion. However, you can add a ``scenarios`` list back on + to them, and then run them through ``generate_scenarios`` again to generate the + cross product of tests. :: + + >>> class CrossProductDemo(unittest.TestCase): + ... scenarios = [('scenario_0_0', {}), + ... ('scenario_0_1', {})] + ... def test_foo(self): + ... return + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(CrossProductDemo("test_foo"))) + >>> for test in testtools.iterate_tests(suite): + ... test.scenarios = [ + ... ('scenario_1_0', {}), + ... ('scenario_1_1', {})] + ... + >>> suite2 = unittest.TestSuite() + >>> suite2.addTests(generate_scenarios(suite)) + >>> print(suite2.countTestCases()) + 4 + + Dynamic Scenarios + +++++++++++++++++ + + A common use case is to have the list of scenarios be dynamic based on plugins + and available libraries. An easy way to do this is to provide a global scope + scenarios somewhere relevant to the tests that will use it, and then that can + be customised, or dynamically populate your scenarios from a registry etc. + For instance:: + + >>> hash_scenarios = [] + >>> try: + ... from hashlib import md5 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("md5", dict(hash=md5))) + >>> try: + ... from hashlib import sha1 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("sha1", dict(hash=sha1))) + ... + >>> class TestHashContract(unittest.TestCase): + ... + ... scenarios = hash_scenarios + ... + >>> class TestHashPerformance(unittest.TestCase): + ... + ... scenarios = hash_scenarios + + + Forcing Scenarios + +++++++++++++++++ + + The ``apply_scenarios`` function can be useful to apply scenarios to a test + that has none applied. ``apply_scenarios`` is the workhorse for + ``generate_scenarios``, except it takes the scenarios passed in rather than + introspecting the test object to determine the scenarios. The + ``apply_scenarios`` function does not reset the test scenarios attribute, + allowing it to be used to layer scenarios without affecting existing scenario + selection. + + + Generating Scenarios + ==================== + + Some functions (currently one :-) are available to ease generation of scenario + lists for common situations. + + Testing Per Implementation Module + +++++++++++++++++++++++++++++++++ + + It is reasonably common to have multiple Python modules that provide the same + capabilities and interface, and to want apply the same tests to all of them. + + In some cases, not all of the statically defined implementations will be able + to be used in a particular testing environment. For example, there may be both + a C and a pure-Python implementation of a module. You want to test the C + module if it can be loaded, but also to have the tests pass if the C module has + not been compiled. + + The ``per_module_scenarios`` function generates a scenario for each named + module. The module object of the imported module is set in the supplied + attribute name of the resulting scenario. + Modules which raise ``ImportError`` during import will have the + ``sys.exc_info()`` of the exception set instead of the module object. Tests + can check for the attribute being a tuple to decide what to do (e.g. to skip). + + Note that for the test to be valid, all access to the module under test must go + through the relevant attribute of the test object. If one of the + implementations is also directly imported by the test module or any other, + testscenarios will not magically stop it being used. + + + Advice on Writing Scenarios + =========================== + + If a parameterised test is because of a bug run without being parameterized, + it should fail rather than running with defaults, because this can hide bugs. + + + Producing Scenarios + =================== + + The `multiply_scenarios` function produces the cross-product of the scenarios + passed in:: + + >>> from testscenarios.scenarios import multiply_scenarios + >>> + >>> scenarios = multiply_scenarios( + ... [('scenario1', dict(param1=1)), ('scenario2', dict(param1=2))], + ... [('scenario2', dict(param2=1))], + ... ) + >>> scenarios == [('scenario1,scenario2', {'param2': 1, 'param1': 1}), + ... ('scenario2,scenario2', {'param2': 1, 'param1': 2})] + True + +Platform: UNKNOWN +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/README b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/README new file mode 100644 index 00000000000..e7e7eb717e0 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/README @@ -0,0 +1,316 @@ +***************************************************************** +testscenarios: extensions to python unittest to support scenarios +***************************************************************** + + Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> + + Licensed under either the Apache License, Version 2.0 or the BSD 3-clause + license at the users choice. A copy of both licenses are available in the + project source as Apache-2.0 and BSD. You may not use this file except in + compliance with one of these two licences. + + Unless required by applicable law or agreed to in writing, software + distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + license you chose for the specific language governing permissions and + limitations under that license. + + +testscenarios provides clean dependency injection for python unittest style +tests. This can be used for interface testing (testing many implementations via +a single test suite) or for classic dependency injection (provide tests with +dependencies externally to the test code itself, allowing easy testing in +different situations). + +Dependencies +============ + +* Python 2.4+ +* testtools <https://launchpad.net/testtools> + + +Why TestScenarios +================= + +Standard Python unittest.py provides on obvious method for running a single +test_foo method with two (or more) scenarios: by creating a mix-in that +provides the functions, objects or settings that make up the scenario. This is +however limited and unsatisfying. Firstly, when two projects are cooperating +on a test suite (for instance, a plugin to a larger project may want to run +the standard tests for a given interface on its implementation), then it is +easy for them to get out of sync with each other: when the list of TestCase +classes to mix-in with changes, the plugin will either fail to run some tests +or error trying to run deleted tests. Secondly, its not as easy to work with +runtime-created-subclasses (a way of dealing with the aforementioned skew) +because they require more indirection to locate the source of the test, and will +often be ignored by e.g. pyflakes pylint etc. + +It is the intent of testscenarios to make dynamically running a single test +in multiple scenarios clear, easy to debug and work with even when the list +of scenarios is dynamically generated. + + +Defining Scenarios +================== + +A **scenario** is a tuple of a string name for the scenario, and a dict of +parameters describing the scenario. The name is appended to the test name, and +the parameters are made available to the test instance when it's run. + +Scenarios are presented in **scenario lists** which are typically Python lists +but may be any iterable. + + +Getting Scenarios applied +========================= + +At its heart the concept is simple. For a given test object with a list of +scenarios we prepare a new test object for each scenario. This involves: + +* Clone the test to a new test with a new id uniquely distinguishing it. +* Apply the scenario to the test by setting each key, value in the scenario + as attributes on the test object. + +There are some complicating factors around making this happen seamlessly. These +factors are in two areas: + +* Choosing what scenarios to use. (See Setting Scenarios For A Test). +* Getting the multiplication to happen. + +Subclasssing +++++++++++++ + +If you can subclass TestWithScenarios, then the ``run()`` method in +TestWithScenarios will take care of test multiplication. It will at test +execution act as a generator causing multiple tests to execute. For this to +work reliably TestWithScenarios must be first in the MRO and you cannot +override run() or __call__. This is the most robust method, in the sense +that any test runner or test loader that obeys the python unittest protocol +will run all your scenarios. + +Manual generation ++++++++++++++++++ + +If you cannot subclass TestWithScenarios (e.g. because you are using +TwistedTestCase, or TestCaseWithResources, or any one of a number of other +useful test base classes, or need to override run() or __call__ yourself) then +you can cause scenario application to happen later by calling +``testscenarios.generate_scenarios()``. For instance:: + + >>> import unittest + >>> try: + ... from StringIO import StringIO + ... except ImportError: + ... from io import StringIO + >>> from testscenarios.scenarios import generate_scenarios + +This can work with loaders and runners from the standard library, or possibly other +implementations:: + + >>> loader = unittest.TestLoader() + >>> test_suite = unittest.TestSuite() + >>> runner = unittest.TextTestRunner(stream=StringIO()) + + >>> mytests = loader.loadTestsFromNames(['doc.test_sample']) + >>> test_suite.addTests(generate_scenarios(mytests)) + >>> runner.run(test_suite) + <unittest...TextTestResult run=1 errors=0 failures=0> + +Testloaders ++++++++++++ + +Some test loaders support hooks like ``load_tests`` and ``test_suite``. +Ensuring your tests have had scenario application done through these hooks can +be a good idea - it means that external test runners (which support these hooks +like ``nose``, ``trial``, ``tribunal``) will still run your scenarios. (Of +course, if you are using the subclassing approach this is already a surety). +With ``load_tests``:: + + >>> def load_tests(standard_tests, module, loader): + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(standard_tests)) + ... return result + +as a convenience, this is available in ``load_tests_apply_scenarios``, so a +module using scenario tests need only say :: + + >>> from testscenarios import load_tests_apply_scenarios as load_tests + +Python 2.7 and greater support a different calling convention for `load_tests`` +<https://bugs.launchpad.net/bzr/+bug/607412>. `load_tests_apply_scenarios` +copes with both. + +With ``test_suite``:: + + >>> def test_suite(): + ... loader = TestLoader() + ... tests = loader.loadTestsFromName(__name__) + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(tests)) + ... return result + + +Setting Scenarios for a test +============================ + +A sample test using scenarios can be found in the doc/ folder. + +See `pydoc testscenarios` for details. + +On the TestCase ++++++++++++++++ + +You can set a scenarios attribute on the test case:: + + >>> class MyTest(unittest.TestCase): + ... + ... scenarios = [ + ... ('scenario1', dict(param=1)), + ... ('scenario2', dict(param=2)),] + +This provides the main interface by which scenarios are found for a given test. +Subclasses will inherit the scenarios (unless they override the attribute). + +After loading ++++++++++++++ + +Test scenarios can also be generated arbitrarily later, as long as the test has +not yet run. Simply replace (or alter, but be aware that many tests may share a +single scenarios attribute) the scenarios attribute. For instance in this +example some third party tests are extended to run with a custom scenario. :: + + >>> import testtools + >>> class TestTransport: + ... """Hypothetical test case for bzrlib transport tests""" + ... pass + ... + >>> stock_library_tests = unittest.TestLoader().loadTestsFromNames( + ... ['doc.test_sample']) + ... + >>> for test in testtools.iterate_tests(stock_library_tests): + ... if isinstance(test, TestTransport): + ... test.scenarios = test.scenarios + [my_vfs_scenario] + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(stock_library_tests)) + +Generated tests don't have a ``scenarios`` list, because they don't normally +require any more expansion. However, you can add a ``scenarios`` list back on +to them, and then run them through ``generate_scenarios`` again to generate the +cross product of tests. :: + + >>> class CrossProductDemo(unittest.TestCase): + ... scenarios = [('scenario_0_0', {}), + ... ('scenario_0_1', {})] + ... def test_foo(self): + ... return + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(CrossProductDemo("test_foo"))) + >>> for test in testtools.iterate_tests(suite): + ... test.scenarios = [ + ... ('scenario_1_0', {}), + ... ('scenario_1_1', {})] + ... + >>> suite2 = unittest.TestSuite() + >>> suite2.addTests(generate_scenarios(suite)) + >>> print(suite2.countTestCases()) + 4 + +Dynamic Scenarios ++++++++++++++++++ + +A common use case is to have the list of scenarios be dynamic based on plugins +and available libraries. An easy way to do this is to provide a global scope +scenarios somewhere relevant to the tests that will use it, and then that can +be customised, or dynamically populate your scenarios from a registry etc. +For instance:: + + >>> hash_scenarios = [] + >>> try: + ... from hashlib import md5 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("md5", dict(hash=md5))) + >>> try: + ... from hashlib import sha1 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("sha1", dict(hash=sha1))) + ... + >>> class TestHashContract(unittest.TestCase): + ... + ... scenarios = hash_scenarios + ... + >>> class TestHashPerformance(unittest.TestCase): + ... + ... scenarios = hash_scenarios + + +Forcing Scenarios ++++++++++++++++++ + +The ``apply_scenarios`` function can be useful to apply scenarios to a test +that has none applied. ``apply_scenarios`` is the workhorse for +``generate_scenarios``, except it takes the scenarios passed in rather than +introspecting the test object to determine the scenarios. The +``apply_scenarios`` function does not reset the test scenarios attribute, +allowing it to be used to layer scenarios without affecting existing scenario +selection. + + +Generating Scenarios +==================== + +Some functions (currently one :-) are available to ease generation of scenario +lists for common situations. + +Testing Per Implementation Module ++++++++++++++++++++++++++++++++++ + +It is reasonably common to have multiple Python modules that provide the same +capabilities and interface, and to want apply the same tests to all of them. + +In some cases, not all of the statically defined implementations will be able +to be used in a particular testing environment. For example, there may be both +a C and a pure-Python implementation of a module. You want to test the C +module if it can be loaded, but also to have the tests pass if the C module has +not been compiled. + +The ``per_module_scenarios`` function generates a scenario for each named +module. The module object of the imported module is set in the supplied +attribute name of the resulting scenario. +Modules which raise ``ImportError`` during import will have the +``sys.exc_info()`` of the exception set instead of the module object. Tests +can check for the attribute being a tuple to decide what to do (e.g. to skip). + +Note that for the test to be valid, all access to the module under test must go +through the relevant attribute of the test object. If one of the +implementations is also directly imported by the test module or any other, +testscenarios will not magically stop it being used. + + +Advice on Writing Scenarios +=========================== + +If a parameterised test is because of a bug run without being parameterized, +it should fail rather than running with defaults, because this can hide bugs. + + +Producing Scenarios +=================== + +The `multiply_scenarios` function produces the cross-product of the scenarios +passed in:: + + >>> from testscenarios.scenarios import multiply_scenarios + >>> + >>> scenarios = multiply_scenarios( + ... [('scenario1', dict(param1=1)), ('scenario2', dict(param1=2))], + ... [('scenario2', dict(param2=1))], + ... ) + >>> scenarios == [('scenario1,scenario2', {'param2': 1, 'param1': 1}), + ... ('scenario2,scenario2', {'param2': 1, 'param1': 2})] + True diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/__init__.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/__init__.py new file mode 100644 index 00000000000..4dbad55dcbb --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/__init__.py @@ -0,0 +1,16 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/example.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/example.py new file mode 100644 index 00000000000..a8d195fade2 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/example.py @@ -0,0 +1,30 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +"""Example TestScenario.""" + +from testscenarios import TestWithScenarios + + +scenario1 = ('basic', {'attribute': 'value'}) +scenario2 = ('advanced', {'attribute': 'value2'}) + + +class SampleWithScenarios(TestWithScenarios): + + scenarios = [scenario1, scenario2] + + def test_demo(self): + self.assertIsInstance(self.attribute, str) diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/test_sample.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/test_sample.py new file mode 100644 index 00000000000..a0b00a5ef54 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/doc/test_sample.py @@ -0,0 +1,22 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +import unittest + +class TestSample(unittest.TestCase): + + def test_so_easy(self): + pass diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/PKG-INFO b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/PKG-INFO new file mode 100644 index 00000000000..f3ab96a5653 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/PKG-INFO @@ -0,0 +1,335 @@ +Metadata-Version: 1.1 +Name: testscenarios +Version: 0.4 +Summary: Testscenarios, a pyunit extension for dependency injection +Home-page: https://launchpad.net/testscenarios +Author: Robert Collins +Author-email: robertc@robertcollins.net +License: UNKNOWN +Description: ***************************************************************** + testscenarios: extensions to python unittest to support scenarios + ***************************************************************** + + Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> + + Licensed under either the Apache License, Version 2.0 or the BSD 3-clause + license at the users choice. A copy of both licenses are available in the + project source as Apache-2.0 and BSD. You may not use this file except in + compliance with one of these two licences. + + Unless required by applicable law or agreed to in writing, software + distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + license you chose for the specific language governing permissions and + limitations under that license. + + + testscenarios provides clean dependency injection for python unittest style + tests. This can be used for interface testing (testing many implementations via + a single test suite) or for classic dependency injection (provide tests with + dependencies externally to the test code itself, allowing easy testing in + different situations). + + Dependencies + ============ + + * Python 2.4+ + * testtools <https://launchpad.net/testtools> + + + Why TestScenarios + ================= + + Standard Python unittest.py provides on obvious method for running a single + test_foo method with two (or more) scenarios: by creating a mix-in that + provides the functions, objects or settings that make up the scenario. This is + however limited and unsatisfying. Firstly, when two projects are cooperating + on a test suite (for instance, a plugin to a larger project may want to run + the standard tests for a given interface on its implementation), then it is + easy for them to get out of sync with each other: when the list of TestCase + classes to mix-in with changes, the plugin will either fail to run some tests + or error trying to run deleted tests. Secondly, its not as easy to work with + runtime-created-subclasses (a way of dealing with the aforementioned skew) + because they require more indirection to locate the source of the test, and will + often be ignored by e.g. pyflakes pylint etc. + + It is the intent of testscenarios to make dynamically running a single test + in multiple scenarios clear, easy to debug and work with even when the list + of scenarios is dynamically generated. + + + Defining Scenarios + ================== + + A **scenario** is a tuple of a string name for the scenario, and a dict of + parameters describing the scenario. The name is appended to the test name, and + the parameters are made available to the test instance when it's run. + + Scenarios are presented in **scenario lists** which are typically Python lists + but may be any iterable. + + + Getting Scenarios applied + ========================= + + At its heart the concept is simple. For a given test object with a list of + scenarios we prepare a new test object for each scenario. This involves: + + * Clone the test to a new test with a new id uniquely distinguishing it. + * Apply the scenario to the test by setting each key, value in the scenario + as attributes on the test object. + + There are some complicating factors around making this happen seamlessly. These + factors are in two areas: + + * Choosing what scenarios to use. (See Setting Scenarios For A Test). + * Getting the multiplication to happen. + + Subclasssing + ++++++++++++ + + If you can subclass TestWithScenarios, then the ``run()`` method in + TestWithScenarios will take care of test multiplication. It will at test + execution act as a generator causing multiple tests to execute. For this to + work reliably TestWithScenarios must be first in the MRO and you cannot + override run() or __call__. This is the most robust method, in the sense + that any test runner or test loader that obeys the python unittest protocol + will run all your scenarios. + + Manual generation + +++++++++++++++++ + + If you cannot subclass TestWithScenarios (e.g. because you are using + TwistedTestCase, or TestCaseWithResources, or any one of a number of other + useful test base classes, or need to override run() or __call__ yourself) then + you can cause scenario application to happen later by calling + ``testscenarios.generate_scenarios()``. For instance:: + + >>> import unittest + >>> try: + ... from StringIO import StringIO + ... except ImportError: + ... from io import StringIO + >>> from testscenarios.scenarios import generate_scenarios + + This can work with loaders and runners from the standard library, or possibly other + implementations:: + + >>> loader = unittest.TestLoader() + >>> test_suite = unittest.TestSuite() + >>> runner = unittest.TextTestRunner(stream=StringIO()) + + >>> mytests = loader.loadTestsFromNames(['doc.test_sample']) + >>> test_suite.addTests(generate_scenarios(mytests)) + >>> runner.run(test_suite) + <unittest...TextTestResult run=1 errors=0 failures=0> + + Testloaders + +++++++++++ + + Some test loaders support hooks like ``load_tests`` and ``test_suite``. + Ensuring your tests have had scenario application done through these hooks can + be a good idea - it means that external test runners (which support these hooks + like ``nose``, ``trial``, ``tribunal``) will still run your scenarios. (Of + course, if you are using the subclassing approach this is already a surety). + With ``load_tests``:: + + >>> def load_tests(standard_tests, module, loader): + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(standard_tests)) + ... return result + + as a convenience, this is available in ``load_tests_apply_scenarios``, so a + module using scenario tests need only say :: + + >>> from testscenarios import load_tests_apply_scenarios as load_tests + + Python 2.7 and greater support a different calling convention for `load_tests`` + <https://bugs.launchpad.net/bzr/+bug/607412>. `load_tests_apply_scenarios` + copes with both. + + With ``test_suite``:: + + >>> def test_suite(): + ... loader = TestLoader() + ... tests = loader.loadTestsFromName(__name__) + ... result = loader.suiteClass() + ... result.addTests(generate_scenarios(tests)) + ... return result + + + Setting Scenarios for a test + ============================ + + A sample test using scenarios can be found in the doc/ folder. + + See `pydoc testscenarios` for details. + + On the TestCase + +++++++++++++++ + + You can set a scenarios attribute on the test case:: + + >>> class MyTest(unittest.TestCase): + ... + ... scenarios = [ + ... ('scenario1', dict(param=1)), + ... ('scenario2', dict(param=2)),] + + This provides the main interface by which scenarios are found for a given test. + Subclasses will inherit the scenarios (unless they override the attribute). + + After loading + +++++++++++++ + + Test scenarios can also be generated arbitrarily later, as long as the test has + not yet run. Simply replace (or alter, but be aware that many tests may share a + single scenarios attribute) the scenarios attribute. For instance in this + example some third party tests are extended to run with a custom scenario. :: + + >>> import testtools + >>> class TestTransport: + ... """Hypothetical test case for bzrlib transport tests""" + ... pass + ... + >>> stock_library_tests = unittest.TestLoader().loadTestsFromNames( + ... ['doc.test_sample']) + ... + >>> for test in testtools.iterate_tests(stock_library_tests): + ... if isinstance(test, TestTransport): + ... test.scenarios = test.scenarios + [my_vfs_scenario] + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(stock_library_tests)) + + Generated tests don't have a ``scenarios`` list, because they don't normally + require any more expansion. However, you can add a ``scenarios`` list back on + to them, and then run them through ``generate_scenarios`` again to generate the + cross product of tests. :: + + >>> class CrossProductDemo(unittest.TestCase): + ... scenarios = [('scenario_0_0', {}), + ... ('scenario_0_1', {})] + ... def test_foo(self): + ... return + ... + >>> suite = unittest.TestSuite() + >>> suite.addTests(generate_scenarios(CrossProductDemo("test_foo"))) + >>> for test in testtools.iterate_tests(suite): + ... test.scenarios = [ + ... ('scenario_1_0', {}), + ... ('scenario_1_1', {})] + ... + >>> suite2 = unittest.TestSuite() + >>> suite2.addTests(generate_scenarios(suite)) + >>> print(suite2.countTestCases()) + 4 + + Dynamic Scenarios + +++++++++++++++++ + + A common use case is to have the list of scenarios be dynamic based on plugins + and available libraries. An easy way to do this is to provide a global scope + scenarios somewhere relevant to the tests that will use it, and then that can + be customised, or dynamically populate your scenarios from a registry etc. + For instance:: + + >>> hash_scenarios = [] + >>> try: + ... from hashlib import md5 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("md5", dict(hash=md5))) + >>> try: + ... from hashlib import sha1 + ... except ImportError: + ... pass + ... else: + ... hash_scenarios.append(("sha1", dict(hash=sha1))) + ... + >>> class TestHashContract(unittest.TestCase): + ... + ... scenarios = hash_scenarios + ... + >>> class TestHashPerformance(unittest.TestCase): + ... + ... scenarios = hash_scenarios + + + Forcing Scenarios + +++++++++++++++++ + + The ``apply_scenarios`` function can be useful to apply scenarios to a test + that has none applied. ``apply_scenarios`` is the workhorse for + ``generate_scenarios``, except it takes the scenarios passed in rather than + introspecting the test object to determine the scenarios. The + ``apply_scenarios`` function does not reset the test scenarios attribute, + allowing it to be used to layer scenarios without affecting existing scenario + selection. + + + Generating Scenarios + ==================== + + Some functions (currently one :-) are available to ease generation of scenario + lists for common situations. + + Testing Per Implementation Module + +++++++++++++++++++++++++++++++++ + + It is reasonably common to have multiple Python modules that provide the same + capabilities and interface, and to want apply the same tests to all of them. + + In some cases, not all of the statically defined implementations will be able + to be used in a particular testing environment. For example, there may be both + a C and a pure-Python implementation of a module. You want to test the C + module if it can be loaded, but also to have the tests pass if the C module has + not been compiled. + + The ``per_module_scenarios`` function generates a scenario for each named + module. The module object of the imported module is set in the supplied + attribute name of the resulting scenario. + Modules which raise ``ImportError`` during import will have the + ``sys.exc_info()`` of the exception set instead of the module object. Tests + can check for the attribute being a tuple to decide what to do (e.g. to skip). + + Note that for the test to be valid, all access to the module under test must go + through the relevant attribute of the test object. If one of the + implementations is also directly imported by the test module or any other, + testscenarios will not magically stop it being used. + + + Advice on Writing Scenarios + =========================== + + If a parameterised test is because of a bug run without being parameterized, + it should fail rather than running with defaults, because this can hide bugs. + + + Producing Scenarios + =================== + + The `multiply_scenarios` function produces the cross-product of the scenarios + passed in:: + + >>> from testscenarios.scenarios import multiply_scenarios + >>> + >>> scenarios = multiply_scenarios( + ... [('scenario1', dict(param1=1)), ('scenario2', dict(param1=2))], + ... [('scenario2', dict(param2=1))], + ... ) + >>> scenarios == [('scenario1,scenario2', {'param2': 1, 'param1': 1}), + ... ('scenario2,scenario2', {'param2': 1, 'param1': 2})] + True + +Platform: UNKNOWN +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/SOURCES.txt b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/SOURCES.txt new file mode 100644 index 00000000000..32492e1b819 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/SOURCES.txt @@ -0,0 +1,25 @@ +.bzrignore +Apache-2.0 +BSD +COPYING +GOALS +HACKING +MANIFEST.in +Makefile +NEWS +README +setup.py +doc/__init__.py +doc/example.py +doc/test_sample.py +lib/testscenarios/__init__.py +lib/testscenarios/scenarios.py +lib/testscenarios/testcase.py +lib/testscenarios.egg-info/PKG-INFO +lib/testscenarios.egg-info/SOURCES.txt +lib/testscenarios.egg-info/dependency_links.txt +lib/testscenarios.egg-info/requires.txt +lib/testscenarios.egg-info/top_level.txt +lib/testscenarios/tests/__init__.py +lib/testscenarios/tests/test_scenarios.py +lib/testscenarios/tests/test_testcase.py
\ No newline at end of file diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/dependency_links.txt b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/dependency_links.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/requires.txt b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/requires.txt new file mode 100644 index 00000000000..ccdb4f2ad56 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/requires.txt @@ -0,0 +1 @@ +testtools
\ No newline at end of file diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/top_level.txt b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/top_level.txt new file mode 100644 index 00000000000..b0ec88e9d5a --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios.egg-info/top_level.txt @@ -0,0 +1 @@ +testscenarios diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/__init__.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/__init__.py new file mode 100644 index 00000000000..ceacf37ddca --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/__init__.py @@ -0,0 +1,74 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + + +"""Support for running tests with different scenarios declaratively + +Testscenarios provides clean dependency injection for python unittest style +tests. This can be used for interface testing (testing many implementations via +a single test suite) or for classic dependency injection (provide tests with +dependencies externally to the test code itself, allowing easy testing in +different situations). + +See the README for a manual, and the docstrings on individual functions and +methods for details. +""" + +# same format as sys.version_info: "A tuple containing the five components of +# the version number: major, minor, micro, releaselevel, and serial. All +# values except releaselevel are integers; the release level is 'alpha', +# 'beta', 'candidate', or 'final'. The version_info value corresponding to the +# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a +# releaselevel of 'dev' for unreleased under-development code. +# +# If the releaselevel is 'alpha' then the major/minor/micro components are not +# established at this point, and setup.py will use a version of next-$(revno). +# If the releaselevel is 'final', then the tarball will be major.minor.micro. +# Otherwise it is major.minor.micro~$(revno). +__version__ = (0, 4, 0, 'final', 0) + +__all__ = [ + 'TestWithScenarios', + 'WithScenarios', + 'apply_scenario', + 'apply_scenarios', + 'generate_scenarios', + 'load_tests_apply_scenarios', + 'multiply_scenarios', + 'per_module_scenarios', + ] + + +import unittest + +from testscenarios.scenarios import ( + apply_scenario, + generate_scenarios, + load_tests_apply_scenarios, + multiply_scenarios, + per_module_scenarios, + ) +from testscenarios.testcase import TestWithScenarios, WithScenarios + + +def test_suite(): + import testscenarios.tests + return testscenarios.tests.test_suite() + + +def load_tests(standard_tests, module, loader): + standard_tests.addTests(loader.loadTestsFromNames(["testscenarios.tests"])) + return standard_tests diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/scenarios.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/scenarios.py new file mode 100644 index 00000000000..eeb72ebb8a4 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/scenarios.py @@ -0,0 +1,167 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# Copyright (c) 2010, 2011 Martin Pool <mbp@sourcefrog.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +__all__ = [ + 'apply_scenario', + 'apply_scenarios', + 'generate_scenarios', + 'load_tests_apply_scenarios', + 'multiply_scenarios', + ] + +from itertools import ( + chain, + product, + ) +import sys +import unittest + +from testtools.testcase import clone_test_with_new_id +from testtools import iterate_tests + + +def apply_scenario(scenario, test): + """Apply scenario to test. + + :param scenario: A tuple (name, parameters) to apply to the test. The test + is cloned, its id adjusted to have (name) after it, and the parameters + dict is used to update the new test. + :param test: The test to apply the scenario to. This test is unaltered. + :return: A new test cloned from test, with the scenario applied. + """ + name, parameters = scenario + scenario_suffix = '(' + name + ')' + newtest = clone_test_with_new_id(test, + test.id() + scenario_suffix) + test_desc = test.shortDescription() + if test_desc is not None: + newtest_desc = "%(test_desc)s %(scenario_suffix)s" % vars() + newtest.shortDescription = (lambda: newtest_desc) + for key, value in parameters.items(): + setattr(newtest, key, value) + return newtest + + +def apply_scenarios(scenarios, test): + """Apply many scenarios to a test. + + :param scenarios: An iterable of scenarios. + :param test: A test to apply the scenarios to. + :return: A generator of tests. + """ + for scenario in scenarios: + yield apply_scenario(scenario, test) + + +def generate_scenarios(test_or_suite): + """Yield the tests in test_or_suite with scenario multiplication done. + + TestCase objects with no scenarios specified are yielded unaltered. Tests + with scenarios are not yielded at all, instead the results of multiplying + them by the scenarios they specified gets yielded. + + :param test_or_suite: A TestCase or TestSuite. + :return: A generator of tests - objects satisfying the TestCase protocol. + """ + for test in iterate_tests(test_or_suite): + scenarios = getattr(test, 'scenarios', None) + if scenarios: + for newtest in apply_scenarios(scenarios, test): + newtest.scenarios = None + yield newtest + else: + yield test + + +def load_tests_apply_scenarios(*params): + """Adapter test runner load hooks to call generate_scenarios. + + If this is referenced by the `load_tests` attribute of a module, then + testloaders that implement this protocol will automatically arrange for + the scenarios to be expanded. This can be used instead of using + TestWithScenarios. + + Two different calling conventions for load_tests have been used, and this + function should support both. Python 2.7 passes (loader, standard_tests, + pattern), and bzr used (standard_tests, module, loader). + + :param loader: A TestLoader. + :param standard_test: The test objects found in this module before + multiplication. + """ + if getattr(params[0], 'suiteClass', None) is not None: + loader, standard_tests, pattern = params + else: + standard_tests, module, loader = params + result = loader.suiteClass() + result.addTests(generate_scenarios(standard_tests)) + return result + + +def multiply_scenarios(*scenarios): + """Multiply two or more iterables of scenarios. + + It is safe to pass scenario generators or iterators. + + :returns: A list of compound scenarios: the cross-product of all + scenarios, with the names concatenated and the parameters + merged together. + """ + result = [] + scenario_lists = map(list, scenarios) + for combination in product(*scenario_lists): + names, parameters = zip(*combination) + scenario_name = ','.join(names) + scenario_parameters = {} + for parameter in parameters: + scenario_parameters.update(parameter) + result.append((scenario_name, scenario_parameters)) + return result + + +def per_module_scenarios(attribute_name, modules): + """Generate scenarios for available implementation modules. + + This is typically used when there is a subsystem implemented, for + example, in both Python and C, and we want to apply the same tests to + both, but the C module may sometimes not be available. + + Note: if the module can't be loaded, the sys.exc_info() tuple for the + exception raised during import of the module is used instead of the module + object. A common idiom is to check in setUp for that and raise a skip or + error for that case. No special helpers are supplied in testscenarios as + yet. + + :param attribute_name: A name to be set in the scenario parameter + dictionary (and thence onto the test instance) pointing to the + implementation module (or import exception) for this scenario. + + :param modules: An iterable of (short_name, module_name), where + the short name is something like 'python' to put in the + scenario name, and the long name is a fully-qualified Python module + name. + """ + scenarios = [] + for short_name, module_name in modules: + try: + mod = __import__(module_name, {}, {}, ['']) + except: + mod = sys.exc_info() + scenarios.append(( + short_name, + {attribute_name: mod})) + return scenarios diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/testcase.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/testcase.py new file mode 100644 index 00000000000..2ab50c78848 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/testcase.py @@ -0,0 +1,70 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +__all__ = [ + 'TestWithScenarios', + 'WithScenarios', + ] + +import unittest + +from testtools.testcase import clone_test_with_new_id + +from testscenarios.scenarios import generate_scenarios + +_doc = """ + When a test object which inherits from WithScenarios is run, and there is a + non-empty scenarios attribute on the object, the test is multiplied by the + run method into one test per scenario. For this to work reliably the + WithScenarios.run method must not be overriden in a subclass (or overridden + compatibly with WithScenarios). + """ + +class WithScenarios(object): + __doc__ = """A mixin for TestCase with support for declarative scenarios. + """ + _doc + + def _get_scenarios(self): + return getattr(self, 'scenarios', None) + + def countTestCases(self): + scenarios = self._get_scenarios() + if not scenarios: + return 1 + else: + return len(scenarios) + + def debug(self): + scenarios = self._get_scenarios() + if scenarios: + for test in generate_scenarios(self): + test.debug() + else: + return super(WithScenarios, self).debug() + + def run(self, result=None): + scenarios = self._get_scenarios() + if scenarios: + for test in generate_scenarios(self): + test.run(result) + return + else: + return super(WithScenarios, self).run(result) + + +class TestWithScenarios(WithScenarios, unittest.TestCase): + __doc__ = """Unittest TestCase with support for declarative scenarios. + """ + _doc diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/__init__.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/__init__.py new file mode 100644 index 00000000000..8e243b6e5ab --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/__init__.py @@ -0,0 +1,43 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +import doctest +import sys +import unittest + +import testscenarios + + +def test_suite(): + result = unittest.TestSuite() + standard_tests = unittest.TestSuite() + module = sys.modules['testscenarios.tests'] + loader = unittest.TestLoader() + return load_tests(standard_tests, module, loader) + + +def load_tests(standard_tests, module, loader): + test_modules = [ + 'testcase', + 'scenarios', + ] + prefix = "testscenarios.tests.test_" + test_mod_names = [prefix + test_module for test_module in test_modules] + standard_tests.addTests(loader.loadTestsFromNames(test_mod_names)) + doctest.set_unittest_reportflags(doctest.REPORT_ONLY_FIRST_FAILURE) + standard_tests.addTest( + doctest.DocFileSuite("../../../README", optionflags=doctest.ELLIPSIS)) + return loader.suiteClass(testscenarios.generate_scenarios(standard_tests)) diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_scenarios.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_scenarios.py new file mode 100644 index 00000000000..97aa17f86cf --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_scenarios.py @@ -0,0 +1,261 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# Copyright (c) 2010, 2011 Martin Pool <mbp@sourcefrog.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +import unittest + +import testscenarios +from testscenarios.scenarios import ( + apply_scenario, + apply_scenarios, + generate_scenarios, + load_tests_apply_scenarios, + multiply_scenarios, + ) +import testtools +from testtools.tests.helpers import LoggingResult + + +class TestGenerateScenarios(testtools.TestCase): + + def hook_apply_scenarios(self): + self.addCleanup(setattr, testscenarios.scenarios, 'apply_scenarios', + apply_scenarios) + log = [] + def capture(scenarios, test): + log.append((scenarios, test)) + return apply_scenarios(scenarios, test) + testscenarios.scenarios.apply_scenarios = capture + return log + + def test_generate_scenarios_preserves_normal_test(self): + class ReferenceTest(unittest.TestCase): + def test_pass(self): + pass + test = ReferenceTest("test_pass") + log = self.hook_apply_scenarios() + self.assertEqual([test], list(generate_scenarios(test))) + self.assertEqual([], log) + + def test_tests_with_scenarios_calls_apply_scenarios(self): + class ReferenceTest(unittest.TestCase): + scenarios = [('demo', {})] + def test_pass(self): + pass + test = ReferenceTest("test_pass") + log = self.hook_apply_scenarios() + tests = list(generate_scenarios(test)) + self.assertEqual( + 'testscenarios.tests.test_scenarios.ReferenceTest.test_pass(demo)', + tests[0].id()) + self.assertEqual([([('demo', {})], test)], log) + + def test_all_scenarios_yielded(self): + class ReferenceTest(unittest.TestCase): + scenarios = [('1', {}), ('2', {})] + def test_pass(self): + pass + test = ReferenceTest("test_pass") + tests = list(generate_scenarios(test)) + self.assertEqual( + 'testscenarios.tests.test_scenarios.ReferenceTest.test_pass(1)', + tests[0].id()) + self.assertEqual( + 'testscenarios.tests.test_scenarios.ReferenceTest.test_pass(2)', + tests[1].id()) + + def test_scenarios_attribute_cleared(self): + class ReferenceTest(unittest.TestCase): + scenarios = [ + ('1', {'foo': 1, 'bar': 2}), + ('2', {'foo': 2, 'bar': 4})] + def test_check_foo(self): + pass + test = ReferenceTest("test_check_foo") + tests = list(generate_scenarios(test)) + for adapted in tests: + self.assertEqual(None, adapted.scenarios) + + def test_multiple_tests(self): + class Reference1(unittest.TestCase): + scenarios = [('1', {}), ('2', {})] + def test_something(self): + pass + class Reference2(unittest.TestCase): + scenarios = [('3', {}), ('4', {})] + def test_something(self): + pass + suite = unittest.TestSuite() + suite.addTest(Reference1("test_something")) + suite.addTest(Reference2("test_something")) + tests = list(generate_scenarios(suite)) + self.assertEqual(4, len(tests)) + + +class TestApplyScenario(testtools.TestCase): + + def setUp(self): + super(TestApplyScenario, self).setUp() + + self.scenario_name = 'demo' + self.scenario_attrs = {'foo': 'bar'} + self.scenario = (self.scenario_name, self.scenario_attrs) + + class ReferenceTest(unittest.TestCase): + def test_pass(self): + pass + def test_pass_with_docstring(self): + """ The test that always passes. + + This test case has a PEP 257 conformant docstring, + with its first line being a brief synopsis and the + rest of the docstring explaining that this test + does nothing but pass unconditionally. + + """ + pass + + self.ReferenceTest = ReferenceTest + + def test_sets_specified_id(self): + raw_test = self.ReferenceTest('test_pass') + raw_id = "testscenarios.tests.test_scenarios.ReferenceTest.test_pass" + scenario_name = self.scenario_name + expect_id = "%(raw_id)s(%(scenario_name)s)" % vars() + modified_test = apply_scenario(self.scenario, raw_test) + self.assertEqual(expect_id, modified_test.id()) + + def test_sets_specified_attributes(self): + raw_test = self.ReferenceTest('test_pass') + modified_test = apply_scenario(self.scenario, raw_test) + self.assertEqual('bar', modified_test.foo) + + def test_appends_scenario_name_to_short_description(self): + raw_test = self.ReferenceTest('test_pass_with_docstring') + modified_test = apply_scenario(self.scenario, raw_test) + raw_doc = self.ReferenceTest.test_pass_with_docstring.__doc__ + raw_desc = raw_doc.split("\n")[0].strip() + scenario_name = self.scenario_name + expect_desc = "%(raw_desc)s (%(scenario_name)s)" % vars() + self.assertEqual(expect_desc, modified_test.shortDescription()) + +class TestApplyScenarios(testtools.TestCase): + + def test_calls_apply_scenario(self): + self.addCleanup(setattr, testscenarios.scenarios, 'apply_scenario', + apply_scenario) + log = [] + def capture(scenario, test): + log.append((scenario, test)) + testscenarios.scenarios.apply_scenario = capture + scenarios = ["foo", "bar"] + result = list(apply_scenarios(scenarios, "test")) + self.assertEqual([('foo', 'test'), ('bar', 'test')], log) + + def test_preserves_scenarios_attribute(self): + class ReferenceTest(unittest.TestCase): + scenarios = [('demo', {})] + def test_pass(self): + pass + test = ReferenceTest("test_pass") + tests = list(apply_scenarios(ReferenceTest.scenarios, test)) + self.assertEqual([('demo', {})], ReferenceTest.scenarios) + self.assertEqual(ReferenceTest.scenarios, tests[0].scenarios) + + +class TestLoadTests(testtools.TestCase): + + class SampleTest(unittest.TestCase): + def test_nothing(self): + pass + scenarios = [ + ('a', {}), + ('b', {}), + ] + + def test_load_tests_apply_scenarios(self): + suite = load_tests_apply_scenarios( + unittest.TestLoader(), + [self.SampleTest('test_nothing')], + None) + result_tests = list(testtools.iterate_tests(suite)) + self.assertEquals( + 2, + len(result_tests), + result_tests) + + def test_load_tests_apply_scenarios_old_style(self): + """Call load_tests in the way used by bzr.""" + suite = load_tests_apply_scenarios( + [self.SampleTest('test_nothing')], + self.__class__.__module__, + unittest.TestLoader(), + ) + result_tests = list(testtools.iterate_tests(suite)) + self.assertEquals( + 2, + len(result_tests), + result_tests) + + +class TestMultiplyScenarios(testtools.TestCase): + + def test_multiply_scenarios(self): + def factory(name): + for i in 'ab': + yield i, {name: i} + scenarios = multiply_scenarios(factory('p'), factory('q')) + self.assertEqual([ + ('a,a', dict(p='a', q='a')), + ('a,b', dict(p='a', q='b')), + ('b,a', dict(p='b', q='a')), + ('b,b', dict(p='b', q='b')), + ], + scenarios) + + def test_multiply_many_scenarios(self): + def factory(name): + for i in 'abc': + yield i, {name: i} + scenarios = multiply_scenarios(factory('p'), factory('q'), + factory('r'), factory('t')) + self.assertEqual( + 3**4, + len(scenarios), + scenarios) + self.assertEqual( + 'a,a,a,a', + scenarios[0][0]) + + +class TestPerModuleScenarios(testtools.TestCase): + + def test_per_module_scenarios(self): + """Generate scenarios for available modules""" + s = testscenarios.scenarios.per_module_scenarios( + 'the_module', [ + ('Python', 'testscenarios'), + ('unittest', 'unittest'), + ('nonexistent', 'nonexistent'), + ]) + self.assertEqual('nonexistent', s[-1][0]) + self.assertIsInstance(s[-1][1]['the_module'], tuple) + s[-1][1]['the_module'] = None + self.assertEqual(s, [ + ('Python', {'the_module': testscenarios}), + ('unittest', {'the_module': unittest}), + ('nonexistent', {'the_module': None}), + ]) diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_testcase.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_testcase.py new file mode 100644 index 00000000000..74d2fe1c504 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/lib/testscenarios/tests/test_testcase.py @@ -0,0 +1,157 @@ +# testscenarios: extensions to python unittest to allow declarative +# dependency injection ('scenarios') by tests. +# +# Copyright (c) 2009, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +import unittest + +import testscenarios +import testtools +from testtools.tests.helpers import LoggingResult + + +class TestTestWithScenarios(testtools.TestCase): + + scenarios = testscenarios.scenarios.per_module_scenarios( + 'impl', (('unittest', 'unittest'), ('unittest2', 'unittest2'))) + + @property + def Implementation(self): + if isinstance(self.impl, tuple): + self.skipTest('import failed - module not installed?') + class Implementation(testscenarios.WithScenarios, self.impl.TestCase): + pass + return Implementation + + def test_no_scenarios_no_error(self): + class ReferenceTest(self.Implementation): + def test_pass(self): + pass + test = ReferenceTest("test_pass") + result = unittest.TestResult() + test.run(result) + self.assertTrue(result.wasSuccessful()) + self.assertEqual(1, result.testsRun) + + def test_with_one_scenario_one_run(self): + class ReferenceTest(self.Implementation): + scenarios = [('demo', {})] + def test_pass(self): + pass + test = ReferenceTest("test_pass") + log = [] + result = LoggingResult(log) + test.run(result) + self.assertTrue(result.wasSuccessful()) + self.assertEqual(1, result.testsRun) + self.assertEqual( + 'testscenarios.tests.test_testcase.ReferenceTest.test_pass(demo)', + log[0][1].id()) + + def test_with_two_scenarios_two_run(self): + class ReferenceTest(self.Implementation): + scenarios = [('1', {}), ('2', {})] + def test_pass(self): + pass + test = ReferenceTest("test_pass") + log = [] + result = LoggingResult(log) + test.run(result) + self.assertTrue(result.wasSuccessful()) + self.assertEqual(2, result.testsRun) + self.assertEqual( + 'testscenarios.tests.test_testcase.ReferenceTest.test_pass(1)', + log[0][1].id()) + self.assertEqual( + 'testscenarios.tests.test_testcase.ReferenceTest.test_pass(2)', + log[4][1].id()) + + def test_attributes_set(self): + class ReferenceTest(self.Implementation): + scenarios = [ + ('1', {'foo': 1, 'bar': 2}), + ('2', {'foo': 2, 'bar': 4})] + def test_check_foo(self): + self.assertEqual(self.foo * 2, self.bar) + test = ReferenceTest("test_check_foo") + log = [] + result = LoggingResult(log) + test.run(result) + self.assertTrue(result.wasSuccessful()) + self.assertEqual(2, result.testsRun) + + def test_scenarios_attribute_cleared(self): + class ReferenceTest(self.Implementation): + scenarios = [ + ('1', {'foo': 1, 'bar': 2}), + ('2', {'foo': 2, 'bar': 4})] + def test_check_foo(self): + self.assertEqual(self.foo * 2, self.bar) + test = ReferenceTest("test_check_foo") + log = [] + result = LoggingResult(log) + test.run(result) + self.assertTrue(result.wasSuccessful()) + self.assertEqual(2, result.testsRun) + self.assertNotEqual(None, test.scenarios) + self.assertEqual(None, log[0][1].scenarios) + self.assertEqual(None, log[4][1].scenarios) + + def test_countTestCases_no_scenarios(self): + class ReferenceTest(self.Implementation): + def test_check_foo(self): + pass + test = ReferenceTest("test_check_foo") + self.assertEqual(1, test.countTestCases()) + + def test_countTestCases_empty_scenarios(self): + class ReferenceTest(self.Implementation): + scenarios = [] + def test_check_foo(self): + pass + test = ReferenceTest("test_check_foo") + self.assertEqual(1, test.countTestCases()) + + def test_countTestCases_1_scenarios(self): + class ReferenceTest(self.Implementation): + scenarios = [('1', {'foo': 1, 'bar': 2})] + def test_check_foo(self): + pass + test = ReferenceTest("test_check_foo") + self.assertEqual(1, test.countTestCases()) + + def test_countTestCases_2_scenarios(self): + class ReferenceTest(self.Implementation): + scenarios = [ + ('1', {'foo': 1, 'bar': 2}), + ('2', {'foo': 2, 'bar': 4})] + def test_check_foo(self): + pass + test = ReferenceTest("test_check_foo") + self.assertEqual(2, test.countTestCases()) + + def test_debug_2_scenarios(self): + log = [] + class ReferenceTest(self.Implementation): + scenarios = [ + ('1', {'foo': 1, 'bar': 2}), + ('2', {'foo': 2, 'bar': 4})] + def test_check_foo(self): + log.append(self) + test = ReferenceTest("test_check_foo") + test.debug() + self.assertEqual(2, len(log)) + self.assertEqual(None, log[0].scenarios) + self.assertEqual(None, log[1].scenarios) + self.assertNotEqual(log[0].id(), log[1].id()) diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.cfg b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.cfg new file mode 100644 index 00000000000..861a9f55426 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.cfg @@ -0,0 +1,5 @@ +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + diff --git a/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.py b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.py new file mode 100755 index 00000000000..6b0d596a2a4 --- /dev/null +++ b/src/third_party/wiredtiger/test/3rdparty/testscenarios-0.4/setup.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +from setuptools import setup +import os.path + +description = open(os.path.join(os.path.dirname(__file__), 'README'), 'rt').read() + +setup(name="testscenarios", + version="0.4", + description="Testscenarios, a pyunit extension for dependency injection", + long_description=description, + maintainer="Robert Collins", + maintainer_email="robertc@robertcollins.net", + url="https://launchpad.net/testscenarios", + packages=['testscenarios', 'testscenarios.tests'], + package_dir = {'':'lib'}, + classifiers = [ + 'Development Status :: 6 - Mature', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Quality Assurance', + 'Topic :: Software Development :: Testing', + ], + install_requires = [ + 'testtools', + ] + ) |