From 37a05844fbbe5e62db81ffba23d5b72afa3d4014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Larchev=C3=AAque?= Date: Mon, 12 Aug 2013 15:13:07 -0400 Subject: [PATCH] rename package finish testing --- MANIFEST.in | 2 +- auf/__init__.py | 2 + auf/django/__init__.py | 2 + .../django/secretquestions}/__init__.py | 0 .../django/secretquestions}/admin.py | 0 .../django/secretquestions}/conf.py | 0 auf/django/secretquestions/decorators.py | 48 ++++++++++ .../django/secretquestions}/forms.py | 0 .../migrations/0001_initial.py | 0 .../secretquestions}/migrations/__init__.py | 0 .../django/secretquestions}/models.py | 0 .../secretquestions}/templates/base.html | 0 .../templates/secretquestions/setup_form.html | 0 .../templates/secretquestions/step.html | 0 auf/django/secretquestions/tests/__init__.py | 3 + auf/django/secretquestions/tests/common.py | 92 +++++++++++++++++++ .../secretquestions}/tests/configuration.py | 29 +++++- .../django/secretquestions}/tests/settings.py | 6 +- auf/django/secretquestions/tests/token.py | 52 +++++++++++ auf/django/secretquestions/tests/urls.py | 21 +++++ .../django/secretquestions}/tests/use.py | 24 ++--- auf/django/secretquestions/tests/views.py | 21 +++++ .../django/secretquestions}/urls.py | 2 +- .../django/secretquestions}/views.py | 0 secretquestions/decorators.py | 43 --------- secretquestions/tests/__init__.py | 2 - secretquestions/tests/common.py | 40 -------- secretquestions/tests/urls.py | 16 ---- secretquestions/tests/views.py | 14 --- setup.py | 8 +- tox.ini | 12 +-- 31 files changed, 289 insertions(+), 150 deletions(-) create mode 100644 auf/__init__.py create mode 100644 auf/django/__init__.py rename {secretquestions => auf/django/secretquestions}/__init__.py (100%) rename {secretquestions => auf/django/secretquestions}/admin.py (100%) rename {secretquestions => auf/django/secretquestions}/conf.py (100%) create mode 100644 auf/django/secretquestions/decorators.py rename {secretquestions => auf/django/secretquestions}/forms.py (100%) rename {secretquestions => auf/django/secretquestions}/migrations/0001_initial.py (100%) rename {secretquestions => auf/django/secretquestions}/migrations/__init__.py (100%) rename {secretquestions => auf/django/secretquestions}/models.py (100%) rename {secretquestions => auf/django/secretquestions}/templates/base.html (100%) rename {secretquestions => auf/django/secretquestions}/templates/secretquestions/setup_form.html (100%) rename {secretquestions => auf/django/secretquestions}/templates/secretquestions/step.html (100%) create mode 100644 auf/django/secretquestions/tests/__init__.py create mode 100644 auf/django/secretquestions/tests/common.py rename {secretquestions => auf/django/secretquestions}/tests/configuration.py (75%) rename {secretquestions => auf/django/secretquestions}/tests/settings.py (74%) create mode 100644 auf/django/secretquestions/tests/token.py create mode 100644 auf/django/secretquestions/tests/urls.py rename {secretquestions => auf/django/secretquestions}/tests/use.py (90%) create mode 100644 auf/django/secretquestions/tests/views.py rename {secretquestions => auf/django/secretquestions}/urls.py (72%) rename {secretquestions => auf/django/secretquestions}/views.py (100%) delete mode 100644 secretquestions/decorators.py delete mode 100644 secretquestions/tests/__init__.py delete mode 100644 secretquestions/tests/common.py delete mode 100644 secretquestions/tests/urls.py delete mode 100644 secretquestions/tests/views.py diff --git a/MANIFEST.in b/MANIFEST.in index 943440d..1bf6e0d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -recursive-include secretquestions/templates * +recursive-include auf/django/secretquestions/templates * diff --git a/auf/__init__.py b/auf/__init__.py new file mode 100644 index 0000000..ece379c --- /dev/null +++ b/auf/__init__.py @@ -0,0 +1,2 @@ +import pkg_resources +pkg_resources.declare_namespace(__name__) diff --git a/auf/django/__init__.py b/auf/django/__init__.py new file mode 100644 index 0000000..ece379c --- /dev/null +++ b/auf/django/__init__.py @@ -0,0 +1,2 @@ +import pkg_resources +pkg_resources.declare_namespace(__name__) diff --git a/secretquestions/__init__.py b/auf/django/secretquestions/__init__.py similarity index 100% rename from secretquestions/__init__.py rename to auf/django/secretquestions/__init__.py diff --git a/secretquestions/admin.py b/auf/django/secretquestions/admin.py similarity index 100% rename from secretquestions/admin.py rename to auf/django/secretquestions/admin.py diff --git a/secretquestions/conf.py b/auf/django/secretquestions/conf.py similarity index 100% rename from secretquestions/conf.py rename to auf/django/secretquestions/conf.py diff --git a/auf/django/secretquestions/decorators.py b/auf/django/secretquestions/decorators.py new file mode 100644 index 0000000..7e16777 --- /dev/null +++ b/auf/django/secretquestions/decorators.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +from datetime import timedelta, datetime +import re + +from django.shortcuts import redirect +from django.utils.translation import ugettext as _ + +from django.contrib import messages + +from .views import SecretQuestionWizard +from .conf import SQ_SESSION_KEY, SQ_TOKEN_TTL + + +def secret_questions_required(ttl=SQ_TOKEN_TTL): + + def _inner(view): + + def _wrapped(request, *args, **kwargs): + session_token, url, date = request.session.get(SQ_SESSION_KEY, + (None, + None, + datetime.now(),)) + get_token = request.GET.get(SQ_SESSION_KEY, None) + date_max = date + timedelta(seconds=ttl) + + if session_token is None or get_token is None: + wiz = SecretQuestionWizard(request) + return wiz(request, *args, **kwargs) + + if date_max < datetime.now() or \ + not request.get_full_path().startswith(url): + if request.method == "POST": + messages.error(request, + _("Your modifications were canceled.")) + url = request.get_full_path() + regex_no_session_key = "(.*)%s=[a..z0..9]*(.*)" % \ + SQ_SESSION_KEY + clean_url = re.sub(regex_no_session_key, "\\1", url) + return redirect(clean_url) + + if session_token == get_token: + return view(request, *args, **kwargs) + + # should not be raised + raise Exception('SQ') # pragma: no cover + return _wrapped + return _inner diff --git a/secretquestions/forms.py b/auf/django/secretquestions/forms.py similarity index 100% rename from secretquestions/forms.py rename to auf/django/secretquestions/forms.py diff --git a/secretquestions/migrations/0001_initial.py b/auf/django/secretquestions/migrations/0001_initial.py similarity index 100% rename from secretquestions/migrations/0001_initial.py rename to auf/django/secretquestions/migrations/0001_initial.py diff --git a/secretquestions/migrations/__init__.py b/auf/django/secretquestions/migrations/__init__.py similarity index 100% rename from secretquestions/migrations/__init__.py rename to auf/django/secretquestions/migrations/__init__.py diff --git a/secretquestions/models.py b/auf/django/secretquestions/models.py similarity index 100% rename from secretquestions/models.py rename to auf/django/secretquestions/models.py diff --git a/secretquestions/templates/base.html b/auf/django/secretquestions/templates/base.html similarity index 100% rename from secretquestions/templates/base.html rename to auf/django/secretquestions/templates/base.html diff --git a/secretquestions/templates/secretquestions/setup_form.html b/auf/django/secretquestions/templates/secretquestions/setup_form.html similarity index 100% rename from secretquestions/templates/secretquestions/setup_form.html rename to auf/django/secretquestions/templates/secretquestions/setup_form.html diff --git a/secretquestions/templates/secretquestions/step.html b/auf/django/secretquestions/templates/secretquestions/step.html similarity index 100% rename from secretquestions/templates/secretquestions/step.html rename to auf/django/secretquestions/templates/secretquestions/step.html diff --git a/auf/django/secretquestions/tests/__init__.py b/auf/django/secretquestions/tests/__init__.py new file mode 100644 index 0000000..acfcacb --- /dev/null +++ b/auf/django/secretquestions/tests/__init__.py @@ -0,0 +1,3 @@ +from .configuration import ConfigurationTest +from .use import UseTest +from .token import TokenTest diff --git a/auf/django/secretquestions/tests/common.py b/auf/django/secretquestions/tests/common.py new file mode 100644 index 0000000..937721c --- /dev/null +++ b/auf/django/secretquestions/tests/common.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +import re + +from django.test import TestCase +from django.test.client import Client + +from django.contrib.auth.models import User + +from auf.django.secretquestions.models import Question, Answer, crypt_answer + + +class SecretQuestionTest(TestCase): + + client = Client() + username = 'paul' + password = 'lemay' + + def setUp(self): + self.create_user() + self.create_questions() + + def create_user(self): + self.user = User.objects.create(username=self.username) + self.user.set_password(self.password) + self.user.save() + + def create_questions(self): + self.question1 = Question.objects.create(text="question1") + self.question1.save() + self.question2 = Question.objects.create(text="question2") + self.question2.save() + + def create_answers(self): + self.answer1 = Answer.objects.create(question=self.question1, + secret=crypt_answer('one'), + user=self.user) + self.answer1.save() + self.answer2 = Answer.objects.create(question=self.question2, + secret=crypt_answer('two'), + user=self.user) + self.answer2.save() + + def _get_hashs(self, response): + """ + Parse response to prepare POST according previous hash + """ + regex_hash = 'name="(hash_[0-9])+" value="([a-z0-9]+)"' + found = re.findall(regex_hash, response.content) + hashs = {} + for k, v in found: + hashs.update({k: v}) + return hashs + + def get_response_from_final_step(self, url): + self.create_answers() + + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + data = {'wizard_step': 0, + '0-username': self.username, } + response = self.client.post(url, data) + self.assertEqual(response.status_code, 200) + self.assertTrue(self.question1.text in response.content) + + # wrong response + data = {'wizard_step': 1, + '0-username': self.username, + '1-raw_answer': 'wrong answer', } + data.update(self._get_hashs(response)) + response = self.client.post(url, data) + + self.assertEqual(response.status_code, 200) + self.assertFalse('2-raw_answer' in response.content) + + # good response + data = {'wizard_step': 1, + '0-username': self.username, + '1-raw_answer': 'one', } + data.update(self._get_hashs(response)) + response = self.client.post(url, data) + self.assertEqual(response.status_code, 200) + self.assertTrue('2-raw_answer' in response.content) + + # good response + data = {'wizard_step': 2, + '0-username': self.username, + '1-raw_answer': 'one', + '2-raw_answer': 'two', } + data.update(self._get_hashs(response)) + response = self.client.post(url, data) + return response diff --git a/secretquestions/tests/configuration.py b/auf/django/secretquestions/tests/configuration.py similarity index 75% rename from secretquestions/tests/configuration.py rename to auf/django/secretquestions/tests/configuration.py index 03ed23d..943b840 100644 --- a/secretquestions/tests/configuration.py +++ b/auf/django/secretquestions/tests/configuration.py @@ -3,8 +3,9 @@ from django.core.urlresolvers import reverse from django.conf import settings -from secretquestions.tests.common import SecretQuestionTest -from secretquestions.models import Answer +from auf.django.secretquestions.models import Answer + +from .common import SecretQuestionTest class ConfigurationTest(SecretQuestionTest): @@ -55,6 +56,30 @@ class ConfigurationTest(SecretQuestionTest): self.assertNotEqual(answer.secret, raw_password) self.assertNotEqual(answer.secret, '') + def test_setting_2_same_questions(self): + """ + Check if error is raised if you choose 2 same questions + """ + raw_password = 'xxx' + self.assertEqual(self.client.login(username=self.username, + password=self.password), True) + url = reverse('sq_setup') + + data = {'form-TOTAL_FORMS': u'2', + 'form-INITIAL_FORMS': u'0', + 'form-MAX_NUM_FORMS': u'', + 'form-0-question': self.question1.id, + 'form-0-secret': raw_password, + 'form-1-question': self.question1.id, + 'form-1-secret': raw_password, } + + response = self.client.post(url, data) + self.assertEqual(response.status_code, 200) + answers = Answer.objects.filter(user=self.user) + self.assertEqual(len(answers), 0) + self.assertTrue( + "Each question has to be different." in response.content) + def test_setting_empty_answer_for_one_question(self): """ Check if the answer is not empty diff --git a/secretquestions/tests/settings.py b/auf/django/secretquestions/tests/settings.py similarity index 74% rename from secretquestions/tests/settings.py rename to auf/django/secretquestions/tests/settings.py index 1deaf72..1931313 100644 --- a/secretquestions/tests/settings.py +++ b/auf/django/secretquestions/tests/settings.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- +USE_I18N = False + SECRET_KEY = 'secret' -ROOT_URLCONF = 'secretquestions.tests.urls' +ROOT_URLCONF = 'auf.django.secretquestions.tests.urls' DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', }} @@ -12,4 +14,4 @@ INSTALLED_APPS = ('django.contrib.auth', 'django.contrib.sessions', 'django.contrib.admin', 'registration', - 'secretquestions',) + 'auf.django.secretquestions',) diff --git a/auf/django/secretquestions/tests/token.py b/auf/django/secretquestions/tests/token.py new file mode 100644 index 0000000..8c6885e --- /dev/null +++ b/auf/django/secretquestions/tests/token.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + + +import time + +from django.core.urlresolvers import reverse + +from .common import SecretQuestionTest +from .views import TTL + + +class TokenTest(SecretQuestionTest): + """ + TestCase for token testing + """ + + def test_expiracy(self): + """ + Check if you try to access page after X times. + """ + url = reverse('sq_test_private_ttl') + response = self.get_response_from_final_step(url) + location = response['location'] + + response = self.client.get(location) + self.assertEqual(response.status_code, 200) + self.assertTrue('OK' in response.content) + time.sleep(TTL+1) + response = self.client.get(location) + self.assertEqual(response.status_code, 302) + redirect = response['location'].replace('http://testserver', '') + self.assertEqual(redirect, url) + + def test_warning(self): + """ + Check if you try to access page after X times. + """ + url = reverse('sq_test_private_ttl') + response = self.get_response_from_final_step(url) + location = response['location'] + + response = self.client.get(location) + self.assertEqual(response.status_code, 200) + self.assertTrue('OK' in response.content) + time.sleep(TTL+1) + response = self.client.post(location, {}) + self.assertEqual(response.status_code, 302) + redirect = response['location'].replace('http://testserver', '') + self.assertEqual(redirect, url) + response = self.client.get(url) + messages = [m.message for m in response.context['messages']] + self.assertTrue("Your modifications were canceled." in messages) diff --git a/auf/django/secretquestions/tests/urls.py b/auf/django/secretquestions/tests/urls.py new file mode 100644 index 0000000..7609c90 --- /dev/null +++ b/auf/django/secretquestions/tests/urls.py @@ -0,0 +1,21 @@ +from django.conf.urls.defaults import patterns, include, url + +from django.contrib import admin + +admin.autodiscover() + +urlpatterns = patterns( + '', + (r'^admin/(.*)', include(admin.site.urls)), + (r'^accounts/', include('registration.urls')), + (r'^secret/', + include('auf.django.secretquestions.urls')), + url(r'^test_public/', + 'auf.django.secretquestions.tests.views.public', + name='sq_test_public'), + url(r'^test_private/', + 'auf.django.secretquestions.tests.views.private', + name='sq_test_private'), + url(r'^test_private_ttl/', + 'auf.django.secretquestions.tests.views.private_ttl', + name='sq_test_private_ttl'),) diff --git a/secretquestions/tests/use.py b/auf/django/secretquestions/tests/use.py similarity index 90% rename from secretquestions/tests/use.py rename to auf/django/secretquestions/tests/use.py index 955dcf4..226f254 100644 --- a/secretquestions/tests/use.py +++ b/auf/django/secretquestions/tests/use.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -import re - from django.core.urlresolvers import reverse -from secretquestions.tests.common import SecretQuestionTest -from secretquestions.conf import SQ_SESSION_KEY +from auf.django.secretquestions import conf + +from .common import SecretQuestionTest class UseTest(SecretQuestionTest): @@ -72,7 +71,7 @@ class UseTest(SecretQuestionTest): self.assertFalse('OK' in response.content) self.assertFalse('username' in response.content) self.assertTrue(url in response['location']) - self.assertTrue(SQ_SESSION_KEY in response['location']) + self.assertTrue(conf.SQ_SESSION_KEY in response['location']) def test_username_form(self): """ @@ -91,18 +90,7 @@ class UseTest(SecretQuestionTest): response = self.client.post(url, data) self.assertEqual(response.status_code, 302) self.assertTrue(url in response['location']) - self.assertTrue(SQ_SESSION_KEY in response['location']) - - def _get_hashs(self, response): - """ - Parse response to prepare POST according previous hash - """ - regex_hash = 'name="(hash_[0-9])+" value="([a-z0-9]+)"' - found = re.findall(regex_hash, response.content) - hashs = {} - for k, v in found: - hashs.update({k: v}) - return hashs + self.assertTrue(conf.SQ_SESSION_KEY in response['location']) def test_question_form(self): """ @@ -146,7 +134,7 @@ class UseTest(SecretQuestionTest): response = self.client.post(url, data) self.assertEqual(response.status_code, 302) self.assertTrue(url in response['location']) - self.assertTrue(SQ_SESSION_KEY in response['location']) + self.assertTrue(conf.SQ_SESSION_KEY in response['location']) response = self.client.get(response['location']) self.assertTrue('OK' in response.content) diff --git a/auf/django/secretquestions/tests/views.py b/auf/django/secretquestions/tests/views.py new file mode 100644 index 0000000..5d97413 --- /dev/null +++ b/auf/django/secretquestions/tests/views.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from django.http import HttpResponse + +from auf.django.secretquestions.decorators import secret_questions_required + +TTL = 1 + + +def public(request): + return HttpResponse("OK") + + +@secret_questions_required() +def private(request): + return HttpResponse("OK") + + +@secret_questions_required(ttl=TTL) +def private_ttl(request): + return HttpResponse("OK") diff --git a/secretquestions/urls.py b/auf/django/secretquestions/urls.py similarity index 72% rename from secretquestions/urls.py rename to auf/django/secretquestions/urls.py index d2198f9..9d19b1b 100644 --- a/secretquestions/urls.py +++ b/auf/django/secretquestions/urls.py @@ -4,5 +4,5 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('', url(r'questions/setup$', - 'secretquestions.views.setup_form', + 'auf.django.secretquestions.views.setup_form', name="sq_setup"), ) diff --git a/secretquestions/views.py b/auf/django/secretquestions/views.py similarity index 100% rename from secretquestions/views.py rename to auf/django/secretquestions/views.py diff --git a/secretquestions/decorators.py b/secretquestions/decorators.py deleted file mode 100644 index 9bbd99f..0000000 --- a/secretquestions/decorators.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- - -from datetime import timedelta, datetime -import re - -from django.shortcuts import redirect -from django.utils.translation import ugettext as _ - -from django.contrib import messages - -from .views import SecretQuestionWizard -from .conf import SQ_SESSION_KEY, SQ_TOKEN_TTL - - -def secret_questions_required(view, ttl=SQ_TOKEN_TTL): - def _wrapped(request, *args, **kwargs): - session_token, url, date = request.session.get(SQ_SESSION_KEY, - (None, - None, - datetime.now() - )) - get_token = request.GET.get(SQ_SESSION_KEY, None) - date_max = date + timedelta(seconds=ttl) - - if session_token is None or get_token is None: - wiz = SecretQuestionWizard(request) - return wiz(request, *args, **kwargs) - - if date_max < datetime.now() or \ - not request.get_full_path().startswith(url): - if request.method == "POST": - messages.error(request, _("Your modifications were canceled.")) - url = request.get_full_path() - regex_no_session_key = "(.*)%s=[a..z0..9]*(.*)" % SQ_SESSION_KEY - clean_url = re.sub(regex_no_session_key, "\\1", url) - return redirect(clean_url) - - if session_token == get_token: - return view(request, *args, **kwargs) - - raise Exception('SQ') - - return _wrapped diff --git a/secretquestions/tests/__init__.py b/secretquestions/tests/__init__.py deleted file mode 100644 index 617f330..0000000 --- a/secretquestions/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from configuration import ConfigurationTest -from use import UseTest diff --git a/secretquestions/tests/common.py b/secretquestions/tests/common.py deleted file mode 100644 index b2d644f..0000000 --- a/secretquestions/tests/common.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.test import TestCase -from django.test.client import Client - -from django.contrib.auth.models import User - -from secretquestions.models import Question, Answer, crypt_answer - - -class SecretQuestionTest(TestCase): - - client = Client() - username = 'paul' - password = 'lemay' - - def setUp(self): - self.create_user() - self.create_questions() - - def create_user(self): - self.user = User.objects.create(username=self.username) - self.user.set_password(self.password) - self.user.save() - - def create_questions(self): - self.question1 = Question.objects.create(text="question1") - self.question1.save() - self.question2 = Question.objects.create(text="question2") - self.question2.save() - - def create_answers(self): - self.answer1 = Answer.objects.create(question=self.question1, - secret=crypt_answer('one'), - user=self.user) - self.answer1.save() - self.answer2 = Answer.objects.create(question=self.question2, - secret=crypt_answer('two'), - user=self.user) - self.answer2.save() diff --git a/secretquestions/tests/urls.py b/secretquestions/tests/urls.py deleted file mode 100644 index b0dd12e..0000000 --- a/secretquestions/tests/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.conf.urls.defaults import patterns, include, url - -from django.contrib import admin - -admin.autodiscover() - -urlpatterns = patterns('', - (r'^admin/(.*)', include(admin.site.urls)), - (r'^accounts/', include('registration.urls')), - (r'^secret/', include('secretquestions.urls')), - url(r'^test_public/', - 'secretquestions.tests.views.public', - name='sq_test_public'), - url(r'^test_private/', - 'secretquestions.tests.views.private', - name='sq_test_private'),) diff --git a/secretquestions/tests/views.py b/secretquestions/tests/views.py deleted file mode 100644 index 4d1d191..0000000 --- a/secretquestions/tests/views.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.http import HttpResponse - -from secretquestions.decorators import secret_questions_required - - -def public(request): - return HttpResponse("OK") - - -@secret_questions_required -def private(request): - return HttpResponse("OK") diff --git a/setup.py b/setup.py index 5061f71..6e878f8 100644 --- a/setup.py +++ b/setup.py @@ -2,8 +2,9 @@ from setuptools import setup, find_packages import sys, os version = '0.0' +name = 'auf.django.secretquestions' -setup(name='django-secretquestions', +setup(name=name, version=version, description="Provides secret questions toolkit", long_description="""\ @@ -12,9 +13,10 @@ setup(name='django-secretquestions', keywords='django secretquestions authentication security', author='Olivier Larchev\xc3\xaaque', author_email='olivier.larcheveque@auf.org', - url='', - license='', + url='http://pypi.auf.org/%s' % name, + license='GPL', packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), + namespace_packages = ['auf'], include_package_data=True, zip_safe=False, install_requires=[ diff --git a/tox.ini b/tox.ini index ba79398..95f0919 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = django1.3, django1.4 +envlist = django1.3 [testenv] deps = @@ -9,16 +9,12 @@ deps = commands = coverage erase - coverage run --source="{envsitepackagesdir}/secretquestions/" {envdir}/bin/django-admin.py test secretquestions --settings=secretquestions.tests.settings - pep8 -r --statistics --count {envsitepackagesdir}/secretquestions/ --exclude={envsitepackagesdir}/secretquestions/migrations/* + coverage run --source="{envsitepackagesdir}/auf/django/secretquestions/" {envdir}/bin/django-admin.py test secretquestions --settings=auf.django.secretquestions.tests.settings + pep8 -r --statistics --count {envsitepackagesdir}/auf/django/secretquestions/ --exclude={envsitepackagesdir}/auf/django/secretquestions/migrations/* coverage report + coverage html [testenv:django1.3] deps = {[testenv]deps} django==1.3 - -[testenv:django1.4] -deps = - {[testenv]deps} - django==1.4