diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2011-02-04 23:20:13 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2011-02-04 23:20:13 -0500 |
commit | 460265da2e04bf22363a245c0fb44c2b6634d065 (patch) | |
tree | 6c2929594098df80e0f774905338afa9b6ad658f | |
parent | 291fdfb6f18ef3c06c2e04cdcf18fb4b9166aa2f (diff) | |
parent | e349d6bc861910456ec9d74ad51d3a147b09a112 (diff) | |
download | python-coveragepy-460265da2e04bf22363a245c0fb44c2b6634d065.tar.gz |
Automated merge with ssh://bitbucket.org/ned/coveragepy
35 files changed, 165 insertions, 64 deletions
@@ -9,6 +9,7 @@ syntax: glob *.bak
.coverage
.coverage.*
+*.swp
# Stuff in the root.
build
@@ -53,7 +53,7 @@ load-plugins= #enable-msg= # Disable the message(s) with the given id(s). -disable-msg= +disable= # Messages that are just silly: # I0011:106: Locally disabling E1101 # W0122: 30:run_python_file: Use of the exec statement @@ -64,7 +64,6 @@ disable-msg= # W0603: 28:call_singleton_method: Using the global statement # W0703:133:CoverageData._read_file: Catch "Exception" I0011,W0122,W0142,W0232,C0323,C0324,W0603,W0703, - # Messages that may be silly: # R0201: 42:Tracer.stop: Method could be a function # C0321: 80:CodeUnit.__lt__: More than one statement on a single line @@ -72,10 +71,10 @@ disable-msg= # W0403: 4: Relative import 'coveragetest' # E1103: 26:RunTests.test_run_python_file: Instance of 'file' has no 'getvalue' member (but some types could not be inferred) R0201,C0321,R0401,W0403,E1103, - # Messages that are noisy for now, eventually maybe we'll turn them on: # C0103:256:coverage.morf_filename: Invalid name "f" (should match [a-z_][a-z0-9_]{2,30}$) - C0103 +# W0404: 22:run_tests_with_coverage: Reimport 'coverage' (imported line 18) + C0103,W0404 [REPORTS] @@ -7,3 +7,4 @@ ignore = distribute_setup.py ez_setup.py mock.py *.min.js sample_html + *.so *.pyd diff --git a/AUTHORS.txt b/AUTHORS.txt index ee09073..77bbcbc 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -6,6 +6,7 @@ Other contributions have been made by: Chris Adams Geoff Bache Titus Brown +Brett Cannon Guillaume Chazarain David Christian Danek Duvall diff --git a/CHANGES.txt b/CHANGES.txt index a3a739a..d338e15 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -19,7 +19,16 @@ Version 3.5 coverage.py will issue a warning, at least alerting you to the problem. Closes `issue 93`_. Thanks to Marius Gedminas for the idea. +- Source files are now opened with Python 3.2's ``tokenize.open()`` where + possible, to get the best handling of Python source files with encodings. + Closes `issue 107`, thanks, Brett Cannon. + +- Internally, files are now closed explicitly, fixing `issue 104`. Thanks, + Brett Cannon. + .. _issue 93: http://bitbucket.org/ned/coveragepy/issue/93/copying-a-mock-object-breaks-coverage +.. _issue 104: https://bitbucket.org/ned/coveragepy/issue/104/explicitly-close-files +.. _issue 107: https://bitbucket.org/ned/coveragepy/issue/107/codeparser-not-opening-source-files-with Version 3.4 --- 19 September 2010 @@ -10,6 +10,7 @@ clean: python test/test_farm.py clean -rm -rf build coverage.egg-info dist htmlcov -rm -f *.pyd */*.pyd + -rm -f *.so */*.so -rm -f *.pyc */*.pyc */*/*.pyc */*/*/*.pyc */*/*/*/*.pyc */*/*/*/*/*.pyc -rm -f *.pyo */*.pyo */*/*.pyo */*/*/*.pyo */*/*/*/*.pyo */*/*/*/*/*.pyo -rm -f *.bak */*.bak */*/*.bak */*/*/*.bak */*/*/*/*.bak */*/*/*/*/*.bak @@ -26,8 +27,8 @@ clean: LINTABLE = coverage setup.py test lint: - -python -x /Python25/Scripts/pylint.bat --rcfile=.pylintrc $(LINTABLE) - python /Python25/Lib/tabnanny.py $(LINTABLE) + -pylint --rcfile=.pylintrc $(LINTABLE) + python -m tabnanny $(LINTABLE) python checkeol.py pep8: diff --git a/alltests.sh b/alltests.sh index 7c8b050..3371021 100755 --- a/alltests.sh +++ b/alltests.sh @@ -9,14 +9,14 @@ source ../ve/26/bin/activate make --quiet testdata -for v in 24 25 26 27 # 23 31 32 +for v in 24 25 26 27 31 32 # 23 do source ../ve/$v/bin/activate python setup.py -q develop - echo "=== $v c ===" + python -c "import platform; print('=== Python %s with C tracer ===' % platform.python_version())" COVERAGE_TEST_TRACER=c nosetests $@ - echo "=== $v py ===" - rm coverage/tracer.so + python -c "import platform; print('=== Python %s with Python tracer ===' % platform.python_version())" + rm coverage/tracer*.so COVERAGE_TEST_TRACER=py nosetests $@ done diff --git a/coverage/backward.py b/coverage/backward.py index 425bcc6..c363f21 100644 --- a/coverage/backward.py +++ b/coverage/backward.py @@ -1,7 +1,7 @@ """Add things to old Pythons so I can pretend they are newer.""" # This file does lots of tricky stuff, so disable a bunch of lintisms. -# pylint: disable-msg=F0401,W0611,W0622 +# pylint: disable=F0401,W0611,W0622 # F0401: Unable to import blah # W0611: Unused import blah # W0622: Redefining built-in blah @@ -71,3 +71,13 @@ try: import configparser except ImportError: import ConfigParser as configparser + +# Python 3.2 provides `tokenize.open`, the best way to open source files. +try: + import tokenize + open_source = tokenize.open # pylint: disable=E1101 +except AttributeError: + def open_source(fname): + """Open a source file the best way.""" + return open(fname, "rU") + diff --git a/coverage/cmdline.py b/coverage/cmdline.py index e5d6bb8..18715b7 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -2,7 +2,7 @@ import optparse, re, sys, traceback -from coverage.backward import sorted # pylint: disable-msg=W0622 +from coverage.backward import sorted # pylint: disable=W0622 from coverage.execfile import run_python_file from coverage.misc import CoverageException, ExceptionDuringRun diff --git a/coverage/codeunit.py b/coverage/codeunit.py index dfc4560..55f44a2 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -2,7 +2,7 @@ import glob, os -from coverage.backward import string_class, StringIO +from coverage.backward import open_source, string_class, StringIO from coverage.misc import CoverageException @@ -104,7 +104,7 @@ class CodeUnit(object): """Return an open file for reading the source of the code unit.""" if os.path.exists(self.filename): # A regular text file: open it. - return open(self.filename) + return open_source(self.filename) # Maybe it's in a zip file? source = self.file_locator.get_zip_data(self.filename) diff --git a/coverage/config.py b/coverage/config.py index 1f6a879..eda3c1c 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -1,7 +1,7 @@ """Config file for coverage.py""" import os -from coverage.backward import configparser # pylint: disable-msg=W0622 +from coverage.backward import configparser # pylint: disable=W0622 class CoverageConfig(object): diff --git a/coverage/control.py b/coverage/control.py index 4fae198..8961a3c 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -269,7 +269,7 @@ class coverage(object): # To log what should_trace returns, change this to "if 1:" if 0: _real_should_trace = _should_trace - def _should_trace(self, filename, frame): # pylint: disable-msg=E0102 + def _should_trace(self, filename, frame): # pylint: disable=E0102 """A logging decorator around the real _should_trace function.""" ret = self._real_should_trace(filename, frame) print("should_trace: %r -> %r" % (filename, ret)) @@ -496,7 +496,7 @@ class coverage(object): return Analysis(self, it) def report(self, morfs=None, show_missing=True, ignore_errors=None, - file=None, # pylint: disable-msg=W0622 + file=None, # pylint: disable=W0622 omit=None, include=None ): """Write a summary report to `file`. diff --git a/coverage/data.py b/coverage/data.py index 3d750c4..5d482ea 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -2,7 +2,7 @@ import os -from coverage.backward import pickle, sorted # pylint: disable-msg=W0622 +from coverage.backward import pickle, sorted # pylint: disable=W0622 class CoverageData(object): diff --git a/coverage/execfile.py b/coverage/execfile.py index 333163f..c61556a 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -2,7 +2,7 @@ import imp, os, sys -from coverage.backward import exec_code_object +from coverage.backward import exec_code_object, open_source from coverage.misc import NoSource, ExceptionDuringRun @@ -38,10 +38,15 @@ def run_python_file(filename, args): try: # Open the source file. try: - source = open(filename, 'rU').read() + source_file = open_source(filename) except IOError: raise NoSource("No file to run: %r" % filename) + try: + source = source_file.read() + finally: + source_file.close() + # We have the source. `compile` still needs the last line to be clean, # so make sure it is, then compile a code object from it. if source[-1] != '\n': diff --git a/coverage/html.py b/coverage/html.py index 76e2890..87edad4 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -2,7 +2,7 @@ import os, re, shutil -from coverage import __url__, __version__ # pylint: disable-msg=W0611 +from coverage import __url__, __version__ # pylint: disable=W0611 from coverage.misc import CoverageException from coverage.phystokens import source_token_lines from coverage.report import Reporter @@ -10,7 +10,7 @@ from coverage.templite import Templite # Disable pylint msg W0612, because a bunch of variables look unused, but # they're accessed in a Templite context via locals(). -# pylint: disable-msg=W0612 +# pylint: disable=W0612 def data_filename(fname): """Return the path to a data file of ours.""" @@ -18,7 +18,11 @@ def data_filename(fname): def data(fname): """Return the contents of a data file of ours.""" - return open(data_filename(fname)).read() + data_file = open(data_filename(fname)) + try: + return data_file.read() + finally: + data_file.close() class HtmlReporter(Reporter): @@ -68,8 +72,11 @@ class HtmlReporter(Reporter): def html_file(self, cu, analysis): """Generate an HTML file for one source file.""" - - source = cu.source_file().read() + source_file = cu.source_file() + try: + source = source_file.read() + finally: + source_file.close() nums = analysis.numbers @@ -138,8 +145,10 @@ class HtmlReporter(Reporter): html_path = os.path.join(self.directory, html_filename) html = spaceless(self.source_tmpl.render(locals())) fhtml = open(html_path, 'w') - fhtml.write(html) - fhtml.close() + try: + fhtml.write(html) + finally: + fhtml.close() # Save this file's information for the index file. self.files.append({ @@ -159,8 +168,10 @@ class HtmlReporter(Reporter): totals = sum([f['nums'] for f in files]) fhtml = open(os.path.join(self.directory, "index.html"), "w") - fhtml.write(index_tmpl.render(locals())) - fhtml.close() + try: + fhtml.write(index_tmpl.render(locals())) + finally: + fhtml.close() # Helpers for templates and generating HTML diff --git a/coverage/parser.py b/coverage/parser.py index ae618ce..8ad4e05 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -2,7 +2,8 @@ import glob, opcode, os, re, sys, token, tokenize -from coverage.backward import set, sorted, StringIO # pylint: disable-msg=W0622 +from coverage.backward import set, sorted, StringIO # pylint: disable=W0622 +from coverage.backward import open_source from coverage.bytecode import ByteCodes, CodeObjects from coverage.misc import nice_pair, CoverageException, NoSource, expensive @@ -22,15 +23,16 @@ class CodeParser(object): self.text = text if not self.text: try: - sourcef = open(self.filename, 'rU') - self.text = sourcef.read() - sourcef.close() + sourcef = open_source(self.filename) + try: + self.text = sourcef.read() + finally: + sourcef.close() except IOError: _, err, _ = sys.exc_info() raise NoSource( "No source for code: %r: %s" % (self.filename, err) ) - self.text = self.text.replace('\r\n', '\n') self.exclude = exclude @@ -302,9 +304,11 @@ class ByteParser(object): else: if not text: assert filename, "If no code or text, need a filename" - sourcef = open(filename, 'rU') - text = sourcef.read() - sourcef.close() + sourcef = open_source(filename) + try: + text = sourcef.read() + finally: + sourcef.close() try: # Python 2.3 and 2.4 don't like partial last lines, so be sure diff --git a/coverage/phystokens.py b/coverage/phystokens.py index 60b8793..fc4f2c9 100644 --- a/coverage/phystokens.py +++ b/coverage/phystokens.py @@ -1,7 +1,7 @@ """Better tokenizing for coverage.py.""" import keyword, re, token, tokenize -from coverage.backward import StringIO # pylint: disable-msg=W0622 +from coverage.backward import StringIO # pylint: disable=W0622 def phys_tokens(toks): """Return all physical tokens, even line continuations. diff --git a/coverage/results.py b/coverage/results.py index 85071fe..a7ec0fd 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -2,7 +2,7 @@ import os -from coverage.backward import set, sorted # pylint: disable-msg=W0622 +from coverage.backward import set, sorted # pylint: disable=W0622 from coverage.misc import format_lines, NoSource from coverage.parser import CodeParser @@ -230,4 +230,4 @@ class Numbers(object): # Implementing 0+Numbers allows us to sum() a list of Numbers. if other == 0: return self - raise NotImplemented + return NotImplemented diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 5eabac7..5f6cc87 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -4,7 +4,7 @@ import os, sys, time import xml.dom.minidom from coverage import __url__, __version__ -from coverage.backward import sorted # pylint: disable-msg=W0622 +from coverage.backward import sorted # pylint: disable=W0622 from coverage.report import Reporter def rate(hit, num): @@ -46,7 +46,7 @@ else: use_setuptools() from setuptools import setup -from distutils.core import Extension # pylint: disable-msg=E0611,F0401 +from distutils.core import Extension # pylint: disable=E0611,F0401 # Get or massage our metadata. diff --git a/test/backtest.py b/test/backtest.py index e8d8366..4576a86 100644 --- a/test/backtest.py +++ b/test/backtest.py @@ -1,6 +1,6 @@ """Add things to old Pythons so I can pretend they are newer, for tests.""" -# pylint: disable-msg=W0622 +# pylint: disable=W0622 # (Redefining built-in blah) # The whole point of this file is to redefine built-ins, so shut up about it. diff --git a/test/backunittest.py b/test/backunittest.py index f606185..c1685e0 100644 --- a/test/backunittest.py +++ b/test/backunittest.py @@ -2,7 +2,7 @@ import difflib, re, sys, unittest -from coverage.backward import set # pylint: disable-msg=W0622 +from coverage.backward import set # pylint: disable=W0622 def _need(method): diff --git a/test/coveragetest.py b/test/coveragetest.py index 53f0ef0..ebff65a 100644 --- a/test/coveragetest.py +++ b/test/coveragetest.py @@ -3,7 +3,7 @@ import imp, os, random, shlex, shutil, sys, tempfile, textwrap import coverage -from coverage.backward import sorted, StringIO # pylint: disable-msg=W0622 +from coverage.backward import sorted, StringIO # pylint: disable=W0622 from backtest import run_command from backunittest import TestCase @@ -123,11 +123,12 @@ class CoverageTest(TestCase): """Return the data written to stderr during the test.""" return self.captured_stderr.getvalue() - def make_file(self, filename, text=""): + def make_file(self, filename, text="", newline=None): """Create a temp file. `filename` is the path to the file, including directories if desired, - and `text` is the content. + and `text` is the content. If `newline` is provided, it is a string + that will be used as the line endings in the created file. Returns the path to the file. @@ -135,6 +136,8 @@ class CoverageTest(TestCase): # Tests that call `make_file` should be run in a temp environment. assert self.run_in_temp_dir text = textwrap.dedent(text) + if newline: + text = text.replace("\n", newline) # Make sure the directories are available. dirs, _ = os.path.split(filename) @@ -143,8 +146,10 @@ class CoverageTest(TestCase): # Create the file. f = open(filename, 'w') - f.write(text) - f.close() + try: + f.write(text) + finally: + f.close() return filename @@ -162,7 +167,7 @@ class CoverageTest(TestCase): if suff[0] == '.py': break try: - # pylint: disable-msg=W0631 + # pylint: disable=W0631 # (Using possibly undefined loop variable 'suff') mod = imp.load_module(modname, f, modfile, suff) finally: diff --git a/test/meta_coverage.py b/test/meta_coverage.py index 1c71abf..ef0292a 100644 --- a/test/meta_coverage.py +++ b/test/meta_coverage.py @@ -45,7 +45,7 @@ def run_tests_with_coverage(): if hasattr(mod, '__file__') and mod.__file__.startswith(covdir): covmods[name] = mod del sys.modules[name] - import coverage # don't warn about re-import: pylint: disable-msg=W0404 + import coverage # don't warn about re-import: pylint: disable=W0404 #sys.modules.update(covmods) # Run nosetests, with the arguments from our command line. diff --git a/test/osinfo.py b/test/osinfo.py index 04855fe..25c3a7c 100644 --- a/test/osinfo.py +++ b/test/osinfo.py @@ -45,8 +45,10 @@ elif sys.platform == 'linux2': try: # get pseudo file /proc/<pid>/status t = open('/proc/%d/status' % os.getpid()) - v = t.read() - t.close() + try: + v = t.read() + finally: + t.close() except IOError: return 0 # non-Linux? # get VmKey line e.g. 'VmRSS: 9999 kB\n ...' diff --git a/test/test_api.py b/test/test_api.py index 5952dfe..aee0734 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -314,7 +314,7 @@ class SourceOmitIncludeTest(CoverageTest): """ cov = coverage.coverage(**kwargs) cov.start() - import usepkgs # pylint: disable-msg=F0401,W0612 + import usepkgs # pylint: disable=F0401,W0612 cov.stop() return cov.data.summary() diff --git a/test/test_cmdline.py b/test/test_cmdline.py index aa72b34..a9858d5 100644 --- a/test/test_cmdline.py +++ b/test/test_cmdline.py @@ -372,7 +372,7 @@ class FakeCoverageForDebugData(object): """Fake coverage().data.has_arcs()""" return False - def summary(self, fullpath): # pylint: disable-msg=W0613 + def summary(self, fullpath): # pylint: disable=W0613 """Fake coverage().data.summary()""" return self._summary diff --git a/test/test_codeunit.py b/test/test_codeunit.py index 7903d15..b543949 100644 --- a/test/test_codeunit.py +++ b/test/test_codeunit.py @@ -8,7 +8,7 @@ from coverage.files import FileLocator sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k from coveragetest import CoverageTest -# pylint: disable-msg=F0401 +# pylint: disable=F0401 # Unable to import 'aa' (No module named aa) class CodeUnitTest(CoverageTest): diff --git a/test/test_execfile.py b/test/test_execfile.py index 2f28a06..f6e4dd7 100644 --- a/test/test_execfile.py +++ b/test/test_execfile.py @@ -55,8 +55,10 @@ class RunTest(CoverageTest): pylines = """# try newlines|print('Hello, world!')|""".split('|') for nl in ('\n', '\r\n', '\r'): fpy = open('nl.py', 'wb') - fpy.write(nl.join(pylines).encode('utf-8')) - fpy.close() + try: + fpy.write(nl.join(pylines).encode('utf-8')) + finally: + fpy.close() run_python_file('nl.py', ['nl.py']) self.assertEqual(self.stdout(), "Hello, world!\n"*3) diff --git a/test/test_farm.py b/test/test_farm.py index 79b345a..7041531 100644 --- a/test/test_farm.py +++ b/test/test_farm.py @@ -3,7 +3,7 @@ import difflib, filecmp, fnmatch, glob, os, re, shutil, sys sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k -from backtest import run_command, execfile # pylint: disable-msg=W0622 +from backtest import run_command, execfile # pylint: disable=W0622 def test_farm(clean_only=False): diff --git a/test/test_files.py b/test/test_files.py index 4ffc6ca..9cbaf9c 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -4,7 +4,7 @@ import os, sys from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher from coverage.files import find_python_files -from coverage.backward import set # pylint: disable-msg=W0622 +from coverage.backward import set # pylint: disable=W0622 sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k from coveragetest import CoverageTest diff --git a/test/test_parser.py b/test/test_parser.py index b398044..220db17 100644 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -16,7 +16,7 @@ class ParserTest(CoverageTest): def parse_source(self, text): """Parse `text` as source, and return the `CodeParser` used.""" text = textwrap.dedent(text) - cp = CodeParser(text, exclude="nocover") + cp = CodeParser(text=text, exclude="nocover") cp.parse_source() return cp @@ -94,3 +94,41 @@ class ParserTest(CoverageTest): b = 6 """) self.assertEqual(cp.exit_counts(), { 1:1, 2:1, 3:1, 6:1 }) + + +class ParserFileTest(CoverageTest): + """Tests for Coverage.py's code parsing from files.""" + + def parse_file(self, filename): + """Parse `text` as source, and return the `CodeParser` used.""" + cp = CodeParser(filename=filename, exclude="nocover") + cp.parse_source() + return cp + + def test_line_endings(self): + text = """\ + # check some basic branch counting + class Foo: + def foo(self, a): + if a: + return 5 + else: + return 7 + + class Bar: + pass + """ + counts = { 2:1, 3:1, 4:2, 5:1, 7:1, 9:1, 10:1 } + name_endings = (("unix", "\n"), ("dos", "\r\n"), ("mac", "\r")) + for fname, newline in name_endings: + fname = fname + ".py" + self.make_file(fname, text, newline=newline) + cp = self.parse_file(fname) + self.assertEqual(cp.exit_counts(), counts) + + def test_encoding(self): + self.make_file("encoded.py", """\ + coverage = "\xe7\xf6v\xear\xe3g\xe9" + """) + cp = self.parse_file("encoded.py") + cp.exit_counts() diff --git a/test/test_summary.py b/test/test_summary.py index fcc2612..5a68912 100644 --- a/test/test_summary.py +++ b/test/test_summary.py @@ -143,7 +143,7 @@ class SummaryTest2(CoverageTest): def test_empty_files(self): cov = coverage.coverage() cov.start() - import usepkgs # pylint: disable-msg=F0401,W0612 + import usepkgs # pylint: disable=F0401,W0612 cov.stop() repout = StringIO() diff --git a/test/test_templite.py b/test/test_templite.py index 93e9183..0435c54 100644 --- a/test/test_templite.py +++ b/test/test_templite.py @@ -3,7 +3,7 @@ from coverage.templite import Templite import unittest -# pylint: disable-msg=W0612,E1101 +# pylint: disable=W0612,E1101 # Disable W0612 (Unused variable) and # E1101 (Instance of 'foo' has no 'bar' member) diff --git a/test/test_testing.py b/test/test_testing.py index 1cae931..2461a08 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -5,7 +5,7 @@ sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k from backunittest import TestCase from coveragetest import CoverageTest -from coverage.backward import set # pylint: disable-msg=W0622 +from coverage.backward import set # pylint: disable=W0622 class TestingTest(TestCase): """Tests of helper methods on `backunittest.TestCase`.""" @@ -96,6 +96,10 @@ class TestingTest(TestCase): class CoverageTestTest(CoverageTest): """Test the methods in `CoverageTest`.""" + def file_text(self, fname): + """Return the text read from a file.""" + return open(fname, "rb").read().decode('ascii') + def test_make_file(self): # A simple file. self.make_file("fooey.boo", "Hello there") @@ -109,3 +113,11 @@ class CoverageTestTest(CoverageTest): # A deeper directory self.make_file("sub/deeper/evenmore/third.txt") self.assertEqual(open("sub/deeper/evenmore/third.txt").read(), "") + + def test_make_file_newline(self): + self.make_file("unix.txt", "Hello\n") + self.assertEqual(self.file_text("unix.txt"), "Hello\n") + self.make_file("dos.txt", "Hello\n", newline="\r\n") + self.assertEqual(self.file_text("dos.txt"), "Hello\r\n") + self.make_file("mac.txt", "Hello\n", newline="\r") + self.assertEqual(self.file_text("mac.txt"), "Hello\r") |