From ae9e912b62567285dc8bcc90a697f52459a78abf Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 21:52:29 +0100 Subject: [PATCH 01/13] Implement a basic tox.ini based on requirements.txt --- tox.ini | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tox.ini diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..b85191c1 --- /dev/null +++ b/tox.ini @@ -0,0 +1,7 @@ +[tox] +skipsdist = true +envlist = py27,py34,py35 + +[testenv] +deps = -rrequirements.txt +commands = py.test {posargs:tests} From cc74c48588ef872bc7fb1c1ada4374d12a04825c Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 23:04:41 +0100 Subject: [PATCH 02/13] Add .coverage, .tox and .cache to .gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 925680bb..0e0a592c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,8 @@ my_test_project/* # Generated when running py.test for the cookiecutter-django generation tests .cache/ + +# Unit test / coverage reports +.coverage +.tox +.cache From bea23a7a911ff9f73cd23074569e43a746421b17 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 23:05:17 +0100 Subject: [PATCH 03/13] Add pytest-cookies to testenv dependencies --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index b85191c1..a7bb3e97 100644 --- a/tox.ini +++ b/tox.ini @@ -3,5 +3,7 @@ skipsdist = true envlist = py27,py34,py35 [testenv] -deps = -rrequirements.txt +deps = + -rrequirements.txt + pytest-cookies commands = py.test {posargs:tests} From 6c339a14170ea77926bc8eb47bd7e61c80db4a42 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 23:05:32 +0100 Subject: [PATCH 04/13] Implement a basic test with cookies.bake() --- tests/test_cookiecutter_generation.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/test_cookiecutter_generation.py diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py new file mode 100644 index 00000000..e7658809 --- /dev/null +++ b/tests/test_cookiecutter_generation.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +import pytest + +@pytest.fixture +def context(): + return { + "project_name": "My Test Project", + "repo_name": "my_test_project", + "author_name": "Test Author", + "email": "test@example.com", + "description": "A short description of the project.", + "domain_name": "example.com", + "version": "0.1.0", + "timezone": "UTC", + "now": "2015/01/13", + "year": "2015" + } + + +def test_default_configuration(cookies, context): + result = cookies.bake(extra_context=context) + assert result.exit_code == 0 From 646e376a8e9bdc1daaa38ebee2de39e945ab443d Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 23:46:38 +0100 Subject: [PATCH 05/13] Integrate additional checks of base.py with slight improvements --- tests/test_cookiecutter_generation.py | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index e7658809..9fcf42d2 100644 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -1,6 +1,14 @@ # -*- coding: utf-8 -*- +import os +import re + import pytest +from binaryornot.check import is_binary + +PATTERN = "{{(\s?cookiecutter)[.](.*?)}}" +RE_OBJ = re.compile(PATTERN) + @pytest.fixture def context(): @@ -18,6 +26,36 @@ def context(): } +def build_files_list(root_dir): + """Build a list containing absolute paths to the generated files.""" + return [ + os.path.join(dirpath, file_path) + for dirpath, subdirs, files in os.walk(root_dir) + for file_path in files + ] + + +def check_paths(paths): + """Method to check all paths have correct substitutions, + used by other tests cases + """ + # Assert that no match is found in any of the files + for path in paths: + if is_binary(path): + continue + for line in open(path, 'r'): + match = RE_OBJ.search(line) + msg = "cookiecutter variable not replaced in {}" + assert match is None, msg.format(path) + + def test_default_configuration(cookies, context): result = cookies.bake(extra_context=context) assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == context['repo_name'] + assert result.project.isdir() + + paths = build_files_list(str(result.project)) + assert paths + check_paths(paths) From f579cf08ac1098134d1c0701392471a985db0c76 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 8 Nov 2015 23:59:10 +0100 Subject: [PATCH 06/13] Implement parametrized test for enabled features --- tests/test_cookiecutter_generation.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 9fcf42d2..650d4e1f 100644 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -59,3 +59,21 @@ def test_default_configuration(cookies, context): paths = build_files_list(str(result.project)) assert paths check_paths(paths) + + +@pytest.fixture(params=['use_maildump', 'use_celery', 'windows']) +def feature_context(request, context): + context.update({request.param: 'y'}) + return context + + +def test_enabled_features(cookies, feature_context): + result = cookies.bake(extra_context=feature_context) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == feature_context['repo_name'] + assert result.project.isdir() + + paths = build_files_list(str(result.project)) + assert paths + check_paths(paths) From 664c72d291e0c8f62538e837f126fdbcb7db2367 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:02:07 +0100 Subject: [PATCH 07/13] Implement test for flake8 compliance --- tests/test_cookiecutter_generation.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 650d4e1f..74f8947c 100644 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -2,6 +2,7 @@ import os import re +import sh import pytest from binaryornot.check import is_binary @@ -34,7 +35,7 @@ def build_files_list(root_dir): for file_path in files ] - + def check_paths(paths): """Method to check all paths have correct substitutions, used by other tests cases @@ -77,3 +78,13 @@ def test_enabled_features(cookies, feature_context): paths = build_files_list(str(result.project)) assert paths check_paths(paths) + + +def test_flake8_compliance(cookies): + """generated project should pass flake8""" + result = cookies.bake() + + try: + sh.flake8(str(result.project)) + except sh.ErrorReturnCode as e: + pytest.fail(e) From 87025216c29966e975f9d8976eac2242dcd63435 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:12:30 +0100 Subject: [PATCH 08/13] Remove unittest modules altogether --- tests/__init__.py | 0 tests/base.py | 71 ------------------------- tests/test_cookiecutter_substitution.py | 33 ------------ 3 files changed, 104 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/base.py delete mode 100644 tests/test_cookiecutter_substitution.py diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/base.py b/tests/base.py deleted file mode 100644 index 9b15198c..00000000 --- a/tests/base.py +++ /dev/null @@ -1,71 +0,0 @@ -import os -import re -import shutil -import unittest -from os.path import exists, dirname, join - -from binaryornot.check import is_binary -import sh - -from cookiecutter.main import cookiecutter - - -class DjangoCookieTestCase(unittest.TestCase): - - root_dir = dirname(dirname(__file__)) - ctx = {} - destpath = None - - def check_paths(self, paths): - """ - Method to check all paths have correct substitutions, - used by other tests cases - """ - # Construct the cookiecutter search pattern - pattern = "{{(\s?cookiecutter)[.](.*?)}}" - re_obj = re.compile(pattern) - - # Assert that no match is found in any of the files - for path in paths: - if not is_binary(path): - for line in open(path, 'r'): - match = re_obj.search(line) - self.assertIsNone( - match, - "cookiecutter variable not replaced in {}".format(path)) - - def generate_project(self, extra_context=None): - ctx = { - "project_name": "My Test Project", - "repo_name": "my_test_project", - "author_name": "Test Author", - "email": "test@example.com", - "description": "A short description of the project.", - "domain_name": "example.com", - "version": "0.1.0", - "timezone": "UTC", - "now": "2015/01/13", - "year": "2015" - } - if extra_context: - assert isinstance(extra_context, dict) - ctx.update(extra_context) - - self.ctx = ctx - self.destpath = join(self.root_dir, self.ctx['repo_name']) - - cookiecutter(template='./', checkout=None, no_input=True, extra_context=ctx) - - # Build a list containing absolute paths to the generated files - paths = [os.path.join(dirpath, file_path) - for dirpath, subdirs, files in os.walk(self.destpath) - for file_path in files] - return paths - - def clean(self): - if exists(self.destpath): - shutil.rmtree(self.destpath) - sh.cd(self.root_dir) - - def tearDown(self): - self.clean() diff --git a/tests/test_cookiecutter_substitution.py b/tests/test_cookiecutter_substitution.py deleted file mode 100644 index 5ac07406..00000000 --- a/tests/test_cookiecutter_substitution.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import absolute_import -import sh - -from .base import DjangoCookieTestCase - - -class TestCookiecutterSubstitution(DjangoCookieTestCase): - """Test that all cookiecutter instances are substituted""" - - def test_default_configuration(self): - # Build a list containing absolute paths to the generated files - paths = self.generate_project() - self.check_paths(paths) - - def test_maildump_enabled(self): - paths = self.generate_project(extra_context={'use_maildump': 'y'}) - self.check_paths(paths) - - def test_celery_enabled(self): - paths = self.generate_project(extra_context={'use_celery': 'y'}) - self.check_paths(paths) - - def test_windows_enabled(self): - paths = self.generate_project(extra_context={'windows': 'y'}) - self.check_paths(paths) - - def test_flake8_compliance(self): - """generated project should pass flake8""" - self.generate_project() - try: - sh.flake8(self.destpath) - except sh.ErrorReturnCode as e: - raise AssertionError(e) From cca450878c646119d3349b788f8d789c9afddb50 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:32:16 +0100 Subject: [PATCH 09/13] Write docs on running the test suite with tox, resolve #399 --- CONTRIBUTING.rst | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index a6b73259..d05ea0db 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -9,3 +9,48 @@ Getting your pull request merged in #. Keep it small. The smaller the pull request the more likely I'll pull it in. #. Pull requests that fix a current issue get priority for review. #. If you're not already in the `CONTRIBUTORS.rst` file, add yourself! + +Testing +------- + +Installation +~~~~~~~~~~~~ + +Please install `tox`_, which is a generic virtualenv management and test command line tool. + +`tox`_ is available for download from `PyPI`_ via `pip`_:: + + $ pip install tox + +It will automatically create a fresh virtual environment and install our test dependencies, +such as `pytest-cookies`_ and `flake8`_. + +Run the Tests +~~~~~~~~~~~~~ + +Tox uses py.test under the hood, hence it supports the same syntax for selecting tests. + +For further information please consult the `pytest usage docs`_. + +To run all tests using various versions of python in virtualenvs defined in tox.ini, just run tox.:: + + $ tox + +It is possible to tests with some versions of python, to do this the command +is:: + + $ tox -e py27,py34 + +Will run py.test with the python2.7, and python3.4 interpreters, for +example. + +To run a particular test with tox for against your current Python version:: + + $ tox -e py -- -k test_default_configuration + +.. _`pytest usage docs`: https://pytest.org/latest/usage.html#specifying-tests-selecting-tests +.. _`tox`: https://tox.readthedocs.org/en/latest/ +.. _`pip`: https://pypi.python.org/pypi/pip/ +.. _`pytest-cookies`: https://pypi.python.org/pypi/pytest-cookies/ +.. _`flake8`: https://pypi.python.org/pypi/flake8/ +.. _`PyPI`: https://pypi.python.org/pypi From b68e89279fc1eb674677d7e3b2b4dfcaa3d08e18 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:35:21 +0100 Subject: [PATCH 10/13] Add tox v2.1.1 to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 9cb44207..aadbfa9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ pytest==2.8.2 git+git://github.com/mverteuil/pytest-ipdb.git pep8==1.6.2 pyflakes==1.0.0 +tox==2.1.1 From adf10a03baed49f153717e2ab58b2b20e520392c Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:38:52 +0100 Subject: [PATCH 11/13] Update travis config to use tox instead of pytest --- .travis.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 980294d5..4608b31c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,17 @@ -language: python -python: - - 3.5 - - 3.4 - - 2.7 -sudo: false -install: -- pip install -r requirements.txt +# Config file for automatic testing at travis-ci.org -script: - - py.test +sudo: false +language: python +python: 3.5 +env: + - TOX_ENV=py27 + - TOX_ENV=py34 + - TOX_ENV=py35 + +script: tox -e $TOX_ENV + +install: + - pip install tox notifications: email: From 54267d0dce67867e94a8b06017c40332a76fa517 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:41:35 +0100 Subject: [PATCH 12/13] Remove requirements.txt from tox.ini in favor of explicit testenv deps --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a7bb3e97..2cd7a3cb 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,8 @@ envlist = py27,py34,py35 [testenv] deps = - -rrequirements.txt + binaryornot + flake8 pytest-cookies + sh commands = py.test {posargs:tests} From 7664194ab84451b8661906b39392f44eab02d2a3 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Mon, 9 Nov 2015 00:54:48 +0100 Subject: [PATCH 13/13] Ensure that tox passes on certain environment variables --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 2cd7a3cb..deb1dd50 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ skipsdist = true envlist = py27,py34,py35 [testenv] +passenv = LC_ALL, LANG, HOME deps = binaryornot flake8