def test_file_content(self, root, original, contents): ''' When file content changes, hash changes ''' path_.write(root / 'file', contents * 3) current = path_.hash(root).hexdigest() assert original != current
def test_happy_days(self, path, contents): ''' When nothing special, write contents ''' path_.write(path, contents) with path.open('r') as f: assert f.read() == contents self.assert_mode(path, 0o644) # open() creates files with this mode regardless of umask
def test_digest_file(path, contents): ''' When file, digest only its contents ''' path_.write(path, contents) hash_ = hashlib.sha512() hash_.update(contents.encode()) assert path_.hash(path).hexdigest() == hash_.hexdigest()
def test_parsing(self, loader): ''' Test config parsing rules - Configuration values are treated as strings. - Empty strings are allowed. - Inline comments can be started with '#' and ';'. - The 'default' section provides defaults for other sections. - ExtendedInterpolation is used (https://docs.python.org/3/library/configparser.html#configparser.ExtendedInterpolation). - Option names have '-' and ' ' replaced with '_'. ''' path = Path('conf') path_.write(path, contents=dedent('''\ [default] a=1 b=2 # comment ; comment [section leader] space thing = spaaace # comment under_score = 1 ; comment dash-ing = yes empty = colon : yep [override-some] a=5 [interpolation] regular = 5 magic = ${regular} very_magic = ${section leader:space thing} ''')) configuration = loader.load(path) assert configuration == { 'section leader': { 'space_thing': 'spaaace', 'under_score': '1', 'dash_ing': 'yes', 'empty': '', 'colon': 'yep', 'a': '1', 'b': '2', }, 'override-some': { 'a': '5', 'b': '2', }, 'interpolation': { 'regular': '5', 'magic': '5', 'very_magic': 'spaaace', 'a': '1', 'b': '2', } }
def test_file_path(self, loader): ''' When file path, use it as a config path ''' path = Path('conf') path_.write(path, contents=dedent('''\ [section] option = value ''')) configuration = loader.load(path) assert configuration == {'section': {'option': 'value'}} # found it
def root(self, contents): ''' Directory tree with its root at 'root' ''' Path('root').mkdir() Path('root/subdir1').mkdir() Path('root/emptydir').mkdir(mode=0o600) Path('root/subdir1/emptydir').mkdir() path_.write(Path('root/file'), contents, 0o600) Path('root/emptyfile').touch() path_.write(Path('root/subdir1/subfile'), contents*2) return Path('root')
def test_dir_path(self, loader, configuration_stem): ''' When directory path, use {dir}/{configuration_name}.conf as config path ''' dir_path = Path('dir') path = dir_path / (configuration_stem + '.conf') path_.write(path, contents=dedent('''\ [section] option = value ''')) configuration = loader.load(dir_path) assert configuration == {'section': {'option': 'value'}} # found it
def test_mode(self, path, contents, mode): ''' When mode given, mode is set and contents were written Even when mode is read-only for owner ''' path_.write(path, contents, mode) # correct mode self.assert_mode(path, mode) # correct contents path.chmod(0o400) with path.open('r') as f: assert f.read() == contents
def test_contents(self): ''' Only when contents=True, assert file contents match ''' file1 = Path('file1') file2 = Path('file2') contents = 'abc' path_.write(file1, contents) path_.write(file2, contents*2) path_.assert_equals(file1, file2, name=False, contents=False, mode=False) with pytest.raises(AssertionError): path_.assert_equals(file1, file2, contents=True, name=False, mode=False) path_.write(file2, contents) path_.assert_equals(file1, file2, contents=True, name=False, mode=False)
def test_inheritance(self, directory_name): ''' Test config file inheritance and use of defaults ''' configuration_stem = 'inheritance' # First defaults should be read # from: data/main.defaults.conf given we used __name__.parent as package_name # Then /etc/{directory_name}/{configuration_name}.conf should override the defaults path_.write(Path('etc/{}/{}.conf'.format(directory_name, configuration_stem)), contents=dedent('''\ [section] a=10 b=20 c=30 e=50 space-word = f2 ''')) # Then each xdg conf file should override the previous (testing with just 1 file here) xdg_conf_dir = Path('home/mittens/much_conf_dir') xdg_conf_file = xdg_conf_dir / directory_name / (configuration_stem + '.conf') path_.write(xdg_conf_file, contents=dedent('''\ [section] a=100 b=200 f=600 space_word = expected ''')) # Finally the path arg should override the previous path = Path('local.conf') path_.write(path, contents='''\ [section] a=1000 g=7000 ''') # Test original = xdg_config_dirs[:] try: xdg_config_dirs[:] = ['/' + str(xdg_conf_dir)] configuration = self.loader(directory_name, configuration_stem).load(path) finally: xdg_config_dirs[:] = original # Assert assert configuration['section'] == dict(a='1000', b='200', c='30', d='4', e='50', f='600', g='7000', space_word='expected')