123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- # coding: utf-8
- # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
- # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
- """Test the config file handling for coverage.py"""
- import sys
- import os
- import coverage
- from coverage.misc import CoverageException
- from tests.coveragetest import CoverageTest
- class ConfigTest(CoverageTest):
- """Tests of the different sources of configuration settings."""
- def test_default_config(self):
- # Just constructing a coverage() object gets the right defaults.
- cov = coverage.Coverage()
- self.assertFalse(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, ".coverage")
- def test_arguments(self):
- # Arguments to the constructor are applied to the configuration.
- cov = coverage.Coverage(timid=True, data_file="fooey.dat", concurrency="multiprocessing")
- self.assertTrue(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, "fooey.dat")
- self.assertEqual(cov.config.concurrency, ["multiprocessing"])
- def test_config_file(self):
- # A .coveragerc file will be read into the configuration.
- self.make_file(".coveragerc", """\
- # This is just a bogus .rc file for testing.
- [run]
- timid = True
- data_file = .hello_kitty.data
- """)
- cov = coverage.Coverage()
- self.assertTrue(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, ".hello_kitty.data")
- def test_named_config_file(self):
- # You can name the config file what you like.
- self.make_file("my_cov.ini", """\
- [run]
- timid = True
- ; I wouldn't really use this as a data file...
- data_file = delete.me
- """)
- cov = coverage.Coverage(config_file="my_cov.ini")
- self.assertTrue(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, "delete.me")
- def test_ignored_config_file(self):
- # You can disable reading the .coveragerc file.
- self.make_file(".coveragerc", """\
- [run]
- timid = True
- data_file = delete.me
- """)
- cov = coverage.Coverage(config_file=False)
- self.assertFalse(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, ".coverage")
- def test_config_file_then_args(self):
- # The arguments override the .coveragerc file.
- self.make_file(".coveragerc", """\
- [run]
- timid = True
- data_file = weirdo.file
- """)
- cov = coverage.Coverage(timid=False, data_file=".mycov")
- self.assertFalse(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, ".mycov")
- def test_data_file_from_environment(self):
- # There's an environment variable for the data_file.
- self.make_file(".coveragerc", """\
- [run]
- timid = True
- data_file = weirdo.file
- """)
- self.set_environ("COVERAGE_FILE", "fromenv.dat")
- cov = coverage.Coverage()
- self.assertEqual(cov.config.data_file, "fromenv.dat")
- # But the constructor arguments override the environment variable.
- cov = coverage.Coverage(data_file="fromarg.dat")
- self.assertEqual(cov.config.data_file, "fromarg.dat")
- def test_parse_errors(self):
- # Im-parsable values raise CoverageException, with details.
- bad_configs_and_msgs = [
- ("[run]\ntimid = maybe?\n", r"maybe[?]"),
- ("timid = 1\n", r"timid = 1"),
- ("[run\n", r"\[run"),
- ("[report]\nexclude_lines = foo(\n",
- r"Invalid \[report\].exclude_lines value 'foo\(': "
- r"(unbalanced parenthesis|missing \))"),
- ("[report]\npartial_branches = foo[\n",
- r"Invalid \[report\].partial_branches value 'foo\[': "
- r"(unexpected end of regular expression|unterminated character set)"),
- ("[report]\npartial_branches_always = foo***\n",
- r"Invalid \[report\].partial_branches_always value "
- r"'foo\*\*\*': "
- r"multiple repeat"),
- ]
- for bad_config, msg in bad_configs_and_msgs:
- print("Trying %r" % bad_config)
- self.make_file(".coveragerc", bad_config)
- with self.assertRaisesRegex(CoverageException, msg):
- coverage.Coverage()
- def test_environment_vars_in_config(self):
- # Config files can have $envvars in them.
- self.make_file(".coveragerc", """\
- [run]
- data_file = $DATA_FILE.fooey
- branch = $OKAY
- [report]
- exclude_lines =
- the_$$one
- another${THING}
- x${THING}y
- x${NOTHING}y
- huh$${X}what
- """)
- self.set_environ("DATA_FILE", "hello-world")
- self.set_environ("THING", "ZZZ")
- self.set_environ("OKAY", "yes")
- cov = coverage.Coverage()
- self.assertEqual(cov.config.data_file, "hello-world.fooey")
- self.assertEqual(cov.config.branch, True)
- self.assertEqual(
- cov.config.exclude_list,
- ["the_$one", "anotherZZZ", "xZZZy", "xy", "huh${X}what"]
- )
- def test_tweaks_after_constructor(self):
- # Arguments to the constructor are applied to the configuration.
- cov = coverage.Coverage(timid=True, data_file="fooey.dat")
- cov.set_option("run:timid", False)
- self.assertFalse(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, "fooey.dat")
- self.assertFalse(cov.get_option("run:timid"))
- self.assertFalse(cov.get_option("run:branch"))
- self.assertEqual(cov.get_option("run:data_file"), "fooey.dat")
- def test_tweak_error_checking(self):
- # Trying to set an unknown config value raises an error.
- cov = coverage.Coverage()
- with self.assertRaises(CoverageException):
- cov.set_option("run:xyzzy", 12)
- with self.assertRaises(CoverageException):
- cov.set_option("xyzzy:foo", 12)
- with self.assertRaises(CoverageException):
- _ = cov.get_option("run:xyzzy")
- with self.assertRaises(CoverageException):
- _ = cov.get_option("xyzzy:foo")
- def test_tweak_plugin_options(self):
- # Plugin options have a more flexible syntax.
- cov = coverage.Coverage()
- cov.set_option("run:plugins", ["fooey.plugin", "xyzzy.coverage.plugin"])
- cov.set_option("fooey.plugin:xyzzy", 17)
- cov.set_option("xyzzy.coverage.plugin:plugh", ["a", "b"])
- with self.assertRaises(CoverageException):
- cov.set_option("no_such.plugin:foo", 23)
- self.assertEqual(cov.get_option("fooey.plugin:xyzzy"), 17)
- self.assertEqual(cov.get_option("xyzzy.coverage.plugin:plugh"), ["a", "b"])
- with self.assertRaises(CoverageException):
- _ = cov.get_option("no_such.plugin:foo")
- def test_unknown_option(self):
- self.make_file(".coveragerc", """\
- [run]
- xyzzy = 17
- """)
- msg = r"Unrecognized option '\[run\] xyzzy=' in config file .coveragerc"
- with self.assertRaisesRegex(CoverageException, msg):
- _ = coverage.Coverage()
- def test_misplaced_option(self):
- self.make_file(".coveragerc", """\
- [report]
- branch = True
- """)
- msg = r"Unrecognized option '\[report\] branch=' in config file .coveragerc"
- with self.assertRaisesRegex(CoverageException, msg):
- _ = coverage.Coverage()
- def test_unknown_option_in_other_ini_file(self):
- self.make_file("setup.cfg", """\
- [coverage:run]
- huh = what?
- """)
- msg = r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg"
- with self.assertRaisesRegex(CoverageException, msg):
- _ = coverage.Coverage()
- class ConfigFileTest(CoverageTest):
- """Tests of the config file settings in particular."""
- def setUp(self):
- super(ConfigFileTest, self).setUp()
- # Parent class saves and restores sys.path, we can just modify it.
- # Add modules to the path so we can import plugins.
- sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules'))
- # This sample file tries to use lots of variation of syntax...
- # The {section} placeholder lets us nest these settings in another file.
- LOTSA_SETTINGS = """\
- # This is a settings file for coverage.py
- [{section}run]
- timid = yes
- data_file = something_or_other.dat
- branch = 1
- cover_pylib = TRUE
- parallel = on
- include = a/ , b/
- concurrency = thread
- source = myapp
- plugins =
- plugins.a_plugin
- plugins.another
- [{section}report]
- ; these settings affect reporting.
- exclude_lines =
- if 0:
- pragma:?\\s+no cover
- another_tab
- ignore_errors = TRUE
- omit =
- one, another, some_more,
- yet_more
- precision = 3
- partial_branches =
- pragma:?\\s+no branch
- partial_branches_always =
- if 0:
- while True:
- show_missing= TruE
- skip_covered = TruE
- [{section}html]
- directory = c:\\tricky\\dir.somewhere
- extra_css=something/extra.css
- title = Title & nums # nums!
- [{section}xml]
- output=mycov.xml
- package_depth = 17
- [{section}paths]
- source =
- .
- /home/ned/src/
- other = other, /home/ned/other, c:\\Ned\\etc
- [{section}plugins.a_plugin]
- hello = world
- ; comments still work.
- names = Jane/John/Jenny
- """
- # Just some sample setup.cfg text from the docs.
- SETUP_CFG = """\
- [bdist_rpm]
- release = 1
- packager = Jane Packager <janep@pysoft.com>
- doc_files = CHANGES.txt
- README.txt
- USAGE.txt
- doc/
- examples/
- """
- def assert_config_settings_are_correct(self, cov):
- """Check that `cov` has all the settings from LOTSA_SETTINGS."""
- self.assertTrue(cov.config.timid)
- self.assertEqual(cov.config.data_file, "something_or_other.dat")
- self.assertTrue(cov.config.branch)
- self.assertTrue(cov.config.cover_pylib)
- self.assertTrue(cov.config.parallel)
- self.assertEqual(cov.config.concurrency, ["thread"])
- self.assertEqual(cov.config.source, ["myapp"])
- self.assertEqual(cov.get_exclude_list(), ["if 0:", r"pragma:?\s+no cover", "another_tab"])
- self.assertTrue(cov.config.ignore_errors)
- self.assertEqual(cov.config.include, ["a/", "b/"])
- self.assertEqual(cov.config.omit, ["one", "another", "some_more", "yet_more"])
- self.assertEqual(cov.config.precision, 3)
- self.assertEqual(cov.config.partial_list, [r"pragma:?\s+no branch"])
- self.assertEqual(cov.config.partial_always_list, ["if 0:", "while True:"])
- self.assertEqual(cov.config.plugins, ["plugins.a_plugin", "plugins.another"])
- self.assertTrue(cov.config.show_missing)
- self.assertTrue(cov.config.skip_covered)
- self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
- self.assertEqual(cov.config.extra_css, "something/extra.css")
- self.assertEqual(cov.config.html_title, "Title & nums # nums!")
- self.assertEqual(cov.config.xml_output, "mycov.xml")
- self.assertEqual(cov.config.xml_package_depth, 17)
- self.assertEqual(cov.config.paths, {
- 'source': ['.', '/home/ned/src/'],
- 'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
- })
- self.assertEqual(cov.config.get_plugin_options("plugins.a_plugin"), {
- 'hello': 'world',
- 'names': 'Jane/John/Jenny',
- })
- self.assertEqual(cov.config.get_plugin_options("plugins.another"), {})
- def test_config_file_settings(self):
- self.make_file(".coveragerc", self.LOTSA_SETTINGS.format(section=""))
- cov = coverage.Coverage()
- self.assert_config_settings_are_correct(cov)
- def test_config_file_settings_in_setupcfg(self):
- # Configuration will be read from setup.cfg from sections prefixed with
- # "coverage:"
- nested = self.LOTSA_SETTINGS.format(section="coverage:")
- self.make_file("setup.cfg", nested + "\n" + self.SETUP_CFG)
- cov = coverage.Coverage()
- self.assert_config_settings_are_correct(cov)
- def test_config_file_settings_in_setupcfg_if_coveragerc_specified(self):
- # Configuration will be read from setup.cfg from sections prefixed with
- # "coverage:", even if the API said to read from a (non-existent)
- # .coveragerc file.
- nested = self.LOTSA_SETTINGS.format(section="coverage:")
- self.make_file("setup.cfg", nested + "\n" + self.SETUP_CFG)
- cov = coverage.Coverage(config_file=".coveragerc")
- self.assert_config_settings_are_correct(cov)
- def test_setupcfg_only_if_not_coveragerc(self):
- self.make_file(".coveragerc", """\
- [run]
- include = foo
- """)
- self.make_file("setup.cfg", """\
- [coverage:run]
- omit = bar
- branch = true
- """)
- cov = coverage.Coverage()
- self.assertEqual(cov.config.include, ["foo"])
- self.assertEqual(cov.config.omit, None)
- self.assertEqual(cov.config.branch, False)
- def test_setupcfg_only_if_prefixed(self):
- self.make_file("setup.cfg", """\
- [run]
- omit = bar
- branch = true
- """)
- cov = coverage.Coverage()
- self.assertEqual(cov.config.omit, None)
- self.assertEqual(cov.config.branch, False)
- def test_non_ascii(self):
- self.make_file(".coveragerc", """\
- [report]
- exclude_lines =
- first
- ✘${TOX_ENVNAME}
- third
- [html]
- title = tabblo & «ταБЬℓσ» # numbers
- """)
- self.set_environ("TOX_ENVNAME", "weirdo")
- cov = coverage.Coverage()
- self.assertEqual(cov.config.exclude_list, ["first", "✘weirdo", "third"])
- self.assertEqual(cov.config.html_title, "tabblo & «ταБЬℓσ» # numbers")
- def test_unreadable_config(self):
- # If a config file is explicitly specified, then it is an error for it
- # to not be readable.
- bad_files = [
- "nosuchfile.txt",
- ".",
- ]
- for bad_file in bad_files:
- msg = "Couldn't read %r as a config file" % bad_file
- with self.assertRaisesRegex(CoverageException, msg):
- coverage.Coverage(config_file=bad_file)
- def test_nocoveragerc_file_when_specified(self):
- cov = coverage.Coverage(config_file=".coveragerc")
- self.assertFalse(cov.config.timid)
- self.assertFalse(cov.config.branch)
- self.assertEqual(cov.config.data_file, ".coverage")
|