Skip to content

Commit c172020

Browse files
author
Pamela McA'Nulty
committed
Very ugly version of test_integration
Only supports 2.7 w/ DJ 1.6, 1.7 and 1.8 so far
1 parent 6ca6525 commit c172020

File tree

3 files changed

+295
-0
lines changed

3 files changed

+295
-0
lines changed

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
sudo: false
2+
language: python
3+
python:
4+
- "2.7"
5+
- "3.4"
6+
- "3.5"
7+
- "3.6"
8+
env:
9+
- DJANGO="1.4"
10+
- DJANGO="1.5"
11+
- DJANGO="1.6"
12+
- DJANGO="1.7"
13+
- DJANGO="1.8"
14+
- DJANGO="1.9"
15+
- DJANGO="1.10"
16+
17+
install: pip install tox-travis
18+
script: tox

tests/test_integration.py

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2+
# For details: https://github.com/nedbat/django_coverage_plugin/blob/master/NOTICE.txt
3+
4+
"""Settings tests for django_coverage_plugin."""
5+
6+
import os
7+
import subprocess
8+
import shutil
9+
10+
from .plugin_test import DjangoPluginTestCase
11+
12+
import django
13+
14+
15+
VIEW_FUNC_TEXT = """
16+
def target_view(request):
17+
return render(
18+
request,
19+
"target_template.html",
20+
{"varA": 1212, "varB": "DcDc"},
21+
)
22+
"""
23+
TEMPLATE_FILE_TEXT = """<!DOCTYPE html>
24+
<html lang="en">
25+
<head>
26+
<meta charset="UTF-8">
27+
<title>Example: {{ varA }}</title>
28+
</head>
29+
<body>
30+
{% if varA %}
31+
{{ varA }}
32+
{% endif %}
33+
<br/>
34+
{% if varA %}
35+
{{ varB }}
36+
{% endif %}
37+
</body>
38+
</html>
39+
"""
40+
COVERAGE_CFG_FILE_TEXT = """
41+
[run]
42+
plugins =
43+
django_coverage_plugin
44+
45+
omit = .tox
46+
47+
[report]
48+
ignore_errors = True
49+
50+
[combine]
51+
ignore_errors = True
52+
"""
53+
TEST_VIEWS_FILE_TEXT = """
54+
import django
55+
from django.test import TestCase
56+
57+
if django.VERSION >= (1, 8):
58+
from app_template_render.views import target_view
59+
60+
class TestViews(TestCase):
61+
def test_view_target_view(self):
62+
from django.core.urlresolvers import reverse
63+
64+
if django.VERSION < (1, 8):
65+
target_view = "app_template_render.views.target_view"
66+
else:
67+
global target_view
68+
69+
resp = self.client.get(reverse(target_view))
70+
for expected in['1212', 'DcDc']:
71+
self.assertContains(resp, expected)
72+
self.assertContains(resp, '<title>Example: 1212</title>')
73+
74+
"""
75+
76+
77+
class IntegrationTest(DjangoPluginTestCase):
78+
"""Tests greenfield settings initializations and other weirdnesses"""
79+
80+
def setUp(self):
81+
self.python = os.path.abspath(os.environ['_'])
82+
self.env_bin = os.path.dirname(self.python)
83+
84+
def set_cwd(self, path):
85+
self.cwd = path
86+
87+
def _cmd(self, *args, **kwargs):
88+
try:
89+
return subprocess.check_output(args, cwd=self.cwd, stderr=subprocess.STDOUT, **kwargs).strip()
90+
except subprocess.CalledProcessError as e:
91+
raise Exception("Called Processed Error:\n cmd: %s\n exc: %s\n output:\n%s" % (args, e, e.output))
92+
93+
def _pycmd(self, *args, **kwargs):
94+
args = [self.python] + list(args)
95+
return self._cmd(*args, **kwargs)
96+
97+
def _cmd_global(self, *args, **kwargs):
98+
args = list(args)
99+
args[0] = os.path.join(self.env_bin, args[0])
100+
return self._cmd(*args, **kwargs)
101+
102+
def _start_project(self, project_name):
103+
self.project_dir = os.path.join(os.getcwd(), project_name)
104+
if os.path.exists(self.project_dir):
105+
shutil.rmtree(self.project_dir)
106+
output = self._cmd("django-admin.py", "startproject", project_name)
107+
self.assertFalse(output)
108+
self.settings_file = os.path.join(self.project_dir, project_name, "settings.py")
109+
if django.VERSION < (1, 6):
110+
with open(self.settings_file) as f:
111+
data = f.read()
112+
data = data.replace("'django.db.backends.'", "'django.db.backends.sqlite3'")
113+
with open(self.settings_file, "w") as f:
114+
f.write(data)
115+
self._add_installed_app("django_coverage_plugin")
116+
self.addCleanup(shutil.rmtree, self.project_dir)
117+
return output
118+
119+
def _add_installed_app(self, app_name):
120+
with open(self.settings_file) as f:
121+
settings_data = f.read()
122+
before, after = settings_data.split("INSTALLED_APPS = (", 1)
123+
apps, after = after.split(")", 1)
124+
apps = "%s\n '%s',\n" % (apps, app_name)
125+
settings_data = "%sINSTALLED_APPS = (%s)%s" % (before, apps, after)
126+
self._save_py_file(self.settings_file, settings_data)
127+
128+
def _save_py_file(self, path, data, show_data=False):
129+
with open(path, "w") as f:
130+
f.write(data)
131+
pyc_path = "%sc" % path
132+
if os.path.exists(pyc_path):
133+
os.remove(pyc_path)
134+
135+
def _start_app(self, app_name):
136+
self.set_cwd(self.project_dir)
137+
output = self._cmd("./manage.py", "startapp", app_name)
138+
self.assertFalse(output)
139+
self._add_installed_app(app_name)
140+
141+
def _run_coverage(self, *args):
142+
self.set_cwd(self.project_dir)
143+
output = self._cmd("coverage", "run", "--rcfile", self.config_file, *args)
144+
env = os.environ.copy()
145+
env['DJANGO_SETTINGS_MODULE'] = self.settings_file
146+
coverage_report = self._cmd("coverage", "report", "-m", "--rcfile", self.config_file, env=env)
147+
coverage_report = self.parse_coverage_report(coverage_report)
148+
return output, coverage_report
149+
150+
def _create_django_project(self, project_name, app_name):
151+
self.cwd = os.getcwd()
152+
self._start_project(project_name)
153+
self._start_app(app_name)
154+
#with open(self.settings_file) as f:
155+
# print f.read()
156+
self.config_file = self._add_project_file(COVERAGE_CFG_FILE_TEXT, "coverage.cfg")
157+
self.template_file = self._add_project_file(TEMPLATE_FILE_TEXT, app_name, "templates", "target_template.html")
158+
self.test_views_file = self._add_project_file(TEST_VIEWS_FILE_TEXT, app_name, "test_views.py")
159+
self.views_file = os.path.join(self.project_dir, app_name, "views.py")
160+
self.urls_file = os.path.join(self.project_dir, project_name, "urls.py")
161+
162+
self._add_view_function(app_name, VIEW_FUNC_TEXT)
163+
self._add_url(project_name, app_name, "target_view", "target_view")
164+
165+
def _add_project_file(self, file_data, *path):
166+
file_path = os.path.join(self.project_dir, *path)
167+
try:
168+
os.makedirs(os.path.dirname(file_path), )
169+
except os.error:
170+
pass
171+
172+
with open(file_path, "w") as f:
173+
f.write(file_data)
174+
return file_path
175+
176+
def _add_view_function(self, app_name, view_text):
177+
with open(self.views_file) as f:
178+
views_data = f.read()
179+
views_data = "%s\n%s\n" % (views_data, view_text)
180+
self._save_py_file(self.views_file, views_data)
181+
182+
183+
def _add_url(self, project_name, app_name, view_func, view_name):
184+
with open(self.urls_file) as f:
185+
urls_data = f.read()
186+
187+
if django.VERSION < (1, 8):
188+
urls_data = urls_data.replace(
189+
"\n)\n",
190+
" url(r'^$', '%(app_name)s.views.target_view', name='target_view')\n)\n" % locals(),
191+
)
192+
else:
193+
urls_data = urls_data.replace("urlpatterns = [", "import %s.views\n\nurlpatterns = [" % app_name)
194+
fmt = ''' url(r'^%(app_name)s/', %(app_name)s.views.%(view_func)s),\n]'''
195+
urls_data = urls_data.replace("]", fmt % locals())
196+
self._save_py_file(self.urls_file, urls_data)
197+
198+
def test_template_render(self):
199+
self._create_django_project("integration_template_render", "app_template_render")
200+
201+
output, coverage_report = self._run_coverage("manage.py", "test", "app_template_render")
202+
self.assertIn("\nOK\n", output)
203+
self.assertIn("Ran 1 test", output)
204+
self.assertNotIn("ERROR", output)
205+
self.assertNotIn("FAIL", output)
206+
207+
import pprint;pprint.pprint(coverage_report)
208+
self.assertIsCovered(coverage_report, "integration_template_render/settings.py")
209+
self.assertIsCovered(coverage_report, "integration_template_render/__init__.py")
210+
self.assertIsCovered(coverage_report, "integration_template_render/urls.py")
211+
self.assertIsCovered(coverage_report, "manage.py")
212+
self.assertIsCovered(coverage_report, "app_template_render/__init__.py")
213+
self.assertIsCovered(coverage_report, "app_template_render/views.py")
214+
self.assertIsCovered(coverage_report, "app_template_render/templates/target_template.html")
215+
216+
def assertIsCovered(self, cov_report, path, expect_missing=0, expect_pct=100):
217+
fmt = u"%s [%s] expected: %%r, got %%r"
218+
info = cov_report[path]
219+
fmt = fmt % (path, info)
220+
self.assertEqual(info.num_missing, expect_missing, fmt % (expect_missing, info.num_missing))
221+
self.assertEqual(info.pct, expect_pct, fmt % (expect_pct, info.pct))
222+
223+
def parse_coverage_report(self, report):
224+
class ReportInfo(object):
225+
def __init__(self, num_lines, num_missing, pct, missing):
226+
self.num_lines = num_lines
227+
self.num_missing = num_missing
228+
self.pct = int(pct[:-1])
229+
self.missing = missing
230+
231+
def __unicode__(self):
232+
return u"%s/%s/%s/%s" % (self.num_lines, self.num_missing, self.pct, self.missing)
233+
234+
def __repr__(self):
235+
return u"ReportInfo(%r, %r, %r, %r)" % (self.num_lines, self.num_missing, self.pct, self.missing)
236+
237+
report_dict = {}
238+
for line in report.splitlines():
239+
if "/.tox/" in line:
240+
continue
241+
pieces = line.split(None, 4)
242+
if len(pieces) not in (4, 5):
243+
continue
244+
245+
if pieces[3][-1] != '%':
246+
continue
247+
if pieces[0] in ("Name", "TOTAL"):
248+
continue
249+
250+
if len(pieces) == 4:
251+
file, num_lines, num_missing, pct = pieces
252+
missing = ""
253+
elif len(pieces) == 5:
254+
file, num_lines, num_missing, pct, missing = pieces
255+
else:
256+
continue
257+
258+
report_dict[file] = ReportInfo(int(num_lines), int(num_missing), pct, missing)
259+
return report_dict

tox.ini

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,21 @@ deps =
5252

5353
commands =
5454
rst2html.py --strict README.rst /tmp/django_coverage_plugin_README.html
55+
56+
[travis]
57+
python =
58+
2.7: py27
59+
3.4: py34
60+
3.5: py35
61+
3.6: py36, doc, check
62+
63+
[travis:env]
64+
DJANGO =
65+
1.4: django14
66+
1.5: django15
67+
1.6: django16
68+
1.7: django17
69+
1.8: django18
70+
1.9: django19
71+
1.10: django110, docs
72+
1.10: django110

0 commit comments

Comments
 (0)