google-apputils
Advanced tools
+251
| #!/usr/bin/env python | ||
| """Bootstrap setuptools installation | ||
| If you want to use setuptools in your package's setup.py, just include this | ||
| file in the same directory with it, and add this to the top of your setup.py:: | ||
| from ez_setup import use_setuptools | ||
| use_setuptools() | ||
| If you want to require a specific version of setuptools, set a download | ||
| mirror, or use an alternate download directory, you can do so by supplying | ||
| the appropriate options to ``use_setuptools()``. | ||
| This file can also be run as a script to install or upgrade setuptools. | ||
| """ | ||
| import sys | ||
| DEFAULT_VERSION = "0.6c11" | ||
| DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] | ||
| md5_data = { | ||
| 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', | ||
| 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', | ||
| 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', | ||
| 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', | ||
| 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', | ||
| 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', | ||
| 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', | ||
| 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', | ||
| 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', | ||
| 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', | ||
| 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', | ||
| 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', | ||
| 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', | ||
| 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', | ||
| 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', | ||
| } | ||
| import sys, os | ||
| try: from hashlib import md5 | ||
| except ImportError: from md5 import md5 | ||
| def _validate_md5(egg_name, data): | ||
| if egg_name in md5_data: | ||
| digest = md5(data).hexdigest() | ||
| if digest != md5_data[egg_name]: | ||
| print >>sys.stderr, ( | ||
| "md5 validation of %s failed! (Possible download problem?)" | ||
| % egg_name | ||
| ) | ||
| sys.exit(2) | ||
| return data | ||
| def use_setuptools( | ||
| version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, | ||
| download_delay=15 | ||
| ): | ||
| """Automatically find/download setuptools and make it available on sys.path | ||
| `version` should be a valid setuptools version number that is available | ||
| as an egg for download under the `download_base` URL (which should end with | ||
| a '/'). `to_dir` is the directory where setuptools will be downloaded, if | ||
| it is not already available. If `download_delay` is specified, it should | ||
| be the number of seconds that will be paused before initiating a download, | ||
| should one be required. If an older version of setuptools is installed, | ||
| this routine will print a message to ``sys.stderr`` and raise SystemExit in | ||
| an attempt to abort the calling script. | ||
| """ | ||
| was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules | ||
| def do_download(): | ||
| egg = download_setuptools(version, download_base, to_dir, download_delay) | ||
| sys.path.insert(0, egg) | ||
| import setuptools; setuptools.bootstrap_install_from = egg | ||
| try: | ||
| import pkg_resources | ||
| except ImportError: | ||
| return do_download() | ||
| try: | ||
| pkg_resources.require("setuptools>="+version); return | ||
| except pkg_resources.VersionConflict, e: | ||
| if was_imported: | ||
| print >>sys.stderr, ( | ||
| "The required version of setuptools (>=%s) is not available, and\n" | ||
| "can't be installed while this script is running. Please install\n" | ||
| " a more recent version first, using 'easy_install -U setuptools'." | ||
| "\n\n(Currently using %r)" | ||
| ) % (version, e.args[0]) | ||
| sys.exit(2) | ||
| except pkg_resources.DistributionNotFound: | ||
| pass | ||
| del pkg_resources, sys.modules['pkg_resources'] # reload ok | ||
| return do_download() | ||
| def download_setuptools( | ||
| version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, | ||
| delay = 15 | ||
| ): | ||
| """Download setuptools from a specified location and return its filename | ||
| `version` should be a valid setuptools version number that is available | ||
| as an egg for download under the `download_base` URL (which should end | ||
| with a '/'). `to_dir` is the directory where the egg will be downloaded. | ||
| `delay` is the number of seconds to pause before an actual download attempt. | ||
| """ | ||
| import urllib2, shutil | ||
| egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) | ||
| url = download_base + egg_name | ||
| saveto = os.path.join(to_dir, egg_name) | ||
| src = dst = None | ||
| if not os.path.exists(saveto): # Avoid repeated downloads | ||
| try: | ||
| from distutils import log | ||
| if delay: | ||
| log.warn(""" | ||
| --------------------------------------------------------------------------- | ||
| This script requires setuptools version %s to run (even to display | ||
| help). I will attempt to download it for you (from | ||
| %s), but | ||
| you may need to enable firewall access for this script first. | ||
| I will start the download in %d seconds. | ||
| (Note: if this machine does not have network access, please obtain the file | ||
| %s | ||
| and place it in this directory before rerunning this script.) | ||
| ---------------------------------------------------------------------------""", | ||
| version, download_base, delay, url | ||
| ); from time import sleep; sleep(delay) | ||
| log.warn("Downloading %s", url) | ||
| src = urllib2.urlopen(url) | ||
| # Read/write all in one block, so we don't create a corrupt file | ||
| # if the download is interrupted. | ||
| data = _validate_md5(egg_name, src.read()) | ||
| dst = open(saveto,"wb"); dst.write(data) | ||
| finally: | ||
| if src: src.close() | ||
| if dst: dst.close() | ||
| return os.path.realpath(saveto) | ||
| def main(argv, version=DEFAULT_VERSION): | ||
| """Install or upgrade setuptools and EasyInstall""" | ||
| try: | ||
| import setuptools | ||
| except ImportError: | ||
| egg = None | ||
| try: | ||
| egg = download_setuptools(version, delay=0) | ||
| sys.path.insert(0,egg) | ||
| from setuptools.command.easy_install import main | ||
| return main(list(argv)+[egg]) # we're done here | ||
| finally: | ||
| if egg and os.path.exists(egg): | ||
| os.unlink(egg) | ||
| else: | ||
| if setuptools.__version__ == '0.0.1': | ||
| print >>sys.stderr, ( | ||
| "You have an obsolete version of setuptools installed. Please\n" | ||
| "remove it from your system entirely before rerunning this script." | ||
| ) | ||
| sys.exit(2) | ||
| req = "setuptools>="+version | ||
| import pkg_resources | ||
| try: | ||
| pkg_resources.require(req) | ||
| except pkg_resources.VersionConflict: | ||
| try: | ||
| from setuptools.command.easy_install import main | ||
| except ImportError: | ||
| from easy_install import main | ||
| main(list(argv)+[download_setuptools(delay=0)]) | ||
| sys.exit(0) # try to force an exit | ||
| else: | ||
| if argv: | ||
| from setuptools.command.easy_install import main | ||
| main(argv) | ||
| else: | ||
| print "Setuptools version",version,"or greater has been installed." | ||
| print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' | ||
| def update_md5(filenames): | ||
| """Update our built-in md5 registry""" | ||
| import re | ||
| for name in filenames: | ||
| base = os.path.basename(name) | ||
| f = open(name,'rb') | ||
| md5_data[base] = md5(f.read()).hexdigest() | ||
| f.close() | ||
| data = [" %r: %r,\n" % it for it in md5_data.items()] | ||
| data.sort() | ||
| repl = "".join(data) | ||
| import inspect | ||
| srcfile = inspect.getsourcefile(sys.modules[__name__]) | ||
| f = open(srcfile, 'rb'); src = f.read(); f.close() | ||
| match = re.search("\nmd5_data = {\n([^}]+)}", src) | ||
| if not match: | ||
| print >>sys.stderr, "Internal error!" | ||
| sys.exit(2) | ||
| src = src[:match.start(1)] + repl + src[match.end(1):] | ||
| f = open(srcfile,'w') | ||
| f.write(src) | ||
| f.close() | ||
| if __name__=='__main__': | ||
| if len(sys.argv)>2 and sys.argv[1]=='--md5update': | ||
| update_md5(sys.argv[2:]) | ||
| else: | ||
| main(sys.argv[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. |
| include *.py | ||
| include LICENSE | ||
| include README | ||
| recursive-include google *.py |
| #!/usr/bin/env python |
| #!/usr/bin/env python | ||
| # | ||
| # Copyright 2005 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Helper script used by app_unittest.sh""" | ||
| import sys | ||
| import gflags as flags | ||
| from google.apputils import app | ||
| FLAGS = flags.FLAGS | ||
| flags.DEFINE_boolean("raise_exception", False, "throw MyException from main") | ||
| class MyException(Exception): | ||
| pass | ||
| def main(args): | ||
| if FLAGS.raise_exception: | ||
| raise MyException | ||
| if __name__ == '__main__': | ||
| app.run() |
| #!/usr/bin/env python | ||
| # Copyright 2008 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Tests for app.py .""" | ||
| import os | ||
| import shutil | ||
| import socket | ||
| import sys | ||
| import mox | ||
| from google.apputils import basetest | ||
| from google.apputils import app | ||
| import gflags as flags | ||
| FLAGS = flags.FLAGS | ||
| class TestFunctions(basetest.TestCase): | ||
| def testInstallExceptionHandler(self): | ||
| self.assertRaises(TypeError, app.InstallExceptionHandler, 1) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #! /bin/bash | ||
| # Copyright 2003 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| # | ||
| # Author: Douglas Greiman | ||
| PYTHON=$(which python) | ||
| function die { | ||
| echo "$1" | ||
| exit 1 | ||
| } | ||
| APP_PACKAGE="google.apputils" | ||
| # This should exit with error code because no main defined | ||
| $PYTHON -c "from ${APP_PACKAGE} import app; app.run()" 2>/dev/null && \ | ||
| die "Test 1 failed" | ||
| # Standard use. This should exit successfully | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| a = 0 | ||
| def main(argv): | ||
| global a | ||
| a = 1 | ||
| app.run() | ||
| assert a == 1" || \ | ||
| die "Test 2 failed" | ||
| # app.run called in exec block, script read from -c string. Should succeed. | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| a = 0 | ||
| s=''' | ||
| def main(argv): | ||
| global a | ||
| a = 1 | ||
| app.run() | ||
| ''' | ||
| exec s | ||
| assert a == 1" || \ | ||
| die "Test 4 failed" | ||
| # app.run called in exec block, script read from file. Should succeed. | ||
| PYFILE=$TEST_TMPDIR/tmp.py | ||
| cat >$PYFILE <<EOF | ||
| from ${APP_PACKAGE} import app | ||
| a = 0 | ||
| s=''' | ||
| def main(argv): | ||
| global a | ||
| a = 1 | ||
| app.run() | ||
| ''' | ||
| exec s | ||
| assert a == 1 | ||
| EOF | ||
| $PYTHON $PYFILE || \ | ||
| die "Test 5 failed" | ||
| rm -f $PYFILE | ||
| # Test for usage from --help | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| pass | ||
| app.run() | ||
| " --help | grep 'USAGE:' >/dev/null || \ | ||
| die "Test 11 failed" | ||
| # Test that the usage() function works | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| app.usage() | ||
| app.run() | ||
| " 2>&1 | egrep '^ --' >/dev/null || \ | ||
| die "Test 12 failed" | ||
| # Test that shorthelp doesn't give flags in this case. | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| app.usage(shorthelp=1) | ||
| app.run() | ||
| " 2>&1 | grep '^ --' >/dev/null && \ | ||
| die "Test 13 failed" | ||
| # Test writeto_stdout. | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| app.usage(shorthelp=1, writeto_stdout=1) | ||
| app.run() | ||
| " | grep 'USAGE' >/dev/null || \ | ||
| die "Test 14 failed" | ||
| # Test detailed_error | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| app.usage(shorthelp=1, writeto_stdout=1, detailed_error='BAZBAZ') | ||
| app.run() | ||
| " 2>&1 | grep 'BAZBAZ' >/dev/null || \ | ||
| die "Test 15 failed" | ||
| # Test exitcode | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| app.usage(writeto_stdout=1, exitcode=1) | ||
| app.run() | ||
| " >/dev/null | ||
| if [ "$?" -ne "1" ]; then | ||
| die "Test 16 failed" | ||
| fi | ||
| # Test --help (this could use wrapping which is tested elsewhere) | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| print 'FAIL' | ||
| app.run() | ||
| " 2>&1 --help | grep 'USAGE: -c \[flags\]' >/dev/null || \ | ||
| die "Test 17 failed" | ||
| # Test --help does not wrap for __main__.__doc__ | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| import sys | ||
| def main(argv): | ||
| print 'FAIL' | ||
| doc = [] | ||
| for i in xrange(10): | ||
| doc.append(str(i)) | ||
| doc.append('12345678 ') | ||
| sys.modules['__main__'].__doc__ = ''.join(doc) | ||
| app.run() | ||
| " 2>&1 --help | grep '712345678 812345678' >/dev/null || \ | ||
| die "Test 18 failed" | ||
| # Test --help with forced wrap for __main__.__doc__ | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| import sys | ||
| def main(argv): | ||
| print 'FAIL' | ||
| doc = [] | ||
| for i in xrange(10): | ||
| doc.append(str(i)) | ||
| doc.append('12345678 ') | ||
| sys.modules['__main__'].__doc__ = ''.join(doc) | ||
| app.SetEnableHelpWrapping() | ||
| app.run() | ||
| " 2>&1 --help | grep '712345678 812345678' >/dev/null && \ | ||
| die "Test 19 failed" | ||
| # Test UsageError | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| raise app.UsageError('You made a usage error') | ||
| app.run() | ||
| " 2>&1 | grep "You made a usage error" >/dev/null || \ | ||
| die "Test 20 failed" | ||
| # Test UsageError exit code | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| raise app.UsageError('You made a usage error', exitcode=64) | ||
| app.run() | ||
| " > /dev/null 2>&1 | ||
| if [ "$?" -ne "64" ]; then | ||
| die "Test 21 failed" | ||
| fi | ||
| # Test catching top-level exceptions. We should get the exception name on | ||
| # stderr. | ||
| ./app_test_helper.py \ | ||
| --raise_exception 2>&1 | grep -q 'MyException' || die "Test 23 failed" | ||
| # Test exception handlers are called | ||
| have_handler_output=$TEST_TMPDIR/handler.txt | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| raise ValueError('look for me') | ||
| class TestExceptionHandler(app.ExceptionHandler): | ||
| def __init__(self, msg): | ||
| self.msg = msg | ||
| def Handle(self, exc): | ||
| print '%s %s' % (self.msg, exc) | ||
| app.InstallExceptionHandler(TestExceptionHandler('first')) | ||
| app.InstallExceptionHandler(TestExceptionHandler('second')) | ||
| app.run() | ||
| " > $have_handler_output 2>&1 | ||
| grep -q "first look for me" $have_handler_output || die "Test 24 failed" | ||
| grep -q "second look for me" $have_handler_output || die "Test 25 failed" | ||
| no_handler_output=$TEST_TMPDIR/no_handler.txt | ||
| # Test exception handlers are not called for "normal" exits | ||
| for exc in "SystemExit(1)" "app.UsageError('foo')"; do | ||
| $PYTHON -c "from ${APP_PACKAGE} import app | ||
| def main(argv): | ||
| raise $exc | ||
| class TestExceptionHandler(app.ExceptionHandler): | ||
| def Handle(self, exc): | ||
| print 'handler was called' | ||
| app.InstallExceptionHandler(TestExceptionHandler()) | ||
| app.run() | ||
| " > $no_handler_output 2>&1 | ||
| grep -q "handler was called" $no_handler_output && die "Test 26 ($exc) failed" | ||
| done | ||
| # Test --help expands docstring. | ||
| $PYTHON -c " | ||
| '''USAGE: %s [flags]''' | ||
| from ${APP_PACKAGE} import app | ||
| def main(argv): print 'FAIL' | ||
| app.run() | ||
| " --help 2>&1 | | ||
| fgrep 'USAGE: -c [flags]' >/dev/null || | ||
| die "Test 27 failed" | ||
| # Test --help expands docstring. | ||
| $PYTHON -c " | ||
| '''USAGE: %s --fmt=\"%%s\" --fraction=50%%''' | ||
| from ${APP_PACKAGE} import app | ||
| def main(argv): print 'FAIL' | ||
| app.run() | ||
| " --help 2>&1 | | ||
| fgrep 'USAGE: -c --fmt="%s" --fraction=50%' >/dev/null || | ||
| die "Test 28 failed" | ||
| # Test --help expands docstring. | ||
| $PYTHON -c " | ||
| '''>%s|%%s|%%%s|%%%%s|%%%%%s<''' | ||
| from ${APP_PACKAGE} import app | ||
| def main(argv): print 'FAIL' | ||
| app.run() | ||
| " --help 2>&1 | | ||
| fgrep '>-c|%s|%-c|%%s|%%-c<' >/dev/null || | ||
| die "Test 29 failed" | ||
| # Test bad docstring. | ||
| $PYTHON -c " | ||
| '''>%@<''' | ||
| from ${APP_PACKAGE} import app | ||
| def main(argv): print 'FAIL' | ||
| app.run() | ||
| " --help 2>&1 | | ||
| fgrep '>%@<' >/dev/null || | ||
| die "Test 30 failed" | ||
| readonly HELP_PROG=" | ||
| from ${APP_PACKAGE} import app | ||
| def main(argv): print 'HI' | ||
| app.run() | ||
| " | ||
| echo "PASS" |
| #!/usr/bin/env python | ||
| # Copyright 2007 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Test tool to demonstrate appcommands.py usage. | ||
| This tool shows how to use appcommands.py. | ||
| """ | ||
| from google.apputils import appcommands | ||
| import gflags as flags | ||
| FLAGS = flags.FLAGS | ||
| flags.DEFINE_string('hint', '', 'Global hint to show in commands') | ||
| # Name taken from app.py | ||
| class Test1(appcommands.Cmd): | ||
| """Help for test1. As described by a docstring.""" | ||
| def __init__(self, name, flag_values, **kargs): | ||
| """Init and register flags specific to command.""" | ||
| super(Test1, self).__init__(name, flag_values, **kargs) | ||
| # Flag --fail1 is specific to this command | ||
| flags.DEFINE_boolean('fail1', False, 'Make test1 fail', | ||
| flag_values=flag_values) | ||
| flags.DEFINE_string('foo', '', 'Param foo', flag_values=flag_values) | ||
| flags.DEFINE_string('bar', '', 'Param bar', flag_values=flag_values) | ||
| flags.DEFINE_integer('intfoo', 0, 'Integer foo', flag_values=flag_values) | ||
| flags.DEFINE_boolean('allhelp', False, 'Get _all_commands_help string', | ||
| flag_values=flag_values) | ||
| def Run(self, unused_argv): | ||
| """Output 'Command1' and flag info. | ||
| Args: | ||
| unused_argv: Remaining arguments after parsing flags and command | ||
| Returns: | ||
| Value of flag fail1 | ||
| """ | ||
| print 'Command1' | ||
| if FLAGS.hint: | ||
| print "Hint1:'%s'" % FLAGS.hint | ||
| print "Foo1:'%s'" % FLAGS.foo | ||
| print "Bar1:'%s'" % FLAGS.bar | ||
| if FLAGS.allhelp: | ||
| print "AllHelp:'%s'" % self._all_commands_help | ||
| return FLAGS.fail1 * 1 | ||
| class Test2(appcommands.Cmd): | ||
| """Help for test2.""" | ||
| def __init__(self, name, flag_values, **kargs): | ||
| """Init and register flags specific to command.""" | ||
| super(Test2, self).__init__(name, flag_values, **kargs) | ||
| flags.DEFINE_boolean('fail2', False, 'Make test2 fail', | ||
| flag_values=flag_values) | ||
| flags.DEFINE_string('foo', '', 'Param foo', flag_values=flag_values) | ||
| flags.DEFINE_string('bar', '', 'Param bar', flag_values=flag_values) | ||
| def Run(self, unused_argv): | ||
| """Output 'Command2' and flag info. | ||
| Args: | ||
| unused_argv: Remaining arguments after parsing flags and command | ||
| Returns: | ||
| Value of flag fail2 | ||
| """ | ||
| print 'Command2' | ||
| if FLAGS.hint: | ||
| print "Hint2:'%s'" % FLAGS.hint | ||
| print "Foo2:'%s'" % FLAGS.foo | ||
| print "Bar2:'%s'" % FLAGS.bar | ||
| return FLAGS.fail2 * 1 | ||
| def Test3(unused_argv): | ||
| """Help for test3.""" | ||
| print 'Command3' | ||
| def Test4(unused_argv): | ||
| """Help for test4.""" | ||
| print 'Command4' | ||
| def main(unused_argv): | ||
| """Register the commands.""" | ||
| appcommands.AddCmd('test1', Test1, | ||
| command_aliases=['testalias1', 'testalias2']) | ||
| appcommands.AddCmd('test1b', Test1, | ||
| command_aliases=['testalias1b', 'testalias2b'], | ||
| all_commands_help='test1b short help', help_full="""test1b | ||
| is my very favorite test | ||
| because it has verbose help messages""") | ||
| appcommands.AddCmd('test2', Test2) | ||
| appcommands.AddCmdFunc('test3', Test3) | ||
| appcommands.AddCmdFunc('test4', Test4, command_aliases=['testalias3'], | ||
| all_commands_help='replacetest4help') | ||
| if __name__ == '__main__': | ||
| appcommands.Run() |
| #! /bin/bash | ||
| # Copyright 2007 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| # | ||
| # Author: mboerger@google.com | ||
| PYTHON=$(which python) | ||
| function die { | ||
| echo "$1" | ||
| exit 1 | ||
| } | ||
| IMPORTS="from google.apputils import app | ||
| from google.apputils import appcommands | ||
| import gflags as flags" | ||
| # This should exit with error code because no main defined | ||
| $PYTHON -c "${IMPORTS} | ||
| appcommands.Run()" >/dev/null 2>&1 && \ | ||
| die "Test 1 failed" | ||
| # Standard use. This should exit successfully | ||
| $PYTHON -c "${IMPORTS} | ||
| import sys | ||
| def test(argv): | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run() | ||
| sys.exit(1)" test || \ | ||
| die "Test 2 failed" | ||
| # Even with no return from Cmds Run() does not return | ||
| $PYTHON -c "${IMPORTS} | ||
| import sys | ||
| def test(argv): | ||
| return | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run() | ||
| sys.exit(1)" test || \ | ||
| die "Test 3 failed" | ||
| # Standard use with returning an error code. | ||
| $PYTHON -c "${IMPORTS} | ||
| import sys | ||
| def test(argv): | ||
| return 1 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run() | ||
| sys.exit(0)" test && \ | ||
| die "Test 4 failed" | ||
| # Executing two commands in single mode does not work (execute only first) | ||
| $PYTHON -c "${IMPORTS} | ||
| def test1(argv): | ||
| return 0 | ||
| def test2(argv): | ||
| return 1 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test1', test1) | ||
| appcommands.AddCmdFunc('test2', test2) | ||
| appcommands.Run()" test1 test2 || \ | ||
| die "Test 5 failed" | ||
| # Registering a command twice does not work. | ||
| $PYTHON -c "${IMPORTS} | ||
| def test1(argv): | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test1) | ||
| appcommands.AddCmdFunc('test', test1) | ||
| appcommands.Run()" test >/dev/null 2>&1 && \ | ||
| die "Test 6 failed" | ||
| # Executing help, returns non zero return code (1), then check result | ||
| RES=`$PYTHON -c "${IMPORTS} | ||
| def test1(argv): | ||
| '''Help1''' | ||
| return 0 | ||
| def test2(argv): | ||
| '''Help2''' | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test1', test1) | ||
| appcommands.AddCmdFunc('test2', test2) | ||
| appcommands.Run()" help` && die "Test 7 failed" | ||
| echo "${RES}" | grep -q "USAGE: " || die "Test 8 failed" | ||
| echo "${RES}" | sed -ne '/following commands:/,/.*/p' | \ | ||
| grep -q "help, test1, test2" || die "Test 9 failed" | ||
| echo "${RES}" | grep -q -E "(^| )test1[ \t]+Help1($| )" || die "Test 10 failed" | ||
| echo "${RES}" | grep -q -E "(^| )test2[ \t]+Help2($| )" || die "Test 11 failed" | ||
| # Executing help for command, returns non zero return code (1), then check result | ||
| RES=`$PYTHON -c "${IMPORTS} | ||
| def test1(argv): | ||
| '''Help1''' | ||
| return 0 | ||
| def test2(argv): | ||
| '''Help2''' | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test1', test1) | ||
| appcommands.AddCmdFunc('test2', test2) | ||
| appcommands.Run()" help test2` && die "Test 12 failed" | ||
| echo "${RES}" | grep -q "USAGE: " || die "Test 13 failed" | ||
| echo "${RES}" | grep -q -E "(^| )Any of the following commands:" && die "Test 14 failed" | ||
| echo "${RES}" | grep -q -E "(^| )test1[ \t]+" && die "Test 15 failed" | ||
| echo "${RES}" | grep -q -E "(^| )test2[ \t]+Help2($| )" || die "Test 16 failed" | ||
| # Returning False succeeds | ||
| $PYTHON -c "${IMPORTS} | ||
| def test(argv): return False | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run()" test || die "Test 17 failed" | ||
| # Returning True fails | ||
| $PYTHON -c "${IMPORTS} | ||
| def test(argv): return True | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run()" test && die "Test 18 failed" | ||
| # Registering using AddCmd instead of AddCmdFunc, should be the normal case | ||
| $PYTHON -c "${IMPORTS} | ||
| class test(appcommands.Cmd): | ||
| def Run(self, argv): return 0 | ||
| def main(argv): | ||
| appcommands.AddCmd('test', test) | ||
| appcommands.Run()" test || die "Test 19 failed" | ||
| # Registering using AddCmd instead of AddCmdFunc, now fail | ||
| $PYTHON -c "${IMPORTS} | ||
| class test(appcommands.Cmd): | ||
| def Run(self, argv): return 1 | ||
| def main(argv): | ||
| appcommands.AddCmd('test', test) | ||
| appcommands.Run()" test && die "Test 20 failed" | ||
| TEST=./appcommands_example.py | ||
| if test -s "${TEST}.py"; then | ||
| TEST="${TEST}.py" | ||
| elif test ! -s "${TEST}"; then | ||
| die "Could not locate ${TEST}" | ||
| fi | ||
| # Success | ||
| $PYTHON $TEST test1 >/dev/null 2>&1 || die "Test 21 failed" | ||
| $PYTHON $TEST test1|grep -q 'Command1' 2>&1 || die "Test 22 failed" | ||
| $PYTHON $TEST test2|grep -q 'Command2' 2>&1 || die "Test 23 failed" | ||
| $PYTHON $TEST test3|grep -q 'Command3' 2>&1 || die "Test 24 failed" | ||
| # Success, --nofail1 belongs to test1 | ||
| $PYTHON $TEST test1 --nofail1 >/dev/null 2>&1 || die "Test 25 failed" | ||
| # Failure, --fail1 | ||
| $PYTHON $TEST test1 --fail1 >/dev/null 2>&1 && die "Test 26 failed" | ||
| # Failure, --nofail1 does not belong to test2 | ||
| $PYTHON $TEST test2 --nofail1 >/dev/null 2>&1 && die "Test 27 failed" | ||
| # Failure, --nofail1 must appear after its command | ||
| $PYTHON $TEST --nofail1 test1 >/dev/null 2>&1 && die "Test 28 failed" | ||
| # Failure, explicit from --fail2 | ||
| $PYTHON $TEST test2 --fail2 >/dev/null 2>&1 && die "Test 29 failed" | ||
| # Success, --hint before command, foo shown with test1 | ||
| $PYTHON $TEST --hint 'XYZ' test1|grep -q "Hint1:'XYZ'" || die "Test 30 failed" | ||
| # Success, --hint before command, foo shown with test1 | ||
| $PYTHON $TEST test1 --hint 'XYZ'|grep -q "Hint1:'XYZ'" || die "Test 31 failed" | ||
| # Success, test1b --allhelp, modified _all_commands_help shown | ||
| $PYTHON $TEST test1b --allhelp|grep -q "AllHelp:'test1b short help'" || die "Test 32 failed" | ||
| # Failure, test1 --allhelp, modified _all_commands_help not shown | ||
| $PYTHON $TEST test1 --allhelp|grep -q "AllHelp:'test1b short help'" && die "Test 33 failed" | ||
| # Test for standard --help | ||
| $PYTHON $TEST --help|grep -q "following commands:" && die "Test 34 failed" | ||
| $PYTHON $TEST help|grep -q "following commands:" || die "Test 35 failed" | ||
| # No help after command | ||
| $PYTHON $TEST test1 --help|grep -q "following commands:" && die "Test 36 failed" | ||
| $PYTHON $TEST test1 --help 'XYZ'|grep -q "Hint1:'XYZ'" && die "Test 37 failed" | ||
| # Help specific to command: | ||
| $PYTHON $TEST --help test1|grep -q "following commands:" && die "Test 38 failed" | ||
| $PYTHON $TEST --help test1|grep -q "test1 *Help for test1" && die "Test 39 failed" | ||
| $PYTHON $TEST help test1|grep -q "following commands:" && die "Test 40 failed" | ||
| $PYTHON $TEST help test1|grep -q "test1, testalias1, testalias2" || die\ | ||
| "Test 41 failed" | ||
| $PYTHON $TEST help testalias1|grep -q "test1, testalias1, testalias2" || die\ | ||
| "Test 42 failed" | ||
| $PYTHON $TEST help testalias1|grep -q "[-]-foo" || die\ | ||
| "Test 43 failed" | ||
| $PYTHON $TEST help testalias2|grep -q "[-]-foo" || die\ | ||
| "Test 44 failed" | ||
| $PYTHON $TEST help test4|grep -q "^ *Help for test4" || die "Test 45 failed" | ||
| $PYTHON $TEST help testalias3|grep -q "^ *Help for test4" || die\ | ||
| "Test 46 failed" | ||
| # Help for cmds with all_command_help. | ||
| $PYTHON $TEST help|grep -q "Help for test1. As described by a docstring." || die "Test 47 failed" | ||
| $PYTHON $TEST help test1|grep -q "Help for test1. As described by a docstring." || die "Test 48 failed" | ||
| $PYTHON $TEST help|grep -q "test1b short help" || die "Test 49 failed" | ||
| $PYTHON $TEST help test1b|grep -q "test1b short help" && die "Test 50 failed" | ||
| $PYTHON $TEST help|grep -q "is my very favorite test" && die "Test 51 failed" | ||
| $PYTHON $TEST help test1b|grep -q "is my very favorite test" || die "Test 52 failed" | ||
| $PYTHON $TEST help|grep -q "Help for test4." && die "Test 53 failed" | ||
| $PYTHON $TEST help test4|grep -q "Help for test4." || die "Test 54 failed" | ||
| $PYTHON $TEST help|grep -q "replacetest4help" || die "Test 55 failed" | ||
| $PYTHON $TEST help test4|grep -q "replacetest4help" && die "Test 56 failed" | ||
| # Success, --hint before command, foo shown with test1 | ||
| $PYTHON $TEST --hint 'XYZ' --help|grep -q "following commands:" && die "Test 57 failed" | ||
| $PYTHON $TEST --hint 'XYZ' --help|grep -q "XYZ" && die "Test 58 failed" | ||
| $PYTHON $TEST --hint 'XYZ' --help|grep -q "This tool shows how" || die "Test 59 failed" | ||
| $PYTHON $TEST --hint 'XYZ' help|grep -q "following commands:" || die "Test 60 failed" | ||
| $PYTHON $TEST --hint 'XYZ' help|grep -q "XYZ" && die "Test 61 failed" | ||
| $PYTHON $TEST --hint 'XYZ' help|grep -q "This tool shows how" || die "Test 62 failed" | ||
| # A command name with an letters, numbers, or an underscore is fine | ||
| $PYTHON -c "${IMPORTS} | ||
| def test(argv): | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.AddCmdFunc('test_foo', test) | ||
| appcommands.AddCmdFunc('a123', test) | ||
| appcommands.Run()" test || die "Test 63 failed" | ||
| # A command name that starts with a non-alphanumeric characters is not ok | ||
| $PYTHON -c "${IMPORTS} | ||
| def test(argv): | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('123', test) | ||
| appcommands.Run()" 123 >/dev/null 2>&1 && die "Test 64 failed" | ||
| # A command name that contains other characters is not ok | ||
| $PYTHON -c "${IMPORTS} | ||
| def test(argv): | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test+1', test) | ||
| appcommands.Run()" "test+1" >/dev/null 2>&1 && die "Test 65 failed" | ||
| # If a command raises app.UsageError, usage is printed. | ||
| RES=`$PYTHON -c "${IMPORTS} | ||
| def test(argv): | ||
| '''Help1''' | ||
| raise app.UsageError('Ha-ha') | ||
| def main(argv): | ||
| appcommands.AddCmdFunc('test', test) | ||
| appcommands.Run()" test` && die "Test 66 failed" | ||
| echo "${RES}" | grep -q "USAGE: " || die "Test 67 failed" | ||
| echo "${RES}" | grep -q -E "(^| )test[ \t]+Help1($| )" || die "Test 68 failed" | ||
| echo "${RES}" | grep -q -E "(^| )Ha-ha($| )" || die "Test 69 failed" | ||
| $PYTHON -c "${IMPORTS} | ||
| class Test(appcommands.Cmd): | ||
| def Run(self, argv): return 0 | ||
| def test(*args, **kwargs): | ||
| return Test(*args, **kwargs) | ||
| def main(argv): | ||
| appcommands.AddCmd('test', test) | ||
| appcommands.Run()" test || die "Test 73 failed" | ||
| # Success, default command set and correctly run. | ||
| RES=`$PYTHON -c "${IMPORTS} | ||
| class test(appcommands.Cmd): | ||
| def Run(self, argv): | ||
| print 'test running correctly' | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmd('test', test) | ||
| appcommands.SetDefaultCommand('test') | ||
| appcommands.Run()"` || die "Test 74 failed" | ||
| echo "${RES}" | grep -q "test running correctly" || die "Test 75 failed" | ||
| # Failure, default command set but missing. | ||
| $PYTHON -c "${IMPORTS} | ||
| class test(appcommands.Cmd): | ||
| def Run(self, argv): | ||
| print 'test running correctly' | ||
| return 0 | ||
| def main(argv): | ||
| appcommands.AddCmd('test', test) | ||
| appcommands.SetDefaultCommand('missing') | ||
| appcommands.Run()" >/dev/null 2>&1 && die "Test 76 failed" | ||
| echo "PASS" |
| #! /bin/bash | ||
| # Copyright 2003 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| # | ||
| # Author: Douglas Greiman | ||
| # Owner: unittest-team@google.com | ||
| EXE=./basetest_test.py | ||
| function die { | ||
| echo "$1" | ||
| exit $2 | ||
| } | ||
| # Create directories for use | ||
| function MaybeMkdir { | ||
| for dir in $@; do | ||
| if [ ! -d "$dir" ] ; then | ||
| mkdir "$dir" || die "Unable to create $dir" | ||
| fi | ||
| done | ||
| } | ||
| # TODO(dborowitz): Clean these up if we die. | ||
| MaybeMkdir abc cba def fed ghi jkl | ||
| # Test assertListEqual, assertDictEqual, and assertSameElements | ||
| $EXE --testid=5 || die "Test 5 failed" $? | ||
| # Test assertAlmostEqual and assertNotAlmostEqual | ||
| $EXE --testid=6 || die "Test 6 failed" $? | ||
| # Test that tests marked as "expected failure" but which passes | ||
| # cause an overall failure. | ||
| $EXE --testid=7 && die "Test 7 passed unexpectedly" $? | ||
| output=$($EXE --testid=8 -- -v 2>&1) && die "Test 8 passed unexpectedly" $? | ||
| printf '%s\n' "$output" | ||
| grep '^FAILED (expected failures=1, unexpected successes=1)' <<<"$output" \ | ||
| && grep '^testDifferentExpectedFailure .* unexpected success' <<<"$output" \ | ||
| && grep '^testExpectedFailure .* expected failure' <<<"$output" \ | ||
| || die "Test 8 didn't write expected diagnostic" | ||
| # Invoke with no env vars and no flags | ||
| ( | ||
| unset TEST_RANDOM_SEED | ||
| unset TEST_SRCDIR | ||
| unset TEST_TMPDIR | ||
| $EXE --testid=1 | ||
| ) || die "Test 1 failed" $? | ||
| # Invoke with env vars but no flags | ||
| ( | ||
| export TEST_RANDOM_SEED=321 | ||
| export TEST_SRCDIR=cba | ||
| export TEST_TMPDIR=fed | ||
| $EXE --testid=2 | ||
| ) || die "Test 2 failed" $? | ||
| # Invoke with no env vars and all flags | ||
| ( | ||
| unset TEST_RANDOM_SEED | ||
| unset TEST_SRCDIR | ||
| unset TEST_TMPDIR | ||
| $EXE --testid=3 --test_random_seed=123 --test_srcdir=abc --test_tmpdir=def | ||
| ) || die "Test 3 failed" $? | ||
| # Invoke with env vars and all flags | ||
| ( | ||
| export TEST_RANDOM_SEED=321 | ||
| export TEST_SRCDIR=cba | ||
| export TEST_TMPDIR=fed | ||
| $EXE --testid=4 --test_random_seed=123 --test_srcdir=abc --test_tmpdir=def | ||
| ) || die "Test 4 failed" $? | ||
| # Cleanup | ||
| rm -r abc cba def fed ghi jkl | ||
| echo "Pass" |
| #!/usr/bin/env python | ||
| # Copyright 2010 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Tests for base google test functionality.""" | ||
| __author__ = 'dborowitz@google.com (Dave Borowitz)' | ||
| import os | ||
| import re | ||
| import string | ||
| import sys | ||
| import unittest | ||
| import gflags as flags | ||
| from google.apputils import basetest | ||
| PY_VERSION_2 = sys.version_info[0] == 2 | ||
| FLAGS = flags.FLAGS | ||
| flags.DEFINE_integer('testid', 0, 'Which test to run') | ||
| _OUTPUT_CAPTURING_CASES = [ | ||
| (basetest.CaptureTestStdout, basetest.DiffTestStdout, sys.stdout), | ||
| (basetest.CaptureTestStderr, basetest.DiffTestStderr, sys.stderr), | ||
| ] | ||
| class CaptureTestStdoutStderrTest(basetest.TestCase): | ||
| def setUp(self): | ||
| self.expected_filepath = os.path.join(FLAGS.test_tmpdir, 'expected_output') | ||
| def testStdoutCapturedSuccessfully(self): | ||
| for capture_output_fn, diff_output_fn, ostream in _OUTPUT_CAPTURING_CASES: | ||
| capture_output_fn() | ||
| ostream.write('This gets captured\n') | ||
| with open(self.expected_filepath, 'wb') as expected_file: | ||
| expected_file.write(b'This gets captured\n') | ||
| diff_output_fn(self.expected_filepath) # should do nothing | ||
| def testRaisesWhenCapturedStdoutDifferentThanExpected(self): | ||
| for capture_output_fn, diff_output_fn, ostream in _OUTPUT_CAPTURING_CASES: | ||
| capture_output_fn() | ||
| ostream.write('Correct captured.out\n') | ||
| with open(self.expected_filepath, 'wb') as expected_file: | ||
| expected_file.write(b'Incorrect captured.out\n') | ||
| self.assertRaises(basetest.OutputDifferedError, | ||
| diff_output_fn, self.expected_filepath) | ||
| def testStdoutNoLongerCapturedAfterDiffTest(self): | ||
| for capture_output_fn, diff_output_fn, ostream in _OUTPUT_CAPTURING_CASES: | ||
| with open(self.expected_filepath, 'wb') as expected_file: | ||
| expected_file.write(b'This goes to captured.out\n') | ||
| capture_output_fn() | ||
| ostream.write('This goes to captured.out\n') | ||
| diff_output_fn(self.expected_filepath) # should do nothing | ||
| ostream.write('This goes to stdout screen\n') | ||
| capture_output_fn() | ||
| ostream.write('This goes to captured.out\n') | ||
| diff_output_fn(self.expected_filepath) # should do nothing | ||
| def testCapturingTestStdoutReturnsContextManager(self): | ||
| for capture_output_fn, _, ostream in _OUTPUT_CAPTURING_CASES: | ||
| with open(self.expected_filepath, 'wb') as expected_file: | ||
| expected_file.write(b'This goes to captured.out\n') | ||
| ostream.write('This goes to stdout screen\n') | ||
| with capture_output_fn( | ||
| expected_output_filepath=self.expected_filepath): | ||
| ostream.write('This goes to captured.out\n') | ||
| class GoogleTestBaseUnitTest(basetest.TestCase): | ||
| def setUp(self): | ||
| self._orig_test_diff = os.environ.pop('TEST_DIFF', None) | ||
| self.data1_file = os.path.join(FLAGS.test_tmpdir, 'provided_1.dat') | ||
| self.data2_file = os.path.join(FLAGS.test_tmpdir, 'provided_2.dat') | ||
| def tearDown(self): | ||
| if self._orig_test_diff is not None: | ||
| os.environ['TEST_DIFF'] = self._orig_test_diff | ||
| def test_Diff_SameData(self): | ||
| """Tests for the internal _Diff method.""" | ||
| basetest._WriteTestData('a\nb\n', self.data1_file) | ||
| basetest._WriteTestData('a\nb\n', self.data2_file) | ||
| # This must not raise an exception: | ||
| basetest._Diff(self.data1_file, self.data2_file) | ||
| @unittest.skipIf(not os.path.exists('/usr/bin/diff'), | ||
| 'requires /usr/bin/diff') | ||
| def test_Diff_SameData_ExternalDiff(self): | ||
| """Test the internal _Diff method when TEST_DIFF is in the env.""" | ||
| os.environ['TEST_DIFF'] = '/usr/bin/diff' | ||
| basetest._WriteTestData('b\n', self.data1_file) | ||
| basetest._WriteTestData('b\n', self.data2_file) | ||
| # This must not raise an exception: | ||
| basetest._Diff(self.data1_file, self.data2_file) | ||
| @unittest.skipIf(not os.path.exists('/usr/bin/diff'), | ||
| 'requires /usr/bin/diff') | ||
| def test_Diff_MissingFile_ExternalDiff(self): | ||
| """Test the internal _Diff method on TEST_DIFF error.""" | ||
| os.environ['TEST_DIFF'] = '/usr/bin/diff' | ||
| basetest._WriteTestData('a\n', self.data1_file) | ||
| if os.path.exists(self.data2_file): | ||
| os.unlink(self.data2_file) # Be 100% sure this does not exist. | ||
| # This depends on /usr/bin/diff returning an exit code greater than 1 | ||
| # when an input file is missing. It has had this behavior forever. | ||
| with self.assertRaises(basetest.DiffFailureError) as error_context: | ||
| basetest._Diff(self.data1_file, self.data2_file) | ||
| def test_Diff_MissingExternalDiff(self): | ||
| """Test the internal _Diff when TEST_DIFF program is non-existant.""" | ||
| os.environ['TEST_DIFF'] = self.data1_file | ||
| if os.path.exists(self.data1_file): | ||
| os.unlink(self.data1_file) # Be 100% sure this does not exist | ||
| with self.assertRaises(basetest.DiffFailureError) as error_context: | ||
| basetest._Diff(self.data2_file, self.data2_file) | ||
| def test_Diff_Exception(self): | ||
| """Test that _Diff includes the delta in the error msg.""" | ||
| basetest._WriteTestData(b'01: text A\n02: text B\n03: C', self.data1_file) | ||
| basetest._WriteTestData(b'01: text A\n02: zzzzzz\n03: C', self.data2_file) | ||
| with self.assertRaises(basetest.OutputDifferedError) as error_context: | ||
| basetest._Diff(self.data1_file, self.data2_file) | ||
| # Check that both filenames and some semblance of a unified diff | ||
| # are present in the exception error message. | ||
| diff_error_message = str(error_context.exception) | ||
| self.assertIn('provided_1', diff_error_message) | ||
| self.assertIn('provided_2', diff_error_message) | ||
| self.assertIn('@@', diff_error_message) | ||
| self.assertIn('02: text B', diff_error_message) | ||
| @unittest.skipIf(not os.path.exists('/usr/bin/diff'), | ||
| 'requires /usr/bin/diff') | ||
| def test_Diff_Exception_ExternalDiff(self): | ||
| """Test that _Diff executes TEST_DIFF when supplied and there are diffs.""" | ||
| os.environ['TEST_DIFF'] = '/usr/bin/diff' | ||
| basetest._WriteTestData(b'01: text A\n02: text B\n03: C', self.data1_file) | ||
| basetest._WriteTestData(b'01: text A\n02: zzzzzz\n03: C', self.data2_file) | ||
| with self.assertRaises(basetest.OutputDifferedError) as error_context: | ||
| basetest._Diff(self.data1_file, self.data2_file) | ||
| # Check that both filenames and the TEST_DIFF command | ||
| # are present in the exception error message. | ||
| diff_error_message = str(error_context.exception) | ||
| self.assertIn('/usr/bin/diff', diff_error_message) | ||
| self.assertIn('provided_1', diff_error_message) | ||
| self.assertIn('provided_2', diff_error_message) | ||
| def testDiffTestStrings(self): | ||
| basetest.DiffTestStrings('a', 'a') | ||
| with self.assertRaises(basetest.OutputDifferedError): | ||
| basetest.DiffTestStrings( | ||
| '-2: a message\n-2: another message\n', | ||
| '-2: a message\n-2: another message \n') | ||
| self.assertRaises(basetest.DiffFailureError, basetest.DiffTestStringFile, | ||
| 'a message', 'txt.a message not existant file here') | ||
| self.assertRaises(basetest.OutputDifferedError, basetest.DiffTestStringFile, | ||
| 'message', os.devnull) | ||
| def testFlags(self): | ||
| if FLAGS.testid == 1: | ||
| self.assertEqual(FLAGS.test_random_seed, 301) | ||
| self.assert_(FLAGS.test_tmpdir.startswith('/')) | ||
| self.assert_(os.access(FLAGS.test_tmpdir, os.W_OK)) | ||
| elif FLAGS.testid == 2: | ||
| self.assertEqual(FLAGS.test_random_seed, 321) | ||
| self.assertEqual(FLAGS.test_srcdir, 'cba') | ||
| self.assertEqual(FLAGS.test_tmpdir, 'fed') | ||
| elif FLAGS.testid == 3: | ||
| self.assertEqual(FLAGS.test_random_seed, 123) | ||
| self.assertEqual(FLAGS.test_srcdir, 'abc') | ||
| self.assertEqual(FLAGS.test_tmpdir, 'def') | ||
| elif FLAGS.testid == 4: | ||
| self.assertEqual(FLAGS.test_random_seed, 123) | ||
| self.assertEqual(FLAGS.test_srcdir, 'abc') | ||
| self.assertEqual(FLAGS.test_tmpdir, 'def') | ||
| def testAssertIn(self): | ||
| animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} | ||
| self.assertIn('a', 'abc') | ||
| self.assertIn(2, [1, 2, 3]) | ||
| self.assertIn('monkey', animals) | ||
| self.assertNotIn('d', 'abc') | ||
| self.assertNotIn(0, [1, 2, 3]) | ||
| self.assertNotIn('otter', animals) | ||
| self.assertRaises(AssertionError, self.assertIn, 'x', 'abc') | ||
| self.assertRaises(AssertionError, self.assertIn, 4, [1, 2, 3]) | ||
| self.assertRaises(AssertionError, self.assertIn, 'elephant', animals) | ||
| self.assertRaises(AssertionError, self.assertNotIn, 'c', 'abc') | ||
| self.assertRaises(AssertionError, self.assertNotIn, 1, [1, 2, 3]) | ||
| self.assertRaises(AssertionError, self.assertNotIn, 'cow', animals) | ||
| @basetest.unittest.expectedFailure | ||
| def testExpectedFailure(self): | ||
| if FLAGS.testid == 7: | ||
| self.assertEqual(1, 1) # expected failure, got success | ||
| else: | ||
| self.assertEqual(1, 2) # the expected failure | ||
| @basetest.unittest.expectedFailure | ||
| def testDifferentExpectedFailure(self): | ||
| if FLAGS.testid == 8: | ||
| self.assertEqual(1, 1) # expected failure, got success | ||
| else: | ||
| self.assertEqual(1, 2) # the expected failure | ||
| def testAssertEqual(self): | ||
| if FLAGS.testid != 5: | ||
| return | ||
| self.assertListEqual([], []) | ||
| self.assertTupleEqual((), ()) | ||
| self.assertSequenceEqual([], ()) | ||
| a = [0, 'a', []] | ||
| b = [] | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertListEqual, a, b) | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertListEqual, tuple(a), tuple(b)) | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertSequenceEqual, a, tuple(b)) | ||
| b.extend(a) | ||
| self.assertListEqual(a, b) | ||
| self.assertTupleEqual(tuple(a), tuple(b)) | ||
| self.assertSequenceEqual(a, tuple(b)) | ||
| self.assertSequenceEqual(tuple(a), b) | ||
| self.assertRaises(AssertionError, self.assertListEqual, a, tuple(b)) | ||
| self.assertRaises(AssertionError, self.assertTupleEqual, tuple(a), b) | ||
| self.assertRaises(AssertionError, self.assertListEqual, None, b) | ||
| self.assertRaises(AssertionError, self.assertTupleEqual, None, tuple(b)) | ||
| self.assertRaises(AssertionError, self.assertSequenceEqual, None, tuple(b)) | ||
| self.assertRaises(AssertionError, self.assertListEqual, 1, 1) | ||
| self.assertRaises(AssertionError, self.assertTupleEqual, 1, 1) | ||
| self.assertRaises(AssertionError, self.assertSequenceEqual, 1, 1) | ||
| self.assertSameElements([1, 2, 3], [3, 2, 1]) | ||
| self.assertSameElements([1, 2] + [3] * 100, [1] * 100 + [2, 3]) | ||
| self.assertSameElements(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) | ||
| self.assertRaises(AssertionError, self.assertSameElements, [10], [10, 11]) | ||
| self.assertRaises(AssertionError, self.assertSameElements, [10, 11], [10]) | ||
| # Test that sequences of unhashable objects can be tested for sameness: | ||
| self.assertSameElements([[1, 2], [3, 4]], [[3, 4], [1, 2]]) | ||
| if PY_VERSION_2: | ||
| # dict's are no longer valid for < comparison in Python 3 making them | ||
| # unsortable (yay, sanity!). But we need to preserve this old behavior | ||
| # when running under Python 2. | ||
| self.assertSameElements([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) | ||
| self.assertRaises(AssertionError, self.assertSameElements, [[1]], [[2]]) | ||
| def testAssertItemsEqualHotfix(self): | ||
| """Confirm that http://bugs.python.org/issue14832 - b/10038517 is gone.""" | ||
| for assert_items_method in (self.assertItemsEqual, self.assertCountEqual): | ||
| with self.assertRaises(self.failureException) as error_context: | ||
| assert_items_method([4], [2]) | ||
| error_message = str(error_context.exception) | ||
| # Confirm that the bug is either no longer present in Python or that our | ||
| # assertItemsEqual patching version of the method in basetest.TestCase | ||
| # doesn't get used. | ||
| self.assertIn('First has 1, Second has 0: 4', error_message) | ||
| self.assertIn('First has 0, Second has 1: 2', error_message) | ||
| def testAssertDictEqual(self): | ||
| self.assertDictEqual({}, {}) | ||
| c = {'x': 1} | ||
| d = {} | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictEqual, c, d) | ||
| d.update(c) | ||
| self.assertDictEqual(c, d) | ||
| d['x'] = 0 | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictEqual, c, d, 'These are unequal') | ||
| self.assertRaises(AssertionError, self.assertDictEqual, None, d) | ||
| self.assertRaises(AssertionError, self.assertDictEqual, [], d) | ||
| self.assertRaises(AssertionError, self.assertDictEqual, 1, 1) | ||
| try: | ||
| # Ensure we use equality as the sole measure of elements, not type, since | ||
| # that is consistent with dict equality. | ||
| self.assertDictEqual({1: 1.0, 2: 2}, {1: 1, 2: 3}) | ||
| except AssertionError, e: | ||
| self.assertMultiLineEqual('{1: 1.0, 2: 2} != {1: 1, 2: 3}\n' | ||
| 'repr() of differing entries:\n2: 2 != 3\n', | ||
| str(e)) | ||
| try: | ||
| self.assertDictEqual({}, {'x': 1}) | ||
| except AssertionError, e: | ||
| self.assertMultiLineEqual("{} != {'x': 1}\n" | ||
| "Unexpected, but present entries:\n'x': 1\n", | ||
| str(e)) | ||
| else: | ||
| self.fail('Expecting AssertionError') | ||
| try: | ||
| self.assertDictEqual({}, {'x': 1}, 'a message') | ||
| except AssertionError, e: | ||
| self.assertIn('a message', str(e)) | ||
| else: | ||
| self.fail('Expecting AssertionError') | ||
| expected = {'a': 1, 'b': 2, 'c': 3} | ||
| seen = {'a': 2, 'c': 3, 'd': 4} | ||
| try: | ||
| self.assertDictEqual(expected, seen) | ||
| except AssertionError, e: | ||
| self.assertMultiLineEqual("""\ | ||
| {'a': 1, 'b': 2, 'c': 3} != {'a': 2, 'c': 3, 'd': 4} | ||
| Unexpected, but present entries: | ||
| 'd': 4 | ||
| repr() of differing entries: | ||
| 'a': 1 != 2 | ||
| Missing entries: | ||
| 'b': 2 | ||
| """, str(e)) | ||
| else: | ||
| self.fail('Expecting AssertionError') | ||
| self.assertRaises(AssertionError, self.assertDictEqual, (1, 2), {}) | ||
| self.assertRaises(AssertionError, self.assertDictEqual, {}, (1, 2)) | ||
| # Ensure deterministic output of keys in dictionaries whose sort order | ||
| # doesn't match the lexical ordering of repr -- this is most Python objects, | ||
| # which are keyed by memory address. | ||
| class Obj(object): | ||
| def __init__(self, name): | ||
| self.name = name | ||
| def __repr__(self): | ||
| return self.name | ||
| try: | ||
| self.assertDictEqual( | ||
| {'a': Obj('A'), Obj('b'): Obj('B'), Obj('c'): Obj('C')}, | ||
| {'a': Obj('A'), Obj('d'): Obj('D'), Obj('e'): Obj('E')}) | ||
| except AssertionError, e: | ||
| # Do as best we can not to be misleading when objects have the same repr | ||
| # but aren't equal. | ||
| err_str = str(e) | ||
| self.assertStartsWith(err_str, | ||
| "{'a': A, b: B, c: C} != {'a': A, d: D, e: E}\n") | ||
| self.assertRegexpMatches(err_str, | ||
| r'(?ms).*^Unexpected, but present entries:\s+' | ||
| r'^(d: D$\s+^e: E|e: E$\s+^d: D)$') | ||
| self.assertRegexpMatches(err_str, | ||
| r'(?ms).*^repr\(\) of differing entries:\s+' | ||
| r'^.a.: A != A$', err_str) | ||
| self.assertRegexpMatches(err_str, | ||
| r'(?ms).*^Missing entries:\s+' | ||
| r'^(b: B$\s+^c: C|c: C$\s+^b: B)$') | ||
| else: | ||
| self.fail('Expecting AssertionError') | ||
| # Confirm that safe_repr, not repr, is being used. | ||
| class RaisesOnRepr(object): | ||
| def __repr__(self): | ||
| return 1/0 # Intentionally broken __repr__ implementation. | ||
| try: | ||
| self.assertDictEqual( | ||
| {RaisesOnRepr(): RaisesOnRepr()}, | ||
| {RaisesOnRepr(): RaisesOnRepr()} | ||
| ) | ||
| self.fail('Expected dicts not to match') | ||
| except AssertionError as e: | ||
| # Depending on the testing environment, the object may get a __main__ | ||
| # prefix or a basetest_test prefix, so strip that for comparison. | ||
| error_msg = re.sub( | ||
| r'( at 0x[^>]+)|__main__\.|basetest_test\.', '', str(e)) | ||
| self.assertRegexpMatches(error_msg, """(?m)\ | ||
| {<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>} != \ | ||
| {<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>} | ||
| Unexpected, but present entries: | ||
| <.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*> | ||
| Missing entries: | ||
| <.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*> | ||
| """) | ||
| # Confirm that safe_repr, not repr, is being used. | ||
| class RaisesOnLt(object): | ||
| def __lt__(self): | ||
| raise TypeError('Object is unordered.') | ||
| def __repr__(self): | ||
| return '<RaisesOnLt object>' | ||
| try: | ||
| self.assertDictEqual( | ||
| {RaisesOnLt(): RaisesOnLt()}, | ||
| {RaisesOnLt(): RaisesOnLt()}) | ||
| except AssertionError as e: | ||
| self.assertIn('Unexpected, but present entries:\n<RaisesOnLt', str(e)) | ||
| self.assertIn('Missing entries:\n<RaisesOnLt', str(e)) | ||
| def testAssertSetEqual(self): | ||
| set1 = set() | ||
| set2 = set() | ||
| self.assertSetEqual(set1, set2) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, None, set2) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, [], set2) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, None) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, []) | ||
| set1 = set(['a']) | ||
| set2 = set() | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, set2) | ||
| set1 = set(['a']) | ||
| set2 = set(['a']) | ||
| self.assertSetEqual(set1, set2) | ||
| set1 = set(['a']) | ||
| set2 = set(['a', 'b']) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, set2) | ||
| set1 = set(['a']) | ||
| set2 = frozenset(['a', 'b']) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, set2) | ||
| set1 = set(['a', 'b']) | ||
| set2 = frozenset(['a', 'b']) | ||
| self.assertSetEqual(set1, set2) | ||
| set1 = set() | ||
| set2 = 'foo' | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, set2) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set2, set1) | ||
| # make sure any string formatting is tuple-safe | ||
| set1 = set([(0, 1), (2, 3)]) | ||
| set2 = set([(4, 5)]) | ||
| self.assertRaises(AssertionError, self.assertSetEqual, set1, set2) | ||
| def testAssertDictContainsSubset(self): | ||
| self.assertDictContainsSubset({}, {}) | ||
| self.assertDictContainsSubset({}, {'a': 1}) | ||
| self.assertDictContainsSubset({'a': 1}, {'a': 1}) | ||
| self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) | ||
| self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictContainsSubset, {'a': 2}, {'a': 1}, | ||
| '.*Mismatched values:.*') | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictContainsSubset, {'c': 1}, {'a': 1}, | ||
| '.*Missing:.*') | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictContainsSubset, {'a': 1, 'c': 1}, {'a': 1}, | ||
| '.*Missing:.*') | ||
| self.assertRaises(basetest.TestCase.failureException, | ||
| self.assertDictContainsSubset, {'a': 1, 'c': 1}, {'a': 1}, | ||
| '.*Missing:.*Mismatched values:.*') | ||
| def testAssertContainsSubset(self): | ||
| # sets, lists, tuples, dicts all ok. Types of set and subset do not have to | ||
| # match. | ||
| actual = ('a', 'b', 'c') | ||
| self.assertContainsSubset({'a', 'b'}, actual) | ||
| self.assertContainsSubset(('b', 'c'), actual) | ||
| self.assertContainsSubset({'b': 1, 'c': 2}, list(actual)) | ||
| self.assertContainsSubset(['c', 'a'], set(actual)) | ||
| self.assertContainsSubset([], set()) | ||
| self.assertContainsSubset([], {'a': 1}) | ||
| self.assertRaises(AssertionError, self.assertContainsSubset, ('d',), actual) | ||
| self.assertRaises(AssertionError, self.assertContainsSubset, ['d'], | ||
| set(actual)) | ||
| self.assertRaises(AssertionError, self.assertContainsSubset, {'a': 1}, []) | ||
| self.assertRaisesWithRegexpMatch(AssertionError, 'Missing elements', | ||
| self.assertContainsSubset, {1, 2, 3}, | ||
| {1, 2}) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, 'Custom message: Missing elements', | ||
| self.assertContainsSubset, {1, 2}, {1}, 'Custom message') | ||
| def testAssertNoCommonElements(self): | ||
| actual = ('a', 'b', 'c') | ||
| self.assertNoCommonElements((), actual) | ||
| self.assertNoCommonElements(('d', 'e'), actual) | ||
| self.assertNoCommonElements({'d', 'e'}, actual) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, 'Custom message: Common elements', | ||
| self.assertNoCommonElements, {1, 2}, {1}, 'Custom message') | ||
| with self.assertRaises(AssertionError): | ||
| self.assertNoCommonElements(['a'], actual) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertNoCommonElements({'a', 'b', 'c'}, actual) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertNoCommonElements({'b', 'c'}, set(actual)) | ||
| def testAssertAlmostEqual(self): | ||
| if FLAGS.testid != 6: | ||
| return | ||
| self.assertAlmostEqual(1.00000001, 1.0) | ||
| self.assertNotAlmostEqual(1.0000001, 1.0) | ||
| def testAssertAlmostEqualsWithDelta(self): | ||
| self.assertAlmostEquals(3.14, 3, delta=0.2) | ||
| self.assertAlmostEquals(2.81, 3.14, delta=1) | ||
| self.assertAlmostEquals(-1, 1, delta=3) | ||
| self.assertRaises(AssertionError, self.assertAlmostEquals, | ||
| 3.14, 2.81, delta=0.1) | ||
| self.assertRaises(AssertionError, self.assertAlmostEquals, | ||
| 1, 2, delta=0.5) | ||
| self.assertNotAlmostEquals(3.14, 2.81, delta=0.1) | ||
| def testGetCommandString_listOfStringArgument(self): | ||
| expected = "'command' 'arg-0'" | ||
| observed = basetest.GetCommandString(['command', 'arg-0']) | ||
| self.assertEqual(expected, observed) | ||
| def testGetCommandString_listOfUnicodeStringArgument(self): | ||
| expected = "'command' 'arg-0'" | ||
| observed = basetest.GetCommandString([u'command', u'arg-0']) | ||
| self.assertEqual(expected, observed) | ||
| def testGetCommandString_stringArgument(self): | ||
| expected = 'command arg-0' | ||
| observed = basetest.GetCommandString('command arg-0') | ||
| self.assertEqual(expected, observed) | ||
| def testGetCommandString_unicodeStringArgument(self): | ||
| expected = 'command arg-0' | ||
| observed = basetest.GetCommandString(u'command arg-0') | ||
| self.assertEqual(expected, observed) | ||
| def testAssertStartsWith(self): | ||
| self.assertStartsWith('foobar', 'foo') | ||
| self.assertStartsWith('foobar', 'foobar') | ||
| self.assertRaises(AssertionError, self.assertStartsWith, 'foobar', 'bar') | ||
| self.assertRaises(AssertionError, self.assertStartsWith, 'foobar', 'blah') | ||
| def testAssertNotStartsWith(self): | ||
| self.assertNotStartsWith('foobar', 'bar') | ||
| self.assertNotStartsWith('foobar', 'blah') | ||
| self.assertRaises(AssertionError, self.assertNotStartsWith, 'foobar', 'foo') | ||
| self.assertRaises(AssertionError, self.assertNotStartsWith, 'foobar', | ||
| 'foobar') | ||
| def testAssertEndsWith(self): | ||
| self.assertEndsWith('foobar', 'bar') | ||
| self.assertEndsWith('foobar', 'foobar') | ||
| self.assertRaises(AssertionError, self.assertEndsWith, 'foobar', 'foo') | ||
| self.assertRaises(AssertionError, self.assertEndsWith, 'foobar', 'blah') | ||
| def testAssertNotEndsWith(self): | ||
| self.assertNotEndsWith('foobar', 'foo') | ||
| self.assertNotEndsWith('foobar', 'blah') | ||
| self.assertRaises(AssertionError, self.assertNotEndsWith, 'foobar', 'bar') | ||
| self.assertRaises(AssertionError, self.assertNotEndsWith, 'foobar', | ||
| 'foobar') | ||
| def testAssertRegexMatch_matches(self): | ||
| self.assertRegexMatch('str', ['str']) | ||
| def testAssertRegexMatch_matchesSubstring(self): | ||
| self.assertRegexMatch('pre-str-post', ['str']) | ||
| def testAssertRegexMatch_multipleRegexMatches(self): | ||
| self.assertRegexMatch('str', ['rts', 'str']) | ||
| def testAssertRegexMatch_emptyListFails(self): | ||
| expected_re = re.compile(r'No regexes specified\.', re.MULTILINE) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| expected_re, | ||
| self.assertRegexMatch, | ||
| 'str', | ||
| regexes=[]) | ||
| def testAssertRegexMatch_badArguments(self): | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| 'regexes is a string;.*', | ||
| self.assertRegexMatch, '1.*2', '1 2') | ||
| def testAssertRegexMatch_unicodeVsBytes(self): | ||
| """Ensure proper utf-8 encoding or decoding happens automatically.""" | ||
| self.assertRegexMatch(u'str', [b'str']) | ||
| self.assertRegexMatch(b'str', [u'str']) | ||
| def testAssertRegexMatch_unicode(self): | ||
| self.assertRegexMatch(u'foo str', [u'str']) | ||
| def testAssertRegexMatch_bytes(self): | ||
| self.assertRegexMatch(b'foo str', [b'str']) | ||
| def testAssertRegexMatch_allTheSameType(self): | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, 'regexes .* same type', | ||
| self.assertRegexMatch, 'foo str', [b'str', u'foo']) | ||
| def testAssertCommandFailsStderr(self): | ||
| # TODO(user): Gross! These should use sys.executable instead of | ||
| # depending on /usr/bin/perl existing. | ||
| self.assertCommandFails( | ||
| ['/usr/bin/perl', '-e', 'die "FAIL";'], | ||
| [r'(.|\n)*FAIL at -e line 1\.']) | ||
| def testAssertCommandFailsWithListOfString(self): | ||
| self.assertCommandFails(['false'], ['']) | ||
| def testAssertCommandFailsWithListOfUnicodeString(self): | ||
| self.assertCommandFails([u'false'], ['']) | ||
| def testAssertCommandFailsWithUnicodeString(self): | ||
| self.assertCommandFails(u'false', [u'']) | ||
| def testAssertCommandFailsWithUnicodeStringBytesRegex(self): | ||
| self.assertCommandFails(u'false', [b'']) | ||
| def testAssertCommandSucceedsStderr(self): | ||
| expected_re = re.compile(r'(.|\n)*FAIL at -e line 1\.', re.MULTILINE) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| expected_re, | ||
| self.assertCommandSucceeds, | ||
| ['/usr/bin/perl', '-e', 'die "FAIL";']) | ||
| def testAssertCommandSucceedsWithMatchingUnicodeRegexes(self): | ||
| self.assertCommandSucceeds(['echo', 'SUCCESS'], regexes=[u'SUCCESS']) | ||
| def testAssertCommandSucceedsWithMatchingBytesRegexes(self): | ||
| self.assertCommandSucceeds(['echo', 'SUCCESS'], regexes=[b'SUCCESS']) | ||
| def testAssertCommandSucceedsWithNonMatchingRegexes(self): | ||
| expected_re = re.compile(r'Running command', re.MULTILINE) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| expected_re, | ||
| self.assertCommandSucceeds, | ||
| ['echo', 'FAIL'], | ||
| regexes=['SUCCESS']) | ||
| def testAssertCommandSucceedsWithListOfString(self): | ||
| self.assertCommandSucceeds(['true']) | ||
| def testAssertCommandSucceedsWithListOfUnicodeString(self): | ||
| self.assertCommandSucceeds([u'true']) | ||
| def testAssertCommandSucceedsWithUnicodeString(self): | ||
| self.assertCommandSucceeds(u'true') | ||
| def testInequality(self): | ||
| # Try ints | ||
| self.assertGreater(2, 1) | ||
| self.assertGreaterEqual(2, 1) | ||
| self.assertGreaterEqual(1, 1) | ||
| self.assertLess(1, 2) | ||
| self.assertLessEqual(1, 2) | ||
| self.assertLessEqual(1, 1) | ||
| self.assertRaises(AssertionError, self.assertGreater, 1, 2) | ||
| self.assertRaises(AssertionError, self.assertGreater, 1, 1) | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, 1, 2) | ||
| self.assertRaises(AssertionError, self.assertLess, 2, 1) | ||
| self.assertRaises(AssertionError, self.assertLess, 1, 1) | ||
| self.assertRaises(AssertionError, self.assertLessEqual, 2, 1) | ||
| # Try Floats | ||
| self.assertGreater(1.1, 1.0) | ||
| self.assertGreaterEqual(1.1, 1.0) | ||
| self.assertGreaterEqual(1.0, 1.0) | ||
| self.assertLess(1.0, 1.1) | ||
| self.assertLessEqual(1.0, 1.1) | ||
| self.assertLessEqual(1.0, 1.0) | ||
| self.assertRaises(AssertionError, self.assertGreater, 1.0, 1.1) | ||
| self.assertRaises(AssertionError, self.assertGreater, 1.0, 1.0) | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, 1.0, 1.1) | ||
| self.assertRaises(AssertionError, self.assertLess, 1.1, 1.0) | ||
| self.assertRaises(AssertionError, self.assertLess, 1.0, 1.0) | ||
| self.assertRaises(AssertionError, self.assertLessEqual, 1.1, 1.0) | ||
| # Try Strings | ||
| self.assertGreater('bug', 'ant') | ||
| self.assertGreaterEqual('bug', 'ant') | ||
| self.assertGreaterEqual('ant', 'ant') | ||
| self.assertLess('ant', 'bug') | ||
| self.assertLessEqual('ant', 'bug') | ||
| self.assertLessEqual('ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertGreater, 'ant', 'bug') | ||
| self.assertRaises(AssertionError, self.assertGreater, 'ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, 'ant', 'bug') | ||
| self.assertRaises(AssertionError, self.assertLess, 'bug', 'ant') | ||
| self.assertRaises(AssertionError, self.assertLess, 'ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertLessEqual, 'bug', 'ant') | ||
| # Try Unicode | ||
| self.assertGreater(u'bug', u'ant') | ||
| self.assertGreaterEqual(u'bug', u'ant') | ||
| self.assertGreaterEqual(u'ant', u'ant') | ||
| self.assertLess(u'ant', u'bug') | ||
| self.assertLessEqual(u'ant', u'bug') | ||
| self.assertLessEqual(u'ant', u'ant') | ||
| self.assertRaises(AssertionError, self.assertGreater, u'ant', u'bug') | ||
| self.assertRaises(AssertionError, self.assertGreater, u'ant', u'ant') | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, u'ant', u'bug') | ||
| self.assertRaises(AssertionError, self.assertLess, u'bug', u'ant') | ||
| self.assertRaises(AssertionError, self.assertLess, u'ant', u'ant') | ||
| self.assertRaises(AssertionError, self.assertLessEqual, u'bug', u'ant') | ||
| # Try Mixed String/Unicode | ||
| self.assertGreater('bug', u'ant') | ||
| self.assertGreater(u'bug', 'ant') | ||
| self.assertGreaterEqual('bug', u'ant') | ||
| self.assertGreaterEqual(u'bug', 'ant') | ||
| self.assertGreaterEqual('ant', u'ant') | ||
| self.assertGreaterEqual(u'ant', 'ant') | ||
| self.assertLess('ant', u'bug') | ||
| self.assertLess(u'ant', 'bug') | ||
| self.assertLessEqual('ant', u'bug') | ||
| self.assertLessEqual(u'ant', 'bug') | ||
| self.assertLessEqual('ant', u'ant') | ||
| self.assertLessEqual(u'ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertGreater, 'ant', u'bug') | ||
| self.assertRaises(AssertionError, self.assertGreater, u'ant', 'bug') | ||
| self.assertRaises(AssertionError, self.assertGreater, 'ant', u'ant') | ||
| self.assertRaises(AssertionError, self.assertGreater, u'ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, 'ant', u'bug') | ||
| self.assertRaises(AssertionError, self.assertGreaterEqual, u'ant', 'bug') | ||
| self.assertRaises(AssertionError, self.assertLess, 'bug', u'ant') | ||
| self.assertRaises(AssertionError, self.assertLess, u'bug', 'ant') | ||
| self.assertRaises(AssertionError, self.assertLess, 'ant', u'ant') | ||
| self.assertRaises(AssertionError, self.assertLess, u'ant', 'ant') | ||
| self.assertRaises(AssertionError, self.assertLessEqual, 'bug', u'ant') | ||
| self.assertRaises(AssertionError, self.assertLessEqual, u'bug', 'ant') | ||
| def testAssertMultiLineEqual(self): | ||
| sample_text = """\ | ||
| http://www.python.org/doc/2.3/lib/module-unittest.html | ||
| test case | ||
| A test case is the smallest unit of testing. [...] | ||
| """ | ||
| revised_sample_text = """\ | ||
| http://www.python.org/doc/2.4.1/lib/module-unittest.html | ||
| test case | ||
| A test case is the smallest unit of testing. [...] You may provide your | ||
| own implementation that does not subclass from TestCase, of course. | ||
| """ | ||
| sample_text_error = """ | ||
| - http://www.python.org/doc/2.3/lib/module-unittest.html | ||
| ? ^ | ||
| + http://www.python.org/doc/2.4.1/lib/module-unittest.html | ||
| ? ^^^ | ||
| test case | ||
| - A test case is the smallest unit of testing. [...] | ||
| + A test case is the smallest unit of testing. [...] You may provide your | ||
| ? +++++++++++++++++++++ | ||
| + own implementation that does not subclass from TestCase, of course. | ||
| """ | ||
| for type1 in (str, unicode): | ||
| for type2 in (str, unicode): | ||
| self.assertRaisesWithLiteralMatch(AssertionError, sample_text_error, | ||
| self.assertMultiLineEqual, | ||
| type1(sample_text), | ||
| type2(revised_sample_text)) | ||
| self.assertRaises(AssertionError, self.assertMultiLineEqual, (1, 2), 'str') | ||
| self.assertRaises(AssertionError, self.assertMultiLineEqual, 'str', (1, 2)) | ||
| def testAssertMultiLineEqualAddsNewlinesIfNeeded(self): | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, | ||
| '\n' | ||
| ' line1\n' | ||
| '- line2\n' | ||
| '? ^\n' | ||
| '+ line3\n' | ||
| '? ^\n', | ||
| self.assertMultiLineEqual, | ||
| 'line1\n' | ||
| 'line2', | ||
| 'line1\n' | ||
| 'line3') | ||
| def testAssertMultiLineEqualShowsMissingNewlines(self): | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, | ||
| '\n' | ||
| ' line1\n' | ||
| '- line2\n' | ||
| '? -\n' | ||
| '+ line2\n', | ||
| self.assertMultiLineEqual, | ||
| 'line1\n' | ||
| 'line2\n', | ||
| 'line1\n' | ||
| 'line2') | ||
| def testAssertMultiLineEqualShowsExtraNewlines(self): | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, | ||
| '\n' | ||
| ' line1\n' | ||
| '- line2\n' | ||
| '+ line2\n' | ||
| '? +\n', | ||
| self.assertMultiLineEqual, | ||
| 'line1\n' | ||
| 'line2', | ||
| 'line1\n' | ||
| 'line2\n') | ||
| def testAssertIsNone(self): | ||
| self.assertIsNone(None) | ||
| self.assertRaises(AssertionError, self.assertIsNone, False) | ||
| self.assertIsNotNone('Google') | ||
| self.assertRaises(AssertionError, self.assertIsNotNone, None) | ||
| self.assertRaises(AssertionError, self.assertIsNone, (1, 2)) | ||
| def testAssertIs(self): | ||
| self.assertIs(object, object) | ||
| self.assertRaises(AssertionError, self.assertIsNot, object, object) | ||
| self.assertIsNot(True, False) | ||
| self.assertRaises(AssertionError, self.assertIs, True, False) | ||
| def testAssertBetween(self): | ||
| self.assertBetween(3.14, 3.1, 3.141) | ||
| self.assertBetween(4, 4, 1e10000) | ||
| self.assertBetween(9.5, 9.4, 9.5) | ||
| self.assertBetween(-1e10, -1e10000, 0) | ||
| self.assertRaises(AssertionError, self.assertBetween, 9.4, 9.3, 9.3999) | ||
| self.assertRaises(AssertionError, self.assertBetween, -1e10000, -1e10, 0) | ||
| def testAssertRaisesWithPredicateMatch_noRaiseFails(self): | ||
| with self.assertRaisesRegexp(AssertionError, '^Exception not raised$'): | ||
| self.assertRaisesWithPredicateMatch(Exception, | ||
| lambda e: True, | ||
| lambda: 1) # don't raise | ||
| with self.assertRaisesRegexp(AssertionError, '^Exception not raised$'): | ||
| with self.assertRaisesWithPredicateMatch(Exception, lambda e: True): | ||
| pass # don't raise | ||
| def testAssertRaisesWithPredicateMatch_raisesWrongExceptionFails(self): | ||
| def _RaiseValueError(): | ||
| raise ValueError | ||
| with self.assertRaises(ValueError): | ||
| self.assertRaisesWithPredicateMatch(IOError, | ||
| lambda e: True, | ||
| _RaiseValueError) | ||
| with self.assertRaises(ValueError): | ||
| with self.assertRaisesWithPredicateMatch(IOError, lambda e: True): | ||
| raise ValueError | ||
| def testAssertRaisesWithPredicateMatch_predicateFails(self): | ||
| def _RaiseValueError(): | ||
| raise ValueError | ||
| with self.assertRaisesRegexp(AssertionError, ' does not match predicate '): | ||
| self.assertRaisesWithPredicateMatch(ValueError, | ||
| lambda e: False, | ||
| _RaiseValueError) | ||
| with self.assertRaisesRegexp(AssertionError, ' does not match predicate '): | ||
| with self.assertRaisesWithPredicateMatch(ValueError, lambda e: False): | ||
| raise ValueError | ||
| def testAssertRaisesWithPredicateMatch_predicatePasses(self): | ||
| def _RaiseValueError(): | ||
| raise ValueError | ||
| self.assertRaisesWithPredicateMatch(ValueError, | ||
| lambda e: True, | ||
| _RaiseValueError) | ||
| with self.assertRaisesWithPredicateMatch(ValueError, lambda e: True): | ||
| raise ValueError | ||
| def testAssertRaisesWithRegexpMatch(self): | ||
| class ExceptionMock(Exception): | ||
| pass | ||
| def Stub(): | ||
| raise ExceptionMock('We expect') | ||
| self.assertRaisesWithRegexpMatch(ExceptionMock, re.compile('expect$'), Stub) | ||
| self.assertRaisesWithRegexpMatch(ExceptionMock, 'expect$', Stub) | ||
| self.assertRaisesWithRegexpMatch(ExceptionMock, u'expect$', Stub) | ||
| def testAssertNotRaisesWithRegexpMatch(self): | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, '^Exception not raised', | ||
| self.assertRaisesWithRegexpMatch, Exception, re.compile('x'), | ||
| lambda: None) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, '^Exception not raised', | ||
| self.assertRaisesWithRegexpMatch, Exception, 'x', lambda: None) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, '^Exception not raised', | ||
| self.assertRaisesWithRegexpMatch, Exception, u'x', lambda: None) | ||
| def testAssertRaisesWithRegexpMismatch(self): | ||
| def Stub(): | ||
| raise Exception('Unexpected') | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, r'"\^Expected\$" does not match "Unexpected"', | ||
| self.assertRaisesWithRegexpMatch, Exception, r'^Expected$', Stub) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, r'"\^Expected\$" does not match "Unexpected"', | ||
| self.assertRaisesWithRegexpMatch, Exception, r'^Expected$', Stub) | ||
| def testAssertContainsInOrder(self): | ||
| # Valids | ||
| self.assertContainsInOrder( | ||
| ['fox', 'dog'], 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| ['quick', 'fox', 'dog'], | ||
| 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| ['The', 'fox', 'dog.'], 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| ['fox'], 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| 'fox', 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| ['fox', 'dog'], 'fox dog fox') | ||
| self.assertContainsInOrder( | ||
| [], 'The quick brown fox jumped over the lazy dog.') | ||
| self.assertContainsInOrder( | ||
| [], '') | ||
| # Invalids | ||
| self.assertRaises( | ||
| AssertionError, self.assertContainsInOrder, | ||
| ['dog', 'fox'], 'The quick brown fox jumped over the lazy dog') | ||
| self.assertRaises( | ||
| AssertionError, self.assertContainsInOrder, | ||
| ['The', 'dog', 'fox'], 'The quick brown fox jumped over the lazy dog') | ||
| self.assertRaises( | ||
| AssertionError, self.assertContainsInOrder, ['dog'], '') | ||
| def testAssertContainsSubsequenceForNumbers(self): | ||
| self.assertContainsSubsequence([1, 2, 3], [1]) | ||
| self.assertContainsSubsequence([1, 2, 3], [1, 2]) | ||
| self.assertContainsSubsequence([1, 2, 3], [1, 3]) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertContainsSubsequence([1, 2, 3], [4]) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertContainsSubsequence([1, 2, 3], [3, 1]) | ||
| def testAssertContainsSubsequenceForStrings(self): | ||
| self.assertContainsSubsequence(['foo', 'bar', 'blorp'], ['foo', 'blorp']) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertContainsSubsequence( | ||
| ['foo', 'bar', 'blorp'], ['blorp', 'foo']) | ||
| def testAssertContainsSubsequenceWithEmptySubsequence(self): | ||
| self.assertContainsSubsequence([1, 2, 3], []) | ||
| self.assertContainsSubsequence(['foo', 'bar', 'blorp'], []) | ||
| self.assertContainsSubsequence([], []) | ||
| def testAssertContainsSubsequenceWithEmptyContainer(self): | ||
| with self.assertRaises(AssertionError): | ||
| self.assertContainsSubsequence([], [1]) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertContainsSubsequence([], ['foo']) | ||
| def testAssertTotallyOrdered(self): | ||
| # Valid. | ||
| self.assertTotallyOrdered() | ||
| self.assertTotallyOrdered([1]) | ||
| self.assertTotallyOrdered([1], [2]) | ||
| self.assertTotallyOrdered([1, 1, 1]) | ||
| self.assertTotallyOrdered([(1, 1)], [(1, 2)], [(2, 1)]) | ||
| if PY_VERSION_2: | ||
| # In Python 3 comparing different types of elements is not supported. | ||
| self.assertTotallyOrdered([None], [1], [2]) | ||
| self.assertTotallyOrdered([1, 1, 1], ['a string']) | ||
| # From the docstring. | ||
| class A(object): | ||
| def __init__(self, x, y): | ||
| self.x = x | ||
| self.y = y | ||
| def __hash__(self): | ||
| return hash(self.x) | ||
| def __repr__(self): | ||
| return 'A(%r, %r)' % (self.x, self.y) | ||
| def __eq__(self, other): | ||
| try: | ||
| return self.x == other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| def __ne__(self, other): | ||
| try: | ||
| return self.x != other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| def __lt__(self, other): | ||
| try: | ||
| return self.x < other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| def __le__(self, other): | ||
| try: | ||
| return self.x <= other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| def __gt__(self, other): | ||
| try: | ||
| return self.x > other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| def __ge__(self, other): | ||
| try: | ||
| return self.x >= other.x | ||
| except AttributeError: | ||
| return NotImplemented | ||
| if PY_VERSION_2: | ||
| self.assertTotallyOrdered( | ||
| [None], # None should come before everything else. | ||
| [1], # Integers sort earlier. | ||
| [A(1, 'a')], | ||
| [A(2, 'b')], # 2 is after 1. | ||
| [A(3, 'c'), A(3, 'd')], # The second argument is irrelevant. | ||
| [A(4, 'z')], | ||
| ['foo']) # Strings sort last. | ||
| else: | ||
| # Python 3 does not define ordering across different types. | ||
| self.assertTotallyOrdered( | ||
| [A(1, 'a')], | ||
| [A(2, 'b')], # 2 is after 1. | ||
| [A(3, 'c'), A(3, 'd')], # The second argument is irrelevant. | ||
| [A(4, 'z')]) | ||
| # Invalid. | ||
| self.assertRaises(AssertionError, self.assertTotallyOrdered, [2], [1]) | ||
| self.assertRaises(AssertionError, self.assertTotallyOrdered, [2], [1], [3]) | ||
| self.assertRaises(AssertionError, self.assertTotallyOrdered, [1, 2]) | ||
| def testShortDescriptionWithoutDocstring(self): | ||
| self.assertEquals( | ||
| self.shortDescription(), | ||
| ('testShortDescriptionWithoutDocstring ' | ||
| '(%s.GoogleTestBaseUnitTest)' % __name__)) | ||
| def testShortDescriptionWithOneLineDocstring(self): | ||
| """Tests shortDescription() for a method with a docstring.""" | ||
| self.assertEquals( | ||
| self.shortDescription(), | ||
| ('testShortDescriptionWithOneLineDocstring ' | ||
| '(%s.GoogleTestBaseUnitTest)\n' | ||
| 'Tests shortDescription() for a method with a docstring.' % __name__)) | ||
| def testShortDescriptionWithMultiLineDocstring(self): | ||
| """Tests shortDescription() for a method with a longer docstring. | ||
| This method ensures that only the first line of a docstring is | ||
| returned used in the short description, no matter how long the | ||
| whole thing is. | ||
| """ | ||
| self.assertEquals( | ||
| self.shortDescription(), | ||
| ('testShortDescriptionWithMultiLineDocstring ' | ||
| '(%s.GoogleTestBaseUnitTest)\n' | ||
| 'Tests shortDescription() for a method with a longer docstring.' | ||
| % __name__)) | ||
| def testRecordedProperties(self): | ||
| """Tests that a test can record a property and then retrieve it.""" | ||
| self.recordProperty('test_property', 'test_value') | ||
| self.assertEquals(self.getRecordedProperties(), | ||
| {'test_property': 'test_value'}) | ||
| def testAssertUrlEqualSame(self): | ||
| self.assertUrlEqual('http://a', 'http://a') | ||
| self.assertUrlEqual('http://a/path/test', 'http://a/path/test') | ||
| self.assertUrlEqual('#fragment', '#fragment') | ||
| self.assertUrlEqual('http://a/?q=1', 'http://a/?q=1') | ||
| self.assertUrlEqual('http://a/?q=1&v=5', 'http://a/?v=5&q=1') | ||
| self.assertUrlEqual('/logs?v=1&a=2&t=labels&f=path%3A%22foo%22', | ||
| '/logs?a=2&f=path%3A%22foo%22&v=1&t=labels') | ||
| self.assertUrlEqual('http://a/path;p1', 'http://a/path;p1') | ||
| self.assertUrlEqual('http://a/path;p2;p3;p1', 'http://a/path;p1;p2;p3') | ||
| self.assertUrlEqual('sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15', | ||
| 'sip:alice@atlanta.com;ttl=15;maddr=239.255.255.1') | ||
| self.assertUrlEqual('http://nyan/cat?p=1&b=', 'http://nyan/cat?b=&p=1') | ||
| def testAssertUrlEqualDifferent(self): | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a', 'http://b') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a/x', 'http://a:8080/x') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a/x', 'http://a/y') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a/?q=2', 'http://a/?q=1') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a/?q=1&v=5', 'http://a/?v=2&q=1') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a', 'sip://b') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a#g', 'sip://a#f') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://a/path;p1;p3;p1', 'http://a/path;p1;p2;p3') | ||
| self.assertRaises(AssertionError, self.assertUrlEqual, | ||
| 'http://nyan/cat?p=1&b=', 'http://nyan/cat?p=1') | ||
| def testSameStructure_same(self): | ||
| self.assertSameStructure(0, 0) | ||
| self.assertSameStructure(1, 1) | ||
| self.assertSameStructure('', '') | ||
| self.assertSameStructure('hello', 'hello', msg='This Should not fail') | ||
| self.assertSameStructure(set(), set()) | ||
| self.assertSameStructure(set([1, 2]), set([1, 2])) | ||
| self.assertSameStructure([], []) | ||
| self.assertSameStructure(['a'], ['a']) | ||
| self.assertSameStructure({}, {}) | ||
| self.assertSameStructure({'one': 1}, {'one': 1}) | ||
| # int and long should always be treated as the same type. | ||
| self.assertSameStructure({3L: 3}, {3: 3L}) | ||
| def testSameStructure_different(self): | ||
| # Different type | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| r"a is a <(type|class) 'int'> but b is a <(type|class) 'str'>", | ||
| self.assertSameStructure, 0, 'hello') | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| r"a is a <(type|class) 'int'> but b is a <(type|class) 'list'>", | ||
| self.assertSameStructure, 0, []) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| r"a is a <(type|class) 'int'> but b is a <(type|class) 'float'>", | ||
| self.assertSameStructure, 2, 2.0) | ||
| # Different scalar values | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, 'a is 0 but b is 1', | ||
| self.assertSameStructure, 0, 1) | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, "a is 'hello' but b is 'goodbye': This was expected", | ||
| self.assertSameStructure, 'hello', 'goodbye', msg='This was expected') | ||
| # Different sets are treated without structure | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, r'AA is (set\(\[1\]\)|\{1\}) but BB is set\((\[\])?\)', | ||
| self.assertSameStructure, set([1]), set(), aname='AA', bname='BB') | ||
| # Different lists | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, 'a has [2] but b does not', | ||
| self.assertSameStructure, ['x', 'y', 'z'], ['x', 'y']) | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, 'a lacks [2] but b has it', | ||
| self.assertSameStructure, ['x', 'y'], ['x', 'y', 'z']) | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, "a[2] is 'z' but b[2] is 'Z'", | ||
| self.assertSameStructure, ['x', 'y', 'z'], ['x', 'y', 'Z']) | ||
| # Different dicts | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, "a has ['two'] but b does not", | ||
| self.assertSameStructure, {'one': 1, 'two': 2}, {'one': 1}) | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, "a lacks ['two'] but b has it", | ||
| self.assertSameStructure, {'one': 1}, {'one': 1, 'two': 2}) | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, "a['two'] is 2 but b['two'] is 3", | ||
| self.assertSameStructure, {'one': 1, 'two': 2}, {'one': 1, 'two': 3}) | ||
| # Deep key generation | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, | ||
| "a[0][0]['x']['y']['z'][0] is 1 but b[0][0]['x']['y']['z'][0] is 2", | ||
| self.assertSameStructure, | ||
| [[{'x': {'y': {'z': [1]}}}]], [[{'x': {'y': {'z': [2]}}}]]) | ||
| # Multiple problems | ||
| self.assertRaisesWithLiteralMatch( | ||
| AssertionError, | ||
| 'a[0] is 1 but b[0] is 3; a[1] is 2 but b[1] is 4', | ||
| self.assertSameStructure, [1, 2], [3, 4]) | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| re.compile(r"^a\[0] is 'a' but b\[0] is 'A'; .*" | ||
| r"a\[18] is 's' but b\[18] is 'S'; \.\.\.$"), | ||
| self.assertSameStructure, | ||
| list(string.ascii_lowercase), list(string.ascii_uppercase)) | ||
| def testAssertJsonEqualSame(self): | ||
| self.assertJsonEqual('{"success": true}', '{"success": true}') | ||
| self.assertJsonEqual('{"success": true}', '{"success":true}') | ||
| self.assertJsonEqual('true', 'true') | ||
| self.assertJsonEqual('null', 'null') | ||
| self.assertJsonEqual('false', 'false') | ||
| self.assertJsonEqual('34', '34') | ||
| self.assertJsonEqual('[1, 2, 3]', '[1,2,3]', msg='please PASS') | ||
| self.assertJsonEqual('{"sequence": [1, 2, 3], "float": 23.42}', | ||
| '{"float": 23.42, "sequence": [1,2,3]}') | ||
| self.assertJsonEqual('{"nest": {"spam": "eggs"}, "float": 23.42}', | ||
| '{"float": 23.42, "nest": {"spam":"eggs"}}') | ||
| def testAssertJsonEqualDifferent(self): | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('{"success": true}', '{"success": false}') | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('{"success": false}', '{"Success": false}') | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('false', 'true') | ||
| with self.assertRaises(AssertionError) as error_context: | ||
| self.assertJsonEqual('null', '0', msg='I demand FAILURE') | ||
| self.assertIn('I demand FAILURE', error_context.exception.args[0]) | ||
| self.assertIn('None', error_context.exception.args[0]) | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('[1, 0, 3]', '[1,2,3]') | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('{"sequence": [1, 2, 3], "float": 23.42}', | ||
| '{"float": 23.42, "sequence": [1,0,3]}') | ||
| with self.assertRaises(AssertionError): | ||
| self.assertJsonEqual('{"nest": {"spam": "eggs"}, "float": 23.42}', | ||
| '{"float": 23.42, "nest": {"Spam":"beans"}}') | ||
| def testAssertJsonEqualBadJson(self): | ||
| with self.assertRaises(ValueError) as error_context: | ||
| self.assertJsonEqual("alhg'2;#", '{"a": true}') | ||
| self.assertIn('first', error_context.exception.args[0]) | ||
| self.assertIn('alhg', error_context.exception.args[0]) | ||
| with self.assertRaises(ValueError) as error_context: | ||
| self.assertJsonEqual('{"a": true}', "alhg'2;#") | ||
| self.assertIn('second', error_context.exception.args[0]) | ||
| self.assertIn('alhg', error_context.exception.args[0]) | ||
| with self.assertRaises(ValueError) as error_context: | ||
| self.assertJsonEqual('', '') | ||
| class GetCommandStderrTestCase(basetest.TestCase): | ||
| def setUp(self): | ||
| self.original_environ = os.environ.copy() | ||
| def tearDown(self): | ||
| os.environ = self.original_environ | ||
| def testReturnStatus(self): | ||
| expected = 255 | ||
| observed = ( | ||
| basetest.GetCommandStderr( | ||
| ['/usr/bin/perl', '-e', 'die "FAIL";'], | ||
| None)[0]) | ||
| self.assertEqual(expected, observed) | ||
| # TODO(dborowitz): Tests for more functionality that do not deal with | ||
| # PYTHON_RUNFILES. | ||
| class EqualityAssertionTest(basetest.TestCase): | ||
| """This test verifies that basetest.failIfEqual actually tests __ne__. | ||
| If a user class implements __eq__, unittest.failUnlessEqual will call it | ||
| via first == second. However, failIfEqual also calls | ||
| first == second. This means that while the caller may believe | ||
| their __ne__ method is being tested, it is not. | ||
| """ | ||
| class NeverEqual(object): | ||
| """Objects of this class behave like NaNs.""" | ||
| def __eq__(self, unused_other): | ||
| return False | ||
| def __ne__(self, unused_other): | ||
| return False | ||
| class AllSame(object): | ||
| """All objects of this class compare as equal.""" | ||
| def __eq__(self, unused_other): | ||
| return True | ||
| def __ne__(self, unused_other): | ||
| return False | ||
| class EqualityTestsWithEq(object): | ||
| """Performs all equality and inequality tests with __eq__.""" | ||
| def __init__(self, value): | ||
| self._value = value | ||
| def __eq__(self, other): | ||
| return self._value == other._value | ||
| def __ne__(self, other): | ||
| return not self.__eq__(other) | ||
| class EqualityTestsWithNe(object): | ||
| """Performs all equality and inequality tests with __ne__.""" | ||
| def __init__(self, value): | ||
| self._value = value | ||
| def __eq__(self, other): | ||
| return not self.__ne__(other) | ||
| def __ne__(self, other): | ||
| return self._value != other._value | ||
| class EqualityTestsWithCmp(object): | ||
| def __init__(self, value): | ||
| self._value = value | ||
| def __cmp__(self, other): | ||
| return cmp(self._value, other._value) | ||
| class EqualityTestsWithLtEq(object): | ||
| def __init__(self, value): | ||
| self._value = value | ||
| def __eq__(self, other): | ||
| return self._value == other._value | ||
| def __lt__(self, other): | ||
| return self._value < other._value | ||
| def testAllComparisonsFail(self): | ||
| i1 = self.NeverEqual() | ||
| i2 = self.NeverEqual() | ||
| self.assertFalse(i1 == i2) | ||
| self.assertFalse(i1 != i2) | ||
| # Compare two distinct objects | ||
| self.assertFalse(i1 is i2) | ||
| self.assertRaises(AssertionError, self.assertEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertEquals, i1, i2) | ||
| self.assertRaises(AssertionError, self.failUnlessEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertNotEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertNotEquals, i1, i2) | ||
| self.assertRaises(AssertionError, self.failIfEqual, i1, i2) | ||
| # A NeverEqual object should not compare equal to itself either. | ||
| i2 = i1 | ||
| self.assertTrue(i1 is i2) | ||
| self.assertFalse(i1 == i2) | ||
| self.assertFalse(i1 != i2) | ||
| self.assertRaises(AssertionError, self.assertEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertEquals, i1, i2) | ||
| self.assertRaises(AssertionError, self.failUnlessEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertNotEqual, i1, i2) | ||
| self.assertRaises(AssertionError, self.assertNotEquals, i1, i2) | ||
| self.assertRaises(AssertionError, self.failIfEqual, i1, i2) | ||
| def testAllComparisonsSucceed(self): | ||
| a = self.AllSame() | ||
| b = self.AllSame() | ||
| self.assertFalse(a is b) | ||
| self.assertTrue(a == b) | ||
| self.assertFalse(a != b) | ||
| self.assertEqual(a, b) | ||
| self.assertEquals(a, b) | ||
| self.failUnlessEqual(a, b) | ||
| self.assertRaises(AssertionError, self.assertNotEqual, a, b) | ||
| self.assertRaises(AssertionError, self.assertNotEquals, a, b) | ||
| self.assertRaises(AssertionError, self.failIfEqual, a, b) | ||
| def _PerformAppleAppleOrangeChecks(self, same_a, same_b, different): | ||
| """Perform consistency checks with two apples and an orange. | ||
| The two apples should always compare as being the same (and inequality | ||
| checks should fail). The orange should always compare as being different | ||
| to each of the apples. | ||
| Args: | ||
| same_a: the first apple | ||
| same_b: the second apple | ||
| different: the orange | ||
| """ | ||
| self.assertTrue(same_a == same_b) | ||
| self.assertFalse(same_a != same_b) | ||
| self.assertEqual(same_a, same_b) | ||
| self.assertEquals(same_a, same_b) | ||
| self.failUnlessEqual(same_a, same_b) | ||
| if PY_VERSION_2: | ||
| # Python 3 removes the global cmp function | ||
| self.assertEqual(0, cmp(same_a, same_b)) | ||
| self.assertFalse(same_a == different) | ||
| self.assertTrue(same_a != different) | ||
| self.assertNotEqual(same_a, different) | ||
| self.assertNotEquals(same_a, different) | ||
| self.failIfEqual(same_a, different) | ||
| if PY_VERSION_2: | ||
| self.assertNotEqual(0, cmp(same_a, different)) | ||
| self.assertFalse(same_b == different) | ||
| self.assertTrue(same_b != different) | ||
| self.assertNotEqual(same_b, different) | ||
| self.assertNotEquals(same_b, different) | ||
| self.failIfEqual(same_b, different) | ||
| if PY_VERSION_2: | ||
| self.assertNotEqual(0, cmp(same_b, different)) | ||
| def testComparisonWithEq(self): | ||
| same_a = self.EqualityTestsWithEq(42) | ||
| same_b = self.EqualityTestsWithEq(42) | ||
| different = self.EqualityTestsWithEq(1769) | ||
| self._PerformAppleAppleOrangeChecks(same_a, same_b, different) | ||
| def testComparisonWithNe(self): | ||
| same_a = self.EqualityTestsWithNe(42) | ||
| same_b = self.EqualityTestsWithNe(42) | ||
| different = self.EqualityTestsWithNe(1769) | ||
| self._PerformAppleAppleOrangeChecks(same_a, same_b, different) | ||
| def testComparisonWithCmpOrLtEq(self): | ||
| if PY_VERSION_2: | ||
| # In Python 3; the __cmp__ method is no longer special. | ||
| cmp_or_lteq_class = self.EqualityTestsWithCmp | ||
| else: | ||
| cmp_or_lteq_class = self.EqualityTestsWithLtEq | ||
| same_a = cmp_or_lteq_class(42) | ||
| same_b = cmp_or_lteq_class(42) | ||
| different = cmp_or_lteq_class(1769) | ||
| self._PerformAppleAppleOrangeChecks(same_a, same_b, different) | ||
| class AssertSequenceStartsWithTest(basetest.TestCase): | ||
| def setUp(self): | ||
| self.a = [5, 'foo', {'c': 'd'}, None] | ||
| def testEmptySequenceStartsWithEmptyPrefix(self): | ||
| self.assertSequenceStartsWith([], ()) | ||
| def testSequencePrefixIsAnEmptyList(self): | ||
| self.assertSequenceStartsWith([[]], ([], 'foo')) | ||
| def testRaiseIfEmptyPrefixWithNonEmptyWhole(self): | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, | ||
| 'Prefix length is 0 but whole length is %d: %s' % ( | ||
| len(self.a), '\[5, \'foo\', \{\'c\': \'d\'\}, None\]'), | ||
| self.assertSequenceStartsWith, [], self.a) | ||
| def testSingleElementPrefix(self): | ||
| self.assertSequenceStartsWith([5], self.a) | ||
| def testTwoElementPrefix(self): | ||
| self.assertSequenceStartsWith((5, 'foo'), self.a) | ||
| def testPrefixIsFullSequence(self): | ||
| self.assertSequenceStartsWith([5, 'foo', {'c': 'd'}, None], self.a) | ||
| def testStringPrefix(self): | ||
| self.assertSequenceStartsWith('abc', 'abc123') | ||
| def testConvertNonSequencePrefixToSequenceAndTryAgain(self): | ||
| self.assertSequenceStartsWith(5, self.a) | ||
| def testWholeNotASequence(self): | ||
| msg = ('For whole: len\(5\) is not supported, it appears to be type: ' | ||
| '<(type|class) \'int\'>') | ||
| self.assertRaisesWithRegexpMatch(AssertionError, msg, | ||
| self.assertSequenceStartsWith, self.a, 5) | ||
| def testRaiseIfSequenceDoesNotStartWithPrefix(self): | ||
| msg = ('prefix: \[\'foo\', \{\'c\': \'d\'\}\] not found at start of whole: ' | ||
| '\[5, \'foo\', \{\'c\': \'d\'\}, None\].') | ||
| self.assertRaisesWithRegexpMatch( | ||
| AssertionError, msg, self.assertSequenceStartsWith, ['foo', {'c': 'd'}], | ||
| self.a) | ||
| def testRaiseIfTypesArNotSupported(self): | ||
| self.assertRaisesWithRegexpMatch( | ||
| TypeError, 'unhashable type', self.assertSequenceStartsWith, | ||
| {'a': 1, 2: 'b'}, {'a': 1, 2: 'b', 'c': '3'}) | ||
| class InitNotNecessaryForAssertsTest(basetest.TestCase): | ||
| """TestCase assertions should work even if __init__ wasn't correctly called. | ||
| This is a hack, see comment in | ||
| basetest.TestCase._getAssertEqualityFunc. We know that not calling | ||
| __init__ of a superclass is a bad thing, but people keep doing them, | ||
| and this (even if a little bit dirty) saves them from shooting | ||
| themselves in the foot. | ||
| """ | ||
| def testSubclass(self): | ||
| class Subclass(basetest.TestCase): | ||
| def __init__(self): # pylint: disable=super-init-not-called | ||
| pass | ||
| Subclass().assertEquals({}, {}) | ||
| def testMultipleInheritance(self): | ||
| class Foo(object): | ||
| def __init__(self, *args, **kwargs): | ||
| pass | ||
| class Subclass(Foo, basetest.TestCase): | ||
| pass | ||
| Subclass().assertEquals({}, {}) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| #!/usr/bin/env python | ||
| # Copyright 2002 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Unittest for datelib.py module.""" | ||
| import datetime | ||
| import random | ||
| import time | ||
| import pytz | ||
| from google.apputils import basetest | ||
| from google.apputils import datelib | ||
| class TimestampUnitTest(basetest.TestCase): | ||
| seed = 1979 | ||
| def testTzAwareSuccession(self): | ||
| a = datelib.Timestamp.now() | ||
| b = datelib.Timestamp.utcnow() | ||
| self.assertLessEqual(a, b) | ||
| def testTzRandomConversion(self): | ||
| random.seed(self.seed) | ||
| for unused_i in xrange(100): | ||
| stz = pytz.timezone(random.choice(pytz.all_timezones)) | ||
| a = datelib.Timestamp.FromString('2008-04-12T10:00:00', stz) | ||
| b = a | ||
| for unused_j in xrange(100): | ||
| b = b.astimezone(pytz.timezone(random.choice(pytz.all_timezones))) | ||
| self.assertEqual(a, b) | ||
| random.seed() | ||
| def testMicroTimestampConversion(self): | ||
| """Test that f1(f2(a)) == a.""" | ||
| def IsEq(x): | ||
| self.assertEqual( | ||
| x, datelib.Timestamp.FromMicroTimestamp(x).AsMicroTimestamp()) | ||
| IsEq(0) | ||
| IsEq(datelib.MAXIMUM_MICROSECOND_TIMESTAMP) | ||
| random.seed(self.seed) | ||
| for _ in xrange(100): | ||
| IsEq(random.randint(0, datelib.MAXIMUM_MICROSECOND_TIMESTAMP)) | ||
| def testMicroTimestampKnown(self): | ||
| self.assertEqual(0, datelib.Timestamp.FromString( | ||
| '1970-01-01T00:00:00', pytz.UTC).AsMicroTimestamp()) | ||
| self.assertEqual( | ||
| datelib.MAXIMUM_MICROSECOND_TIMESTAMP, | ||
| datelib.MAXIMUM_MICROSECOND_TIMESTAMP_AS_TS.AsMicroTimestamp()) | ||
| def testMicroTimestampOrdering(self): | ||
| """Test that cmp(a, b) == cmp(f1(a), f1(b)).""" | ||
| def IsEq(a, b): | ||
| self.assertEqual( | ||
| cmp(a, b), | ||
| cmp(datelib.Timestamp.FromMicroTimestamp(a), | ||
| datelib.Timestamp.FromMicroTimestamp(b))) | ||
| random.seed(self.seed) | ||
| for unused_i in xrange(100): | ||
| IsEq( | ||
| random.randint(0, datelib.MAXIMUM_MICROSECOND_TIMESTAMP), | ||
| random.randint(0, datelib.MAXIMUM_MICROSECOND_TIMESTAMP)) | ||
| def testCombine(self): | ||
| for tz in (datelib.UTC, datelib.US_PACIFIC): | ||
| self.assertEqual( | ||
| tz.localize(datelib.Timestamp(1970, 1, 1, 0, 0, 0, 0)), | ||
| datelib.Timestamp.combine( | ||
| datelib.datetime.date(1970, 1, 1), | ||
| datelib.datetime.time(0, 0, 0), | ||
| tz)) | ||
| self.assertEqual( | ||
| tz.localize(datelib.Timestamp(9998, 12, 31, 23, 59, 59, 999999)), | ||
| datelib.Timestamp.combine( | ||
| datelib.datetime.date(9998, 12, 31), | ||
| datelib.datetime.time(23, 59, 59, 999999), | ||
| tz)) | ||
| def testStrpTime(self): | ||
| time_str = '20130829 23:43:19.206' | ||
| time_fmt = '%Y%m%d %H:%M:%S.%f' | ||
| expected = datelib.Timestamp(2013, 8, 29, 23, 43, 19, 206000) | ||
| for tz in (datelib.UTC, datelib.US_PACIFIC): | ||
| if tz == datelib.LocalTimezone: | ||
| actual = datelib.Timestamp.strptime(time_str, time_fmt) | ||
| else: | ||
| actual = datelib.Timestamp.strptime(time_str, time_fmt, tz) | ||
| self.assertEqual(tz.localize(expected), actual) | ||
| def testFromString1(self): | ||
| for string_zero in ( | ||
| '1970-01-01 00:00:00', | ||
| '19700101T000000', | ||
| '1970-01-01T00:00:00' | ||
| ): | ||
| for testtz in (datelib.UTC, datelib.US_PACIFIC): | ||
| self.assertEqual( | ||
| datelib.Timestamp.FromString(string_zero, testtz), | ||
| testtz.localize(datelib.Timestamp(1970, 1, 1, 0, 0, 0, 0))) | ||
| self.assertEqual( | ||
| datelib.Timestamp.FromString( | ||
| '1970-01-01T00:00:00+0000', datelib.US_PACIFIC), | ||
| datelib.UTC.localize(datelib.Timestamp(1970, 1, 1, 0, 0, 0, 0))) | ||
| startdate = datelib.US_PACIFIC.localize( | ||
| datelib.Timestamp(2009, 1, 1, 3, 0, 0, 0)) | ||
| for day in xrange(1, 366): | ||
| self.assertEqual( | ||
| datelib.Timestamp.FromString(startdate.isoformat()), | ||
| startdate, | ||
| 'FromString works for day %d since 2009-01-01' % day) | ||
| startdate += datelib.datetime.timedelta(days=1) | ||
| def testFromString2(self): | ||
| """Test correctness of parsing the local time in a given timezone. | ||
| The result shall always be the same as tz.localize(naive_time). | ||
| """ | ||
| baseday = datelib.datetime.date(2009, 1, 1).toordinal() | ||
| for day_offset in xrange(0, 365): | ||
| day = datelib.datetime.date.fromordinal(baseday + day_offset) | ||
| naive_day = datelib.datetime.datetime.combine( | ||
| day, datelib.datetime.time(0, 45, 9)) | ||
| naive_day_str = naive_day.strftime('%Y-%m-%dT%H:%M:%S') | ||
| self.assertEqual( | ||
| datelib.US_PACIFIC.localize(naive_day), | ||
| datelib.Timestamp.FromString(naive_day_str, tz=datelib.US_PACIFIC), | ||
| 'FromString localizes time incorrectly') | ||
| def testFromStringInterval(self): | ||
| expected_date = datetime.datetime.utcnow() - datetime.timedelta(days=1) | ||
| expected_s = time.mktime(expected_date.utctimetuple()) | ||
| actual_date = datelib.Timestamp.FromString('1d') | ||
| actual_s = time.mktime(actual_date.timetuple()) | ||
| diff_seconds = actual_s - expected_s | ||
| self.assertBetween(diff_seconds, 0, 1) | ||
| self.assertRaises( | ||
| datelib.TimeParseError, datelib.Timestamp.FromString, 'wat') | ||
| def _EpochToDatetime(t, tz=None): | ||
| if tz is not None: | ||
| return datelib.datetime.datetime.fromtimestamp(t, tz) | ||
| else: | ||
| return datelib.datetime.datetime.utcfromtimestamp(t) | ||
| class DatetimeConversionUnitTest(basetest.TestCase): | ||
| def setUp(self): | ||
| self.pst = pytz.timezone('US/Pacific') | ||
| self.utc = pytz.utc | ||
| self.now = time.time() | ||
| def testDatetimeToUTCMicros(self): | ||
| self.assertEqual( | ||
| 0, datelib.DatetimeToUTCMicros(_EpochToDatetime(0))) | ||
| self.assertEqual( | ||
| 1001 * long(datelib._MICROSECONDS_PER_SECOND), | ||
| datelib.DatetimeToUTCMicros(_EpochToDatetime(1001))) | ||
| self.assertEqual(long(self.now * datelib._MICROSECONDS_PER_SECOND), | ||
| datelib.DatetimeToUTCMicros(_EpochToDatetime(self.now))) | ||
| # tzinfo shouldn't change the result | ||
| self.assertEqual( | ||
| 0, datelib.DatetimeToUTCMicros(_EpochToDatetime(0, tz=self.pst))) | ||
| def testDatetimeToUTCMillis(self): | ||
| self.assertEqual( | ||
| 0, datelib.DatetimeToUTCMillis(_EpochToDatetime(0))) | ||
| self.assertEqual( | ||
| 1001 * 1000L, datelib.DatetimeToUTCMillis(_EpochToDatetime(1001))) | ||
| self.assertEqual(long(self.now * 1000), | ||
| datelib.DatetimeToUTCMillis(_EpochToDatetime(self.now))) | ||
| # tzinfo shouldn't change the result | ||
| self.assertEqual( | ||
| 0, datelib.DatetimeToUTCMillis(_EpochToDatetime(0, tz=self.pst))) | ||
| def testUTCMicrosToDatetime(self): | ||
| self.assertEqual(_EpochToDatetime(0), datelib.UTCMicrosToDatetime(0)) | ||
| self.assertEqual(_EpochToDatetime(1.000001), | ||
| datelib.UTCMicrosToDatetime(1000001)) | ||
| self.assertEqual(_EpochToDatetime(self.now), datelib.UTCMicrosToDatetime( | ||
| long(self.now * datelib._MICROSECONDS_PER_SECOND))) | ||
| # Check timezone-aware comparisons | ||
| self.assertEqual(_EpochToDatetime(0, self.pst), | ||
| datelib.UTCMicrosToDatetime(0, tz=self.pst)) | ||
| self.assertEqual(_EpochToDatetime(0, self.pst), | ||
| datelib.UTCMicrosToDatetime(0, tz=self.utc)) | ||
| def testUTCMillisToDatetime(self): | ||
| self.assertEqual(_EpochToDatetime(0), datelib.UTCMillisToDatetime(0)) | ||
| self.assertEqual(_EpochToDatetime(1.001), datelib.UTCMillisToDatetime(1001)) | ||
| t = time.time() | ||
| dt = _EpochToDatetime(t) | ||
| # truncate sub-milli time | ||
| dt -= datelib.datetime.timedelta(microseconds=dt.microsecond % 1000) | ||
| self.assertEqual(dt, datelib.UTCMillisToDatetime(long(t * 1000))) | ||
| # Check timezone-aware comparisons | ||
| self.assertEqual(_EpochToDatetime(0, self.pst), | ||
| datelib.UTCMillisToDatetime(0, tz=self.pst)) | ||
| self.assertEqual(_EpochToDatetime(0, self.pst), | ||
| datelib.UTCMillisToDatetime(0, tz=self.utc)) | ||
| class MicrosecondsToSecondsUnitTest(basetest.TestCase): | ||
| def testConversionFromMicrosecondsToSeconds(self): | ||
| self.assertEqual(0.0, datelib.MicrosecondsToSeconds(0)) | ||
| self.assertEqual(7.0, datelib.MicrosecondsToSeconds(7000000)) | ||
| self.assertEqual(1.234567, datelib.MicrosecondsToSeconds(1234567)) | ||
| self.assertEqual(12345654321.123456, | ||
| datelib.MicrosecondsToSeconds(12345654321123456)) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #!/usr/bin/env python | ||
| # Copyright 2007 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Unittest for common file utilities.""" | ||
| import __builtin__ | ||
| import errno | ||
| import os | ||
| import posix | ||
| import pwd | ||
| import shutil | ||
| import stat | ||
| import tempfile | ||
| import mox | ||
| from google.apputils import basetest | ||
| from google.apputils import file_util | ||
| import gflags as flags | ||
| FLAGS = flags.FLAGS | ||
| # pylint is dumb about mox: | ||
| # pylint: disable=no-member | ||
| class FileUtilTest(basetest.TestCase): | ||
| def testHomeDir(self): | ||
| self.assertEqual(file_util.HomeDir(), pwd.getpwuid(os.geteuid()).pw_dir) | ||
| self.assertEqual(file_util.HomeDir(0), pwd.getpwuid(0).pw_dir) | ||
| self.assertEqual(file_util.HomeDir('root'), pwd.getpwnam('root').pw_dir) | ||
| class FileUtilTempdirTest(basetest.TestCase): | ||
| def setUp(self): | ||
| self.temp_dir = tempfile.mkdtemp() | ||
| self.file_path = self.temp_dir + 'sample.txt' | ||
| self.sample_contents = 'Random text: aldmkfhjwoem103u74.' | ||
| # To avoid confusion in the mode tests. | ||
| self.prev_umask = posix.umask(0) | ||
| def tearDown(self): | ||
| shutil.rmtree(self.temp_dir) | ||
| posix.umask(self.prev_umask) | ||
| def testWriteOverwrite(self): | ||
| file_util.Write(self.file_path, 'original contents') | ||
| file_util.Write(self.file_path, self.sample_contents) | ||
| with open(self.file_path) as fp: | ||
| self.assertEquals(fp.read(), self.sample_contents) | ||
| def testWriteExclusive(self): | ||
| file_util.Write(self.file_path, 'original contents') | ||
| self.assertRaises(OSError, file_util.Write, self.file_path, | ||
| self.sample_contents, overwrite_existing=False) | ||
| def testWriteMode(self): | ||
| mode = 0744 | ||
| file_util.Write(self.file_path, self.sample_contents, mode=mode) | ||
| s = os.stat(self.file_path) | ||
| self.assertEqual(stat.S_IMODE(s.st_mode), mode) | ||
| def testAtomicWriteSuccessful(self): | ||
| file_util.AtomicWrite(self.file_path, self.sample_contents) | ||
| with open(self.file_path) as fp: | ||
| self.assertEquals(fp.read(), self.sample_contents) | ||
| def testAtomicWriteMode(self): | ||
| mode = 0745 | ||
| file_util.AtomicWrite(self.file_path, self.sample_contents, mode=mode) | ||
| s = os.stat(self.file_path) | ||
| self.assertEqual(stat.S_IMODE(s.st_mode), mode) | ||
| class FileUtilMoxTestBase(basetest.TestCase): | ||
| def setUp(self): | ||
| self.mox = mox.Mox() | ||
| self.sample_contents = 'Contents of the file' | ||
| self.file_path = '/path/to/some/file' | ||
| self.fd = 'a file descriptor' | ||
| def tearDown(self): | ||
| # In case a test fails before it gets to the unset line. | ||
| self.mox.UnsetStubs() | ||
| class FileUtilMoxTest(FileUtilMoxTestBase): | ||
| def testListDirPath(self): | ||
| self.mox.StubOutWithMock(os, 'listdir') | ||
| dir_contents = ['file1', 'file2', 'file3', 'directory1', 'file4', | ||
| 'directory2'] | ||
| os.listdir('/path/to/some/directory').AndReturn(dir_contents) | ||
| self.mox.ReplayAll() | ||
| self.assertListEqual(file_util.ListDirPath('/path/to/some/directory'), | ||
| ['%s/%s' % ('/path/to/some/directory', entry) | ||
| for entry in dir_contents]) | ||
| self.mox.VerifyAll() | ||
| def testSuccessfulRead(self): | ||
| file_handle = self.mox.CreateMockAnything() | ||
| self.mox.StubOutWithMock(__builtin__, 'open', use_mock_anything=True) | ||
| open(self.file_path).AndReturn(file_handle) | ||
| file_handle.__enter__().AndReturn(file_handle) | ||
| file_handle.read().AndReturn(self.sample_contents) | ||
| file_handle.__exit__(None, None, None) | ||
| self.mox.ReplayAll() | ||
| try: | ||
| self.assertEquals(file_util.Read(self.file_path), self.sample_contents) | ||
| self.mox.VerifyAll() | ||
| finally: | ||
| # Because we mock out the built-in open() function, which the unittest | ||
| # library depends on, we need to make sure we revert it before leaving the | ||
| # test, otherwise any test failures will cause further internal failures | ||
| # and yield no meaningful error output. | ||
| self.mox.ResetAll() | ||
| self.mox.UnsetStubs() | ||
| def testWriteGroup(self): | ||
| self.mox.StubOutWithMock(os, 'open') | ||
| self.mox.StubOutWithMock(os, 'write') | ||
| self.mox.StubOutWithMock(os, 'close') | ||
| self.mox.StubOutWithMock(os, 'chown') | ||
| gid = 'new gid' | ||
| os.open(self.file_path, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, | ||
| 0666).AndReturn(self.fd) | ||
| os.write(self.fd, self.sample_contents) | ||
| os.close(self.fd) | ||
| os.chown(self.file_path, -1, gid) | ||
| self.mox.ReplayAll() | ||
| file_util.Write(self.file_path, self.sample_contents, gid=gid) | ||
| self.mox.VerifyAll() | ||
| class AtomicWriteMoxTest(FileUtilMoxTestBase): | ||
| def setUp(self): | ||
| super(AtomicWriteMoxTest, self).setUp() | ||
| self.mox.StubOutWithMock(tempfile, 'mkstemp') | ||
| self.mox.StubOutWithMock(os, 'write') | ||
| self.mox.StubOutWithMock(os, 'close') | ||
| self.mox.StubOutWithMock(os, 'chmod') | ||
| self.mox.StubOutWithMock(os, 'rename') | ||
| self.mox.StubOutWithMock(os, 'remove') | ||
| self.mode = 'new permissions' | ||
| self.gid = 'new gid' | ||
| self.temp_filename = '/some/temp/file' | ||
| self.os_error = OSError('A problem renaming!') | ||
| tempfile.mkstemp(dir='/path/to/some').AndReturn( | ||
| (self.fd, self.temp_filename)) | ||
| os.write(self.fd, self.sample_contents) | ||
| os.close(self.fd) | ||
| os.chmod(self.temp_filename, self.mode) | ||
| def tearDown(self): | ||
| self.mox.UnsetStubs() | ||
| def testAtomicWriteGroup(self): | ||
| self.mox.StubOutWithMock(os, 'chown') | ||
| os.chown(self.temp_filename, -1, self.gid) | ||
| os.rename(self.temp_filename, self.file_path) | ||
| self.mox.ReplayAll() | ||
| file_util.AtomicWrite(self.file_path, self.sample_contents, | ||
| mode=self.mode, gid=self.gid) | ||
| self.mox.VerifyAll() | ||
| def testAtomicWriteGroupError(self): | ||
| self.mox.StubOutWithMock(os, 'chown') | ||
| os.chown(self.temp_filename, -1, self.gid).AndRaise(self.os_error) | ||
| os.remove(self.temp_filename) | ||
| self.mox.ReplayAll() | ||
| self.assertRaises(OSError, file_util.AtomicWrite, self.file_path, | ||
| self.sample_contents, mode=self.mode, gid=self.gid) | ||
| self.mox.VerifyAll() | ||
| def testRenamingError(self): | ||
| os.rename(self.temp_filename, self.file_path).AndRaise(self.os_error) | ||
| os.remove(self.temp_filename) | ||
| self.mox.ReplayAll() | ||
| self.assertRaises(OSError, file_util.AtomicWrite, self.file_path, | ||
| self.sample_contents, mode=self.mode) | ||
| self.mox.VerifyAll() | ||
| def testRenamingErrorWithRemoveError(self): | ||
| extra_error = OSError('A problem removing!') | ||
| os.rename(self.temp_filename, self.file_path).AndRaise(self.os_error) | ||
| os.remove(self.temp_filename).AndRaise(extra_error) | ||
| self.mox.ReplayAll() | ||
| try: | ||
| file_util.AtomicWrite(self.file_path, self.sample_contents, | ||
| mode=self.mode) | ||
| except OSError as e: | ||
| self.assertEquals(str(e), | ||
| 'A problem renaming!. Additional errors cleaning up: ' | ||
| 'A problem removing!') | ||
| else: | ||
| raise self.failureException('OSError not raised by AtomicWrite') | ||
| self.mox.VerifyAll() | ||
| class TemporaryFilesMoxTest(FileUtilMoxTestBase): | ||
| def testTemporaryFileWithContents(self): | ||
| contents = 'Inspiration!' | ||
| with file_util.TemporaryFileWithContents(contents) as temporary_file: | ||
| filename = temporary_file.name | ||
| contents_read = open(temporary_file.name).read() | ||
| self.assertEqual(contents_read, contents) | ||
| # Ensure that the file does not exist. | ||
| self.assertFalse(os.path.exists(filename)) | ||
| class TemporaryDirsMoxTest(FileUtilMoxTestBase): | ||
| def testTemporaryDirectoryWithException(self): | ||
| def Inner(accumulator): | ||
| with file_util.TemporaryDirectory(base_path=FLAGS.test_tmpdir) as tmpdir: | ||
| self.assertTrue(os.path.isdir(tmpdir)) | ||
| accumulator.append(tmpdir) | ||
| raise Exception('meh') | ||
| temp_dirs = [] | ||
| self.assertRaises(Exception, Inner, temp_dirs) | ||
| # Ensure that the directory is removed on exit even when exceptions happen. | ||
| self.assertEquals(len(temp_dirs), 1) | ||
| self.assertFalse(os.path.isdir(temp_dirs[0])) | ||
| def testTemporaryDirectory(self): | ||
| with file_util.TemporaryDirectory(base_path=FLAGS.test_tmpdir) as temp_dir: | ||
| self.assertTrue(os.path.isdir(temp_dir)) | ||
| # Ensure that the directory is removed on exit. | ||
| self.assertFalse(os.path.isdir(temp_dir)) | ||
| class MkDirsMoxTest(FileUtilMoxTestBase): | ||
| # pylint is dumb about mox: | ||
| # pylint: disable=maybe-no-member | ||
| def setUp(self): | ||
| super(MkDirsMoxTest, self).setUp() | ||
| self.mox.StubOutWithMock(os, 'mkdir') | ||
| self.mox.StubOutWithMock(os, 'chmod') | ||
| self.mox.StubOutWithMock(os.path, 'isdir') | ||
| self.dir_tree = ['/path', 'to', 'some', 'directory'] | ||
| def tearDown(self): | ||
| self.mox.UnsetStubs() | ||
| def testNoErrorsAbsoluteOneDir(self): | ||
| # record, replay | ||
| os.mkdir('/foo') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo') | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsAbsoluteOneDirWithForceMode(self): | ||
| # record, replay | ||
| os.mkdir('/foo') | ||
| os.chmod('/foo', 0707) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo', force_mode=0707) | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsExistingDirWithForceMode(self): | ||
| exist_error = OSError(errno.EEXIST, 'This string not used') | ||
| # record, replay | ||
| os.mkdir('/foo').AndRaise(exist_error) | ||
| # no chmod is called since the dir exists | ||
| os.path.isdir('/foo').AndReturn(True) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo', force_mode=0707) | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsAbsoluteSlashDot(self): | ||
| # record, replay | ||
| os.mkdir('/foo') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo/.') | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsAbsoluteExcessiveSlashDot(self): | ||
| """See that normpath removes irrelevant .'s in the path.""" | ||
| # record, replay | ||
| os.mkdir('/foo') | ||
| os.mkdir('/foo/bar') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/./foo/./././bar/.') | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsAbsoluteTwoDirs(self): | ||
| # record, replay | ||
| os.mkdir('/foo') | ||
| os.mkdir('/foo/bar') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo/bar') | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsPartialTwoDirsWithForceMode(self): | ||
| exist_error = OSError(errno.EEXIST, 'This string not used') | ||
| # record, replay | ||
| os.mkdir('/foo').AndRaise(exist_error) # /foo exists | ||
| os.path.isdir('/foo').AndReturn(True) | ||
| os.mkdir('/foo/bar') # bar does not | ||
| os.chmod('/foo/bar', 0707) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('/foo/bar', force_mode=0707) | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsRelativeOneDir(self): | ||
| # record, replay | ||
| os.mkdir('foo') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('foo') | ||
| self.mox.VerifyAll() | ||
| def testNoErrorsRelativeTwoDirs(self): | ||
| # record, replay | ||
| os.mkdir('foo') | ||
| os.mkdir('foo/bar') | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs('foo/bar') | ||
| self.mox.VerifyAll() | ||
| def testDirectoriesExist(self): | ||
| exist_error = OSError(errno.EEXIST, 'This string not used') | ||
| # record, replay | ||
| for i in range(len(self.dir_tree)): | ||
| path = os.path.join(*self.dir_tree[:i+1]) | ||
| os.mkdir(path).AndRaise(exist_error) | ||
| os.path.isdir(path).AndReturn(True) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| file_util.MkDirs(os.path.join(*self.dir_tree)) | ||
| self.mox.VerifyAll() | ||
| def testFileInsteadOfDirectory(self): | ||
| exist_error = OSError(errno.EEXIST, 'This string not used') | ||
| path = self.dir_tree[0] | ||
| # record, replay | ||
| os.mkdir(path).AndRaise(exist_error) | ||
| os.path.isdir(path).AndReturn(False) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| self.assertRaises(OSError, file_util.MkDirs, os.path.join(*self.dir_tree)) | ||
| self.mox.VerifyAll() | ||
| def testNonExistsError(self): | ||
| non_exist_error = OSError(errno.ETIMEDOUT, 'This string not used') | ||
| path = self.dir_tree[0] | ||
| # record, replay | ||
| os.mkdir(path).AndRaise(non_exist_error) | ||
| self.mox.ReplayAll() | ||
| # test, verify | ||
| self.assertRaises(OSError, file_util.MkDirs, os.path.join(*self.dir_tree)) | ||
| self.mox.VerifyAll() | ||
| class RmDirsTestCase(mox.MoxTestBase): | ||
| def testRmDirs(self): | ||
| test_sandbox = os.path.join(FLAGS.test_tmpdir, 'test-rm-dirs') | ||
| test_dir = os.path.join(test_sandbox, 'test', 'dir') | ||
| os.makedirs(test_sandbox) | ||
| with open(os.path.join(test_sandbox, 'file'), 'w'): | ||
| pass | ||
| os.makedirs(test_dir) | ||
| with open(os.path.join(test_dir, 'file'), 'w'): | ||
| pass | ||
| file_util.RmDirs(test_dir) | ||
| self.assertFalse(os.path.exists(os.path.join(test_sandbox, 'test'))) | ||
| self.assertTrue(os.path.exists(os.path.join(test_sandbox, 'file'))) | ||
| shutil.rmtree(test_sandbox) | ||
| def testRmDirsForNonExistingDirectory(self): | ||
| self.mox.StubOutWithMock(os, 'rmdir') | ||
| os.rmdir('path/to') | ||
| os.rmdir('path') | ||
| self.mox.StubOutWithMock(shutil, 'rmtree') | ||
| shutil.rmtree('path/to/directory').AndRaise( | ||
| OSError(errno.ENOENT, "No such file or directory 'path/to/directory'")) | ||
| self.mox.ReplayAll() | ||
| file_util.RmDirs('path/to/directory') | ||
| self.mox.VerifyAll() | ||
| def testRmDirsForNonExistingParentDirectory(self): | ||
| self.mox.StubOutWithMock(os, 'rmdir') | ||
| os.rmdir('path/to').AndRaise( | ||
| OSError(errno.ENOENT, "No such file or directory 'path/to'")) | ||
| os.rmdir('path') | ||
| self.mox.StubOutWithMock(shutil, 'rmtree') | ||
| shutil.rmtree('path/to/directory').AndRaise( | ||
| OSError(errno.ENOENT, "No such file or directory 'path/to/directory'")) | ||
| self.mox.ReplayAll() | ||
| file_util.RmDirs('path/to/directory') | ||
| self.mox.VerifyAll() | ||
| def testRmDirsForNotEmptyDirectory(self): | ||
| self.mox.StubOutWithMock(os, 'rmdir') | ||
| os.rmdir('path/to').AndRaise( | ||
| OSError(errno.ENOTEMPTY, 'Directory not empty', 'path/to')) | ||
| self.mox.StubOutWithMock(shutil, 'rmtree') | ||
| shutil.rmtree('path/to/directory') | ||
| self.mox.ReplayAll() | ||
| file_util.RmDirs('path/to/directory') | ||
| self.mox.VerifyAll() | ||
| def testRmDirsForPermissionDeniedOnParentDirectory(self): | ||
| self.mox.StubOutWithMock(os, 'rmdir') | ||
| os.rmdir('path/to').AndRaise( | ||
| OSError(errno.EACCES, 'Permission denied', 'path/to')) | ||
| self.mox.StubOutWithMock(shutil, 'rmtree') | ||
| shutil.rmtree('path/to/directory') | ||
| self.mox.ReplayAll() | ||
| file_util.RmDirs('path/to/directory') | ||
| self.mox.VerifyAll() | ||
| def testRmDirsWithSimplePath(self): | ||
| self.mox.StubOutWithMock(shutil, 'rmtree') | ||
| shutil.rmtree('directory') | ||
| self.mox.ReplayAll() | ||
| file_util.RmDirs('directory') | ||
| self.mox.VerifyAll() | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #!/usr/bin/env python | ||
| # -*- coding: utf-8 -*- | ||
| """Test for google.apputils.humanize.""" | ||
| import datetime | ||
| from google.apputils import basetest | ||
| from google.apputils import datelib | ||
| from google.apputils import humanize | ||
| class HumanizeTest(basetest.TestCase): | ||
| def testCommas(self): | ||
| self.assertEqual('0', humanize.Commas(0)) | ||
| self.assertEqual('100', humanize.Commas(100)) | ||
| self.assertEqual('1,000', humanize.Commas(1000)) | ||
| self.assertEqual('10,000', humanize.Commas(10000)) | ||
| self.assertEqual('1,000,000', humanize.Commas(1e6)) | ||
| self.assertEqual('-1,000,000', humanize.Commas(-1e6)) | ||
| def testPlural(self): | ||
| self.assertEqual('0 objects', humanize.Plural(0, 'object')) | ||
| self.assertEqual('1 object', humanize.Plural(1, 'object')) | ||
| self.assertEqual('-1 objects', humanize.Plural(-1, 'object')) | ||
| self.assertEqual('42 objects', humanize.Plural(42, 'object')) | ||
| self.assertEqual('42 cats', humanize.Plural(42, 'cat')) | ||
| self.assertEqual('42 glasses', humanize.Plural(42, 'glass')) | ||
| self.assertEqual('42 potatoes', humanize.Plural(42, 'potato')) | ||
| self.assertEqual('42 cherries', humanize.Plural(42, 'cherry')) | ||
| self.assertEqual('42 monkeys', humanize.Plural(42, 'monkey')) | ||
| self.assertEqual('42 oxen', humanize.Plural(42, 'ox', 'oxen')) | ||
| self.assertEqual('42 indices', humanize.Plural(42, 'index')) | ||
| self.assertEqual( | ||
| '42 attorneys general', | ||
| humanize.Plural(42, 'attorney general', 'attorneys general')) | ||
| def testPluralWord(self): | ||
| self.assertEqual('vaxen', humanize.PluralWord(2, 'vax', plural='vaxen')) | ||
| self.assertEqual('cores', humanize.PluralWord(2, 'core')) | ||
| self.assertEqual('group', humanize.PluralWord(1, 'group')) | ||
| self.assertEqual('cells', humanize.PluralWord(0, 'cell')) | ||
| self.assertEqual('degree', humanize.PluralWord(1.0, 'degree')) | ||
| self.assertEqual('helloes', humanize.PluralWord(3.14, 'hello')) | ||
| def testWordSeries(self): | ||
| self.assertEqual('', humanize.WordSeries([])) | ||
| self.assertEqual('foo', humanize.WordSeries(['foo'])) | ||
| self.assertEqual('foo and bar', humanize.WordSeries(['foo', 'bar'])) | ||
| self.assertEqual( | ||
| 'foo, bar, and baz', humanize.WordSeries(['foo', 'bar', 'baz'])) | ||
| self.assertEqual( | ||
| 'foo, bar, or baz', humanize.WordSeries(['foo', 'bar', 'baz'], | ||
| conjunction='or')) | ||
| def testAddIndefiniteArticle(self): | ||
| self.assertEqual('a thing', humanize.AddIndefiniteArticle('thing')) | ||
| self.assertEqual('an object', humanize.AddIndefiniteArticle('object')) | ||
| self.assertEqual('a Porsche', humanize.AddIndefiniteArticle('Porsche')) | ||
| self.assertEqual('an Audi', humanize.AddIndefiniteArticle('Audi')) | ||
| def testDecimalPrefix(self): | ||
| self.assertEqual('0 m', humanize.DecimalPrefix(0, 'm')) | ||
| self.assertEqual('1 km', humanize.DecimalPrefix(1000, 'm')) | ||
| self.assertEqual('-1 km', humanize.DecimalPrefix(-1000, 'm')) | ||
| self.assertEqual('10 Gbps', humanize.DecimalPrefix(10e9, 'bps')) | ||
| self.assertEqual('6000 Yg', humanize.DecimalPrefix(6e27, 'g')) | ||
| self.assertEqual('12.1 km', humanize.DecimalPrefix(12100, 'm', precision=3)) | ||
| self.assertEqual('12 km', humanize.DecimalPrefix(12100, 'm', precision=2)) | ||
| self.assertEqual('1.15 km', humanize.DecimalPrefix(1150, 'm', precision=3)) | ||
| self.assertEqual('-1.15 km', humanize.DecimalPrefix(-1150, 'm', | ||
| precision=3)) | ||
| self.assertEqual('1 k', humanize.DecimalPrefix(1000, '')) | ||
| self.assertEqual('-10 G', humanize.DecimalPrefix(-10e9, '')) | ||
| self.assertEqual('12', humanize.DecimalPrefix(12, '')) | ||
| self.assertEqual('-115', humanize.DecimalPrefix(-115, '')) | ||
| self.assertEqual('0', humanize.DecimalPrefix(0, '')) | ||
| self.assertEqual('1.1 s', humanize.DecimalPrefix(1.12, 's', precision=2)) | ||
| self.assertEqual('-1.1 s', humanize.DecimalPrefix(-1.12, 's', precision=2)) | ||
| self.assertEqual('nan bps', humanize.DecimalPrefix(float('nan'), 'bps')) | ||
| self.assertEqual('nan', humanize.DecimalPrefix(float('nan'), '')) | ||
| self.assertEqual('inf bps', humanize.DecimalPrefix(float('inf'), 'bps')) | ||
| self.assertEqual('-inf bps', humanize.DecimalPrefix(float('-inf'), 'bps')) | ||
| self.assertEqual('-inf', humanize.DecimalPrefix(float('-inf'), '')) | ||
| self.assertEqual('-4 mm', | ||
| humanize.DecimalPrefix(-0.004, 'm', min_scale=None)) | ||
| self.assertEqual('0 m', humanize.DecimalPrefix(0, 'm', min_scale=None)) | ||
| self.assertEqual( | ||
| u'1 µs', | ||
| humanize.DecimalPrefix(0.0000013, 's', min_scale=None)) | ||
| self.assertEqual('3 km', humanize.DecimalPrefix(3000, 'm', min_scale=None)) | ||
| self.assertEqual( | ||
| '5000 TB', | ||
| humanize.DecimalPrefix(5e15, 'B', max_scale=4)) | ||
| self.assertEqual( | ||
| '5 mSWE', | ||
| humanize.DecimalPrefix(0.005, 'SWE', min_scale=None)) | ||
| self.assertEqual( | ||
| '0.0005 ms', | ||
| humanize.DecimalPrefix(5e-7, 's', min_scale=-1, precision=2)) | ||
| def testBinaryPrefix(self): | ||
| self.assertEqual('0 B', humanize.BinaryPrefix(0, 'B')) | ||
| self.assertEqual('1000 B', humanize.BinaryPrefix(1000, 'B')) | ||
| self.assertEqual('1 KiB', humanize.BinaryPrefix(1024, 'B')) | ||
| self.assertEqual('64 GiB', humanize.BinaryPrefix(2**36, 'B')) | ||
| self.assertEqual('65536 Yibit', humanize.BinaryPrefix(2**96, 'bit')) | ||
| self.assertEqual('1.25 KiB', humanize.BinaryPrefix(1280, 'B', precision=3)) | ||
| self.assertEqual('1.2 KiB', humanize.BinaryPrefix(1280, 'B', precision=2)) | ||
| self.assertEqual('1.2 Ki', humanize.BinaryPrefix(1280, '', precision=2)) | ||
| self.assertEqual('12', humanize.BinaryPrefix(12, '', precision=2)) | ||
| # Test both int and long versions of the same quantity to make sure they are | ||
| # printed in the same way. | ||
| self.assertEqual('10.0 QPS', humanize.BinaryPrefix(10, 'QPS', precision=3)) | ||
| self.assertEqual('10.0 QPS', humanize.BinaryPrefix(10L, 'QPS', precision=3)) | ||
| def testDecimalScale(self): | ||
| self.assertIsInstance(humanize.DecimalScale(0, '')[0], float) | ||
| self.assertIsInstance(humanize.DecimalScale(1, '')[0], float) | ||
| self.assertEqual((12.1, 'km'), humanize.DecimalScale(12100, 'm')) | ||
| self.assertEqual((12.1, 'k'), humanize.DecimalScale(12100, '')) | ||
| self.assertEqual((0, ''), humanize.DecimalScale(0, '')) | ||
| self.assertEqual( | ||
| (12.1, 'km'), | ||
| humanize.DecimalScale(12100, 'm', min_scale=0, max_scale=None)) | ||
| self.assertEqual( | ||
| (12100, 'm'), | ||
| humanize.DecimalScale(12100, 'm', min_scale=0, max_scale=0)) | ||
| self.assertEqual((1.15, 'Mm'), humanize.DecimalScale(1150000, 'm')) | ||
| self.assertEqual((1, 'm'), | ||
| humanize.DecimalScale(1, 'm', min_scale=None)) | ||
| self.assertEqual((450, 'mSWE'), | ||
| humanize.DecimalScale(0.45, 'SWE', min_scale=None)) | ||
| self.assertEqual( | ||
| (250, u'µm'), | ||
| humanize.DecimalScale(1.0 / (4 * 1000), 'm', min_scale=None)) | ||
| self.assertEqual( | ||
| (0.250, 'km'), | ||
| humanize.DecimalScale(250, 'm', min_scale=1)) | ||
| self.assertEqual( | ||
| (12000, 'mm'), | ||
| humanize.DecimalScale(12, 'm', min_scale=None, max_scale=-1)) | ||
| def testBinaryScale(self): | ||
| self.assertIsInstance(humanize.BinaryScale(0, '')[0], float) | ||
| self.assertIsInstance(humanize.BinaryScale(1, '')[0], float) | ||
| value, unit = humanize.BinaryScale(200000000000, 'B') | ||
| self.assertAlmostEqual(value, 186.26, 2) | ||
| self.assertEqual(unit, 'GiB') | ||
| value, unit = humanize.BinaryScale(3000000000000, 'B') | ||
| self.assertAlmostEqual(value, 2.728, 3) | ||
| self.assertEqual(unit, 'TiB') | ||
| def testPrettyFraction(self): | ||
| # No rounded integer part | ||
| self.assertEqual(u'½', humanize.PrettyFraction(0.5)) | ||
| # Roundeded integer + fraction | ||
| self.assertEqual(u'6⅔', humanize.PrettyFraction(20.0 / 3.0)) | ||
| # Rounded integer, no fraction | ||
| self.assertEqual(u'2', humanize.PrettyFraction(2.00001)) | ||
| # No rounded integer, no fraction | ||
| self.assertEqual(u'0', humanize.PrettyFraction(0.001)) | ||
| # Round up | ||
| self.assertEqual(u'1', humanize.PrettyFraction(0.99)) | ||
| # No round up, edge case | ||
| self.assertEqual(u'⅞', humanize.PrettyFraction(0.9)) | ||
| # Negative fraction | ||
| self.assertEqual(u'-⅕', humanize.PrettyFraction(-0.2)) | ||
| # Negative close to zero (should not be -0) | ||
| self.assertEqual(u'0', humanize.PrettyFraction(-0.001)) | ||
| # Smallest fraction that should round down. | ||
| self.assertEqual(u'0', humanize.PrettyFraction(1.0 / 16.0)) | ||
| # Largest fraction should round up. | ||
| self.assertEqual(u'1', humanize.PrettyFraction(15.0 / 16.0)) | ||
| # Integer zero. | ||
| self.assertEqual(u'0', humanize.PrettyFraction(0)) | ||
| # Check that division yields fraction | ||
| self.assertEqual(u'⅘', humanize.PrettyFraction(4.0 / 5.0)) | ||
| # Custom spacer. | ||
| self.assertEqual(u'2 ½', humanize.PrettyFraction(2.5, spacer=' ')) | ||
| def testDuration(self): | ||
| self.assertEqual('2h', humanize.Duration(7200)) | ||
| self.assertEqual('5d 13h 47m 12s', humanize.Duration(481632)) | ||
| self.assertEqual('0s', humanize.Duration(0)) | ||
| self.assertEqual('59s', humanize.Duration(59)) | ||
| self.assertEqual('1m', humanize.Duration(60)) | ||
| self.assertEqual('1m 1s', humanize.Duration(61)) | ||
| self.assertEqual('1h 1s', humanize.Duration(3601)) | ||
| self.assertEqual('2h-2s', humanize.Duration(7202, separator='-')) | ||
| def testLargeDuration(self): | ||
| # The maximum seconds and days that can be stored in a datetime.timedelta | ||
| # object, as seconds. max_days is equal to MAX_DELTA_DAYS in Python's | ||
| # Modules/datetimemodule.c, converted to seconds. | ||
| max_seconds = 3600 * 24 - 1 | ||
| max_days = 999999999 * 24 * 60 * 60 | ||
| self.assertEqual('999999999d', humanize.Duration(max_days)) | ||
| self.assertEqual('999999999d 23h 59m 59s', | ||
| humanize.Duration(max_days + max_seconds)) | ||
| self.assertEqual('>=999999999d 23h 59m 60s', | ||
| humanize.Duration(max_days + max_seconds + 1)) | ||
| def testTimeDelta(self): | ||
| self.assertEqual('0s', humanize.TimeDelta(datetime.timedelta())) | ||
| self.assertEqual('2h', humanize.TimeDelta(datetime.timedelta(hours=2))) | ||
| self.assertEqual('1m', humanize.TimeDelta(datetime.timedelta(minutes=1))) | ||
| self.assertEqual('5d', humanize.TimeDelta(datetime.timedelta(days=5))) | ||
| self.assertEqual('1.25s', humanize.TimeDelta( | ||
| datetime.timedelta(seconds=1, microseconds=250000))) | ||
| self.assertEqual('1.5s', | ||
| humanize.TimeDelta(datetime.timedelta(seconds=1.5))) | ||
| self.assertEqual('4d 10h 5m 12.25s', humanize.TimeDelta( | ||
| datetime.timedelta(days=4, hours=10, minutes=5, seconds=12, | ||
| microseconds=250000))) | ||
| def testUnixTimestamp(self): | ||
| self.assertEqual('2013-11-17 11:08:27.723524 PST', | ||
| humanize.UnixTimestamp(1384715307.723524, | ||
| datelib.US_PACIFIC)) | ||
| self.assertEqual('2013-11-17 19:08:27.723524 UTC', | ||
| humanize.UnixTimestamp(1384715307.723524, | ||
| datelib.UTC)) | ||
| # DST part of the timezone should not depend on the current local time, | ||
| # so this should be in PDT (and different from the PST in the first test). | ||
| self.assertEqual('2013-05-17 15:47:21.723524 PDT', | ||
| humanize.UnixTimestamp(1368830841.723524, | ||
| datelib.US_PACIFIC)) | ||
| self.assertEqual('1970-01-01 00:00:00.000000 UTC', | ||
| humanize.UnixTimestamp(0, datelib.UTC)) | ||
| def testAddOrdinalSuffix(self): | ||
| self.assertEqual('0th', humanize.AddOrdinalSuffix(0)) | ||
| self.assertEqual('1st', humanize.AddOrdinalSuffix(1)) | ||
| self.assertEqual('2nd', humanize.AddOrdinalSuffix(2)) | ||
| self.assertEqual('3rd', humanize.AddOrdinalSuffix(3)) | ||
| self.assertEqual('4th', humanize.AddOrdinalSuffix(4)) | ||
| self.assertEqual('5th', humanize.AddOrdinalSuffix(5)) | ||
| self.assertEqual('10th', humanize.AddOrdinalSuffix(10)) | ||
| self.assertEqual('11th', humanize.AddOrdinalSuffix(11)) | ||
| self.assertEqual('12th', humanize.AddOrdinalSuffix(12)) | ||
| self.assertEqual('13th', humanize.AddOrdinalSuffix(13)) | ||
| self.assertEqual('14th', humanize.AddOrdinalSuffix(14)) | ||
| self.assertEqual('20th', humanize.AddOrdinalSuffix(20)) | ||
| self.assertEqual('21st', humanize.AddOrdinalSuffix(21)) | ||
| self.assertEqual('22nd', humanize.AddOrdinalSuffix(22)) | ||
| self.assertEqual('23rd', humanize.AddOrdinalSuffix(23)) | ||
| self.assertEqual('24th', humanize.AddOrdinalSuffix(24)) | ||
| self.assertEqual('63rd', humanize.AddOrdinalSuffix(63)) | ||
| self.assertEqual('100000th', humanize.AddOrdinalSuffix(100000)) | ||
| self.assertEqual('100001st', humanize.AddOrdinalSuffix(100001)) | ||
| self.assertEqual('100011th', humanize.AddOrdinalSuffix(100011)) | ||
| self.assertRaises(ValueError, humanize.AddOrdinalSuffix, -1) | ||
| self.assertRaises(ValueError, humanize.AddOrdinalSuffix, 0.5) | ||
| self.assertRaises(ValueError, humanize.AddOrdinalSuffix, 123.001) | ||
| class NaturalSortKeyChunkingTest(basetest.TestCase): | ||
| def testChunkifySingleChars(self): | ||
| self.assertListEqual( | ||
| humanize.NaturalSortKey('a1b2c3'), | ||
| ['a', 1, 'b', 2, 'c', 3]) | ||
| def testChunkifyMultiChars(self): | ||
| self.assertListEqual( | ||
| humanize.NaturalSortKey('aa11bb22cc33'), | ||
| ['aa', 11, 'bb', 22, 'cc', 33]) | ||
| def testChunkifyComplex(self): | ||
| self.assertListEqual( | ||
| humanize.NaturalSortKey('one 11 -- two 44'), | ||
| ['one ', 11, ' -- two ', 44]) | ||
| class NaturalSortKeysortTest(basetest.TestCase): | ||
| def testNaturalSortKeySimpleWords(self): | ||
| self.test = ['pair', 'banana', 'apple'] | ||
| self.good = ['apple', 'banana', 'pair'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeySimpleNums(self): | ||
| self.test = ['3333', '2222', '9999', '0000'] | ||
| self.good = ['0000', '2222', '3333', '9999'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeySimpleDigits(self): | ||
| self.test = ['8', '3', '2'] | ||
| self.good = ['2', '3', '8'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testVersionStrings(self): | ||
| self.test = ['1.2', '0.9', '1.1a2', '1.1a', '1', '1.2.1', '0.9.1'] | ||
| self.good = ['0.9', '0.9.1', '1', '1.1a', '1.1a2', '1.2', '1.2.1'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeySimpleNumLong(self): | ||
| self.test = ['11', '9', '1', '200', '19', '20', '900'] | ||
| self.good = ['1', '9', '11', '19', '20', '200', '900'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeyAlNum(self): | ||
| self.test = ['x10', 'x9', 'x1', 'x11'] | ||
| self.good = ['x1', 'x9', 'x10', 'x11'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeyNumAlNum(self): | ||
| self.test = ['4x10', '4x9', '4x11', '5yy4', '3x1', '2x11'] | ||
| self.good = ['2x11', '3x1', '4x9', '4x10', '4x11', '5yy4'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| def testNaturalSortKeyAlNumAl(self): | ||
| self.test = ['a9c', 'a4b', 'a10c', 'a1c', 'c10c', 'c10a', 'c9a'] | ||
| self.good = ['a1c', 'a4b', 'a9c', 'a10c', 'c9a', 'c10a', 'c10c'] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| class NaturalSortKeyBigTest(basetest.TestCase): | ||
| def testBig(self): | ||
| self.test = [ | ||
| '1000X Radonius Maximus', '10X Radonius', '200X Radonius', | ||
| '20X Radonius', '20X Radonius Prime', '30X Radonius', | ||
| '40X Radonius', 'Allegia 50 Clasteron', 'Allegia 500 Clasteron', | ||
| 'Allegia 51 Clasteron', 'Allegia 51B Clasteron', | ||
| 'Allegia 52 Clasteron', 'Allegia 60 Clasteron', 'Alpha 100', | ||
| 'Alpha 2', 'Alpha 200', 'Alpha 2A', 'Alpha 2A-8000', 'Alpha 2A-900', | ||
| 'Callisto Morphamax', 'Callisto Morphamax 500', | ||
| 'Callisto Morphamax 5000', 'Callisto Morphamax 600', | ||
| 'Callisto Morphamax 700', 'Callisto Morphamax 7000', | ||
| 'Callisto Morphamax 7000 SE', 'Callisto Morphamax 7000 SE2', | ||
| 'QRS-60 Intrinsia Machine', 'QRS-60F Intrinsia Machine', | ||
| 'QRS-62 Intrinsia Machine', 'QRS-62F Intrinsia Machine', | ||
| 'Xiph Xlater 10000', 'Xiph Xlater 2000', 'Xiph Xlater 300', | ||
| 'Xiph Xlater 40', 'Xiph Xlater 5', 'Xiph Xlater 50', | ||
| 'Xiph Xlater 500', 'Xiph Xlater 5000', 'Xiph Xlater 58'] | ||
| self.good = [ | ||
| '10X Radonius', | ||
| '20X Radonius', | ||
| '20X Radonius Prime', | ||
| '30X Radonius', | ||
| '40X Radonius', | ||
| '200X Radonius', | ||
| '1000X Radonius Maximus', | ||
| 'Allegia 50 Clasteron', | ||
| 'Allegia 51 Clasteron', | ||
| 'Allegia 51B Clasteron', | ||
| 'Allegia 52 Clasteron', | ||
| 'Allegia 60 Clasteron', | ||
| 'Allegia 500 Clasteron', | ||
| 'Alpha 2', | ||
| 'Alpha 2A', | ||
| 'Alpha 2A-900', | ||
| 'Alpha 2A-8000', | ||
| 'Alpha 100', | ||
| 'Alpha 200', | ||
| 'Callisto Morphamax', | ||
| 'Callisto Morphamax 500', | ||
| 'Callisto Morphamax 600', | ||
| 'Callisto Morphamax 700', | ||
| 'Callisto Morphamax 5000', | ||
| 'Callisto Morphamax 7000', | ||
| 'Callisto Morphamax 7000 SE', | ||
| 'Callisto Morphamax 7000 SE2', | ||
| 'QRS-60 Intrinsia Machine', | ||
| 'QRS-60F Intrinsia Machine', | ||
| 'QRS-62 Intrinsia Machine', | ||
| 'QRS-62F Intrinsia Machine', | ||
| 'Xiph Xlater 5', | ||
| 'Xiph Xlater 40', | ||
| 'Xiph Xlater 50', | ||
| 'Xiph Xlater 58', | ||
| 'Xiph Xlater 300', | ||
| 'Xiph Xlater 500', | ||
| 'Xiph Xlater 2000', | ||
| 'Xiph Xlater 5000', | ||
| 'Xiph Xlater 10000', | ||
| ] | ||
| self.test.sort(key=humanize.NaturalSortKey) | ||
| self.assertListEqual(self.test, self.good) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #!/usr/bin/env python | ||
| # Copyright 2010 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Tests for the resources module.""" | ||
| __author__ = 'dborowitz@google.com (Dave Borowitz)' | ||
| from google.apputils import basetest | ||
| from google.apputils import file_util | ||
| from google.apputils import resources | ||
| PREFIX = __name__ + ':data/' | ||
| class ResourcesTest(basetest.TestCase): | ||
| def _CheckTestData(self, func): | ||
| self.assertEqual('test file a contents\n', func(PREFIX + 'a')) | ||
| self.assertEqual('test file b contents\n', func(PREFIX + 'b')) | ||
| def testGetResource(self): | ||
| self._CheckTestData(resources.GetResource) | ||
| def testGetResourceAsFile(self): | ||
| self._CheckTestData(lambda n: resources.GetResourceAsFile(n).read()) | ||
| def testGetResourceFilename(self): | ||
| self._CheckTestData( | ||
| lambda n: file_util.Read(resources.GetResourceFilename(n))) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #!/usr/bin/env python | ||
| # Copyright 2010 Google Inc. All Rights Reserved. | ||
| """Tests for google.apputils. | ||
| In addition to the test modules under this package, we have a special TestCase | ||
| that runs the tests that are shell scripts. | ||
| """ | ||
| # TODO(dborowitz): It may be useful to generalize this and provide it to users | ||
| # who want to run their own sh_tests. | ||
| import os | ||
| import subprocess | ||
| import sys | ||
| from google.apputils import basetest | ||
| import gflags | ||
| FLAGS = gflags.FLAGS | ||
| class ShellScriptTests(basetest.TestCase): | ||
| """TestCase that runs the various *test.sh scripts.""" | ||
| def RunTestScript(self, script_name): | ||
| tests_path = os.path.dirname(__file__) | ||
| sh_test_path = os.path.realpath(os.path.join(tests_path, script_name)) | ||
| path_with_python = ':'.join(( | ||
| os.path.dirname(sys.executable), os.environ.get('PATH'))) | ||
| env = { | ||
| 'PATH': path_with_python, | ||
| # Setuptools puts dependency eggs in our path, so propagate that. | ||
| 'PYTHONPATH': os.pathsep.join(sys.path), | ||
| 'TEST_TMPDIR': FLAGS.test_tmpdir, | ||
| } | ||
| p = subprocess.Popen(sh_test_path, cwd=tests_path, env=env) | ||
| self.assertEqual(0, p.wait()) | ||
| def testBaseTest(self): | ||
| self.RunTestScript('basetest_sh_test.sh') | ||
| def testApp(self): | ||
| self.RunTestScript('app_unittest.sh') | ||
| def testAppCommands(self): | ||
| self.RunTestScript('appcommands_unittest.sh') | ||
| if __name__ == '__main__': | ||
| basetest.main() |
| #!/usr/bin/env python | ||
| # This code must be source compatible with Python 2.4 through 3.3. | ||
| # | ||
| # Copyright 2003 Google Inc. All Rights Reserved. | ||
| """Unittest for shellutil module.""" | ||
| import os | ||
| # Use unittest instead of basetest to avoid bootstrap issues / circular deps. | ||
| import unittest | ||
| from google.apputils import shellutil | ||
| # Running windows? | ||
| win32 = (os.name == 'nt') | ||
| class ShellUtilUnitTest(unittest.TestCase): | ||
| def testShellEscapeList(self): | ||
| # TODO(user): Actually run some shell commands and test the | ||
| # shell escaping works properly. | ||
| # Empty list | ||
| words = [] | ||
| self.assertEqual(shellutil.ShellEscapeList(words), '') | ||
| # Empty string | ||
| words = [''] | ||
| self.assertEqual(shellutil.ShellEscapeList(words), "''") | ||
| # Single word | ||
| words = ['foo'] | ||
| self.assertEqual(shellutil.ShellEscapeList(words), "'foo'") | ||
| # Single word with single quote | ||
| words = ["foo'bar"] | ||
| expected = """ 'foo'"'"'bar' """.strip() | ||
| self.assertEqual(shellutil.ShellEscapeList(words), expected) | ||
| # .. double quote | ||
| words = ['foo"bar'] | ||
| expected = """ 'foo"bar' """.strip() | ||
| self.assertEqual(shellutil.ShellEscapeList(words), expected) | ||
| # Multiple words | ||
| words = ['foo', 'bar'] | ||
| self.assertEqual(shellutil.ShellEscapeList(words), "'foo' 'bar'") | ||
| # Words with spaces | ||
| words = ['foo', 'bar', "foo'' ''bar"] | ||
| expected = """ 'foo' 'bar' 'foo'"'"''"'"' '"'"''"'"'bar' """.strip() | ||
| self.assertEqual(shellutil.ShellEscapeList(words), expected) | ||
| # Now I'm just being mean | ||
| words = ['foo', 'bar', """ ""'"'" """.strip()] | ||
| expected = """ 'foo' 'bar' '""'"'"'"'"'"'"' """.strip() | ||
| self.assertEqual(shellutil.ShellEscapeList(words), expected) | ||
| def testShellifyStatus(self): | ||
| if not win32: | ||
| self.assertEqual(shellutil.ShellifyStatus(0), 0) | ||
| self.assertEqual(shellutil.ShellifyStatus(1), 129) | ||
| self.assertEqual(shellutil.ShellifyStatus(1 * 256), 1) | ||
| if __name__ == '__main__': | ||
| unittest.main() |
| #!/usr/bin/env python | ||
| # Copyright 2006 Google Inc. All Rights Reserved. | ||
| # | ||
| # 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. | ||
| """Tests for the stopwatch module.""" | ||
| __author__ = 'dbentley@google.com (Dan Bentley)' | ||
| from google.apputils import basetest | ||
| import gflags as flags | ||
| from google.apputils import stopwatch | ||
| FLAGS = flags.FLAGS | ||
| class StubTime(object): | ||
| """Simple stub replacement for the time module. | ||
| Only useful for relative calculations, since it always starts at 0. | ||
| """ | ||
| # These method names match the standard library time module. | ||
| def __init__(self): | ||
| self._counter = 0 | ||
| def time(self): | ||
| """Get the time for this time object. | ||
| A call is always guaranteed to be greater than the previous one. | ||
| Returns: | ||
| A monotonically increasing time. | ||
| """ | ||
| self._counter += 0.0001 | ||
| return self._counter | ||
| def sleep(self, time): | ||
| """Simulate sleeping for the specified number of seconds.""" | ||
| self._counter += time | ||
| class StopwatchUnitTest(basetest.TestCase): | ||
| """Stopwatch tests. | ||
| These tests are tricky because timing is difficult. | ||
| Therefore, we test the structure of the results but not the results | ||
| themselves for fear it would lead to intermittent but persistent | ||
| failures. | ||
| """ | ||
| def setUp(self): | ||
| self.time = StubTime() | ||
| stopwatch.time = self.time | ||
| def testResults(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.start() | ||
| sw.stop() | ||
| results = sw.results() | ||
| self.assertListEqual([r[0] for r in results], ['total']) | ||
| results = sw.results(verbose=1) | ||
| self.assertListEqual([r[0] for r in results], ['overhead', 'total']) | ||
| # test tally part of results. | ||
| sw.start('ron') | ||
| sw.stop('ron') | ||
| sw.start('ron') | ||
| sw.stop('ron') | ||
| results = sw.results() | ||
| results = sw.results(verbose=1) | ||
| for r in results: | ||
| if r[0] == 'ron': | ||
| assert r[2] == 2 | ||
| def testSeveralTimes(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.start() | ||
| sw.start('a') | ||
| sw.start('b') | ||
| self.time.sleep(1) | ||
| sw.stop('b') | ||
| sw.stop('a') | ||
| sw.stop() | ||
| results = sw.results(verbose=1) | ||
| self.assertListEqual([r[0] for r in results], | ||
| ['a', 'b', 'overhead', 'total']) | ||
| # Make sure overhead is positive | ||
| self.assertEqual(results[2][1] > 0, 1) | ||
| def testNoStopOthers(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.start() | ||
| sw.start('a') | ||
| sw.start('b', stop_others=0) | ||
| self.time.sleep(1) | ||
| sw.stop('b') | ||
| sw.stop('a') | ||
| sw.stop() | ||
| #overhead should be negative, because we ran two timers simultaneously | ||
| #It is possible that this could fail in outlandish circumstances. | ||
| #If this is a problem in practice, increase the value of the call to | ||
| #time.sleep until it passes consistently. | ||
| #Or, consider finding a platform where the two calls sw.start() and | ||
| #sw.start('a') happen within 1 second. | ||
| results = sw.results(verbose=1) | ||
| self.assertEqual(results[2][1] < 0, 1) | ||
| def testStopNonExistentTimer(self): | ||
| sw = stopwatch.StopWatch() | ||
| self.assertRaises(RuntimeError, sw.stop) | ||
| self.assertRaises(RuntimeError, sw.stop, 'foo') | ||
| def testResultsDoesntCrashWhenUnstarted(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.results() | ||
| def testResultsDoesntCrashWhenUnstopped(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.start() | ||
| sw.results() | ||
| def testTimerValue(self): | ||
| sw = stopwatch.StopWatch() | ||
| self.assertAlmostEqual(0, sw.timervalue('a'), 2) | ||
| sw.start('a') | ||
| self.assertAlmostEqual(0, sw.timervalue('a'), 2) | ||
| self.time.sleep(1) | ||
| self.assertAlmostEqual(1, sw.timervalue('a'), 2) | ||
| sw.stop('a') | ||
| self.assertAlmostEqual(1, sw.timervalue('a'), 2) | ||
| sw.start('a') | ||
| self.time.sleep(1) | ||
| self.assertAlmostEqual(2, sw.timervalue('a'), 2) | ||
| sw.stop('a') | ||
| self.assertAlmostEqual(2, sw.timervalue('a'), 2) | ||
| def testResultsDoesntReset(self): | ||
| sw = stopwatch.StopWatch() | ||
| sw.start() | ||
| self.time.sleep(1) | ||
| sw.start('a') | ||
| self.time.sleep(1) | ||
| sw.stop('a') | ||
| sw.stop() | ||
| res1 = sw.results(verbose=True) | ||
| res2 = sw.results(verbose=True) | ||
| self.assertListEqual(res1, res2) | ||
| if __name__ == '__main__': | ||
| basetest.main() |
+6
| [tox] | ||
| envlist = py27 | ||
| [testenv] | ||
| deps = ez-setup | ||
| commands = python setup.py google_test |
| Metadata-Version: 1.0 | ||
| Name: google-apputils | ||
| Version: 0.4.1 | ||
| Version: 0.4.2 | ||
| Summary: UNKNOWN | ||
@@ -5,0 +5,0 @@ Home-page: http://code.google.com/p/google-apputils-python |
@@ -0,3 +1,7 @@ | ||
| LICENSE | ||
| MANIFEST.in | ||
| README | ||
| ez_setup.py | ||
| setup.py | ||
| tox.ini | ||
| google/__init__.py | ||
@@ -23,2 +27,19 @@ google/apputils/__init__.py | ||
| google_apputils.egg-info/requires.txt | ||
| google_apputils.egg-info/top_level.txt | ||
| google_apputils.egg-info/top_level.txt | ||
| tests/__init__.py | ||
| tests/app_test.py | ||
| tests/app_test_helper.py | ||
| tests/app_unittest.sh | ||
| tests/appcommands_example.py | ||
| tests/appcommands_unittest.sh | ||
| tests/basetest_sh_test.sh | ||
| tests/basetest_test.py | ||
| tests/datelib_unittest.py | ||
| tests/file_util_test.py | ||
| tests/humanize_test.py | ||
| tests/resources_test.py | ||
| tests/sh_test.py | ||
| tests/shellutil_unittest.py | ||
| tests/stopwatch_unittest.py | ||
| tests/data/a | ||
| tests/data/b |
+1
-1
| Metadata-Version: 1.0 | ||
| Name: google-apputils | ||
| Version: 0.4.1 | ||
| Version: 0.4.2 | ||
| Summary: UNKNOWN | ||
@@ -5,0 +5,0 @@ Home-page: http://code.google.com/p/google-apputils-python |
+7
-3
@@ -18,4 +18,8 @@ #!/usr/bin/env python | ||
| import ez_setup | ||
| ez_setup.use_setuptools() | ||
| try: | ||
| import setuptools | ||
| except ImportError: | ||
| import ez_setup | ||
| ez_setup.use_setuptools() | ||
| import setuptools | ||
@@ -54,3 +58,3 @@ from setuptools import setup, find_packages | ||
| name="google-apputils", | ||
| version="0.4.1", | ||
| version="0.4.2", | ||
| packages=find_packages(exclude=["tests"]), | ||
@@ -57,0 +61,0 @@ namespace_packages=["google"], |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
327248
92.94%46
84%6836
70.9%