def test_load_file_with_duplicate_includes(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "fruits/oranges.beancount" include "{root}/legumes/tomates.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ include "../legumes/tomates.beancount" 2014-01-02 open Assets:Oranges """, 'legumes/tomates.beancount': """ 2014-01-03 open Assets:Tomates """, 'legumes/patates.beancount': """ 2014-01-04 open Assets:Patates """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertTrue(errors) self.assertEqual(3, len(entries)) self.assertEqual( ['apples.beancount', 'oranges.beancount', 'tomates.beancount'], list(map(path.basename, options_map['include'])))
def test_load_file_with_multiple_includes(self): # Including recursive includes and mixed and absolute. with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "fruits/oranges.beancount" include "{root}/legumes/patates.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ include "../legumes/tomates.beancount" 2014-01-02 open Assets:Oranges """, 'legumes/tomates.beancount': """ 2014-01-03 open Assets:Tomates """, 'legumes/patates.beancount': """ 2014-01-04 open Assets:Patates """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertFalse(errors) self.assertEqual(4, len(entries))
def test_load_file_return_include_filenames(self): # Also check that they are normalized paths. with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "oranges.beancount" 2014-01-01 open Assets:Apples """, 'oranges.beancount': """ include "bananas.beancount" 2014-01-02 open Assets:Oranges """, 'bananas.beancount': """ 2014-01-02 open Assets:Bananas """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertFalse(errors) self.assertEqual(3, len(entries)) self.assertTrue( all(path.isabs(filename) for filename in options_map['include'])) self.assertEqual( ['apples.beancount', 'bananas.beancount', 'oranges.beancount'], list(map(path.basename, options_map['include'])))
def test_load_string_with_relative_include(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "fruits/oranges.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) try: cwd = os.getcwd() os.chdir(tmp) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) finally: os.chdir(cwd) self.assertFalse(errors) self.assertEqual(2, len(entries)) self.assertEqual(['apples.beancount', 'oranges.beancount'], list(map(path.basename, options_map['include'])))
def test_load_cache_override_filename_pattern(self): orig_load_file = loader._load_file prev_env = os.getenv('BEANCOUNT_LOAD_CACHE_FILENAME') os.environ['BEANCOUNT_LOAD_CACHE_FILENAME'] = '__{filename}__' loader.initialize() try: with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(filename) self.assertEqual({'__apples.beancount__', 'apples.beancount'}, set(os.listdir(tmp))) finally: # Restore pre-test values. loader._load_file = orig_load_file if prev_env is None: del os.environ['BEANCOUNT_LOAD_CACHE_FILENAME'] else: os.environ['BEANCOUNT_LOAD_CACHE_FILENAME'] = prev_env
def test_validate_local_links(self): with test_utils.tempdir() as tmpdir: os.mkdir(path.join(tmpdir, 'root')) os.mkdir(path.join(tmpdir, 'root/sub')) open(path.join(tmpdir, 'parent.html'), 'w') open(path.join(tmpdir, 'root/sibling.html'), 'w') open(path.join(tmpdir, 'root/sibling.png'), 'w') open(path.join(tmpdir, 'root/sub/child.html'), 'w') filename = path.join(tmpdir, 'root/start.html') with open(filename, 'w') as ffile: ffile.write(textwrap.dedent(""" <html> <body> <a href="../parent.html">Parent</a> <a href="../parent_not.html">Parent</a> <a href="sibling.html">Sibling</a> <a href="sibling_not.html">Sibling</a> <img src="sibling.png">Sibling Image</a> <a href="sub/child.html">Child</a> <a href="sub/child_not.html">Child</a> </body> </html> """)) missing, empty = scrape.validate_local_links(filename) self.assertFalse(empty) self.assertEqual(3, len(missing)) self.assertTrue(all(re.search('_not', filename) for filename in missing))
def test_include_encrypted(self): with test_utils.tempdir() as tmpdir: test_utils.create_temporary_files( tmpdir, { 'apples.beancount': """ include "oranges.beancount.asc" 2014-01-01 open Assets:Apples """, 'oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) # Encrypt the oranges file and remove the unencrypted file. with open(path.join(tmpdir, 'oranges.beancount')) as infile: self.encrypt_as_file( infile.read(), path.join(tmpdir, 'oranges.beancount.asc')) os.remove(path.join(tmpdir, 'oranges.beancount')) # Load the top-level file which includes the encrypted file. with test_utils.environ('GNUPGHOME', self.ringdir): entries, errors, options_map = loader.load_file( path.join(tmpdir, 'apples.beancount')) self.assertFalse(errors) self.assertEqual(2, len(entries)) self.assertRegex(entries[0].meta['filename'], 'apples.beancount') self.assertRegex(entries[1].meta['filename'], 'oranges.+count.asc')
def test_create_temporary_files(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "{root}/fruits/oranges.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) # Check the total list of files. apples = path.join(tmp, 'apples.beancount') oranges = path.join(tmp, 'fruits/oranges.beancount') self.assertEqual({apples, oranges}, set( path.join(root, filename) for root, _, files in os.walk(tmp) for filename in files)) # Check the contents of apples (with replacement of root). apples_content = open(apples).read() self.assertRegex(apples_content, 'open Assets:Apples') self.assertNotRegex(apples_content, '{root}') # Check the contents of oranges. oranges_content = open(oranges).read() self.assertRegex(oranges_content, 'open Assets:Oranges')
def test_bake_missing_input(self): with test_utils.tempdir() as tmpdir: with self.assertRaises(SystemExit): output = path.join(tmpdir, 'output') filename = path.join(tmpdir, 'does_not_exist.beancount') test_utils.run_with_args(bake.main, self.get_args() + [filename, output])
def test_tempdir(self): with test_utils.tempdir() as tempdir: open(path.join(tempdir, 'file1'), 'w') os.mkdir(path.join(tempdir, 'directory')) open(path.join(tempdir, 'directory', 'file2'), 'w') self.assertFalse(path.exists(tempdir)) self.assertFalse(path.exists(path.join(tempdir, 'file1'))) self.assertFalse(path.exists(path.join(tempdir, 'directory')))
def test_validate_local_links__empty(self): with test_utils.tempdir() as tmpdir: filename = path.join(tmpdir, 'start.html') with open(filename, 'w'): pass missing, empty = scrape.validate_local_links(filename) self.assertTrue(empty) self.assertFalse(missing)
def test_save_scraped_document__ignore_directories(self): html = lxml.html.document_fromstring(self.test_html) with test_utils.tempdir() as tmp: response = mock.MagicMock() response.url = '/doc/to/' response.status = 200 response.read.return_value = self.test_html.encode('utf8') response.info().get_content_type.return_value = 'text/html' bake.save_scraped_document(tmp, response.url, response, response.read.return_value, html, set()) self.assertEqual([], os.listdir(tmp))
def test_load_file_with_nonexist_include(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'root.beancount': """ include "/some/file/that/does/not/exist.beancount" """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'root.beancount')) self.assertEqual(1, len(errors)) self.assertTrue(re.search('does not exist', errors[0].message))
def test_load_file_no_includes(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertEqual(0, len(errors)) self.assertEqual(['apples.beancount'], list(map(path.basename, options_map['include'])))
def test_save_scraped_document__file(self): html = lxml.html.document_fromstring(self.test_html) with test_utils.tempdir() as tmp: response = mock.MagicMock() response.url = '/path/to/file' response.status = 200 response.read.return_value = self.test_html.encode('utf8') response.info().get_content_type.return_value = 'text/html' bake.save_scraped_document(tmp, response.url, response, response.read.return_value, html, set()) filename = path.join(tmp, 'path/to/file.html') self.assertTrue(path.exists(filename)) self.assertLines(open(filename).read(), self.expected_html)
def test_save_scraped_document__binary_content(self): html = lxml.html.document_fromstring(self.test_html) with test_utils.tempdir() as tmp: response = mock.MagicMock() response.url = '/resources/something.png' response.status = 200 expected_contents = 'IMAGE!'.encode('utf8') response.read.return_value = expected_contents response.info().get_content_type.return_value = 'image/png' bake.save_scraped_document( tmp, response.url, response, expected_contents, html, set()) actual_contents = open(path.join(tmp, 'resources/something.png'), 'rb').read() self.assertEqual(expected_contents, actual_contents)
def test_load_cache(self): # Create an initial set of files and load file, thus creating a cache. with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "oranges.beancount" 2014-01-01 open Assets:Apples """, 'oranges.beancount': """ include "bananas.beancount" 2014-01-02 open Assets:Oranges """, 'bananas.beancount': """ 2014-01-02 open Assets:Bananas """ }) top_filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(top_filename) self.assertFalse(errors) self.assertEqual(3, len(entries)) self.assertEqual(1, self.num_calls) # Make sure the cache was created. self.assertTrue( path.exists(path.join(tmp, '.apples.beancount.picklecache'))) # Load the root file again, make sure the cache is being hit. entries, errors, options_map = loader.load_file(top_filename) self.assertEqual(1, self.num_calls) # Touch the top-level file and ensure it's a cache miss. with open(top_filename, 'a') as file: file.write('\n') entries, errors, options_map = loader.load_file(top_filename) self.assertEqual(2, self.num_calls) # Load the root file again, make sure the cache is being hit. entries, errors, options_map = loader.load_file(top_filename) self.assertEqual(2, self.num_calls) # Touch the top-level file and ensure it's a cache miss. with open(top_filename, 'a') as file: file.write('\n') entries, errors, options_map = loader.load_file(top_filename) self.assertEqual(3, self.num_calls)
def test_load_cache_override_filename_pattern_by_argument(self): with test_utils.tempdir() as tmp: cache_filename = path.join(tmp, "__{filename}__") loader.initialize(use_cache=True, cache_filename=cache_filename) test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(filename) self.assertEqual({'__apples.beancount__', 'apples.beancount'}, set(os.listdir(tmp)))
def test_load_file_with_nonexist_include(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'root.beancount': """ include "/some/file/that/does/not/exist.beancount" """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'root.beancount')) self.assertEqual(1, len(errors)) self.assertRegex(errors[0].message, 'does not exist') self.assertEqual(['root.beancount'], list(map(path.basename, options_map['include'])))
def test_load_cache_read_only_fs(self, remove_mock, warn_mock): # Create an initial set of files and load file, thus creating a cache. with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(filename) with open(filename, 'w'): pass entries, errors, options_map = loader.load_file(filename) self.assertEqual(1, len(warn_mock.mock_calls))
def test_bake_archive__unknown(self, filename): """ 2013-01-01 open Expenses:Restaurant 2013-01-01 open Assets:Cash 2014-03-02 * "Some basic transaction" Expenses:Restaurant 50.02 USD Assets:Cash """ with test_utils.tempdir() as tmpdir: for archive_name in ('archive.tar.zip', 'archive.tar.xz'): with self.assertRaises(SystemExit): outfile = path.join(tmpdir, archive_name) test_utils.run_with_args( bake.main, self.get_args() + [filename, outfile])
def test_load_cache_override_filename_pattern_by_env_var(self): with test_utils.environ('BEANCOUNT_LOAD_CACHE_FILENAME', '__{filename}__'): loader.initialize(use_cache=True) with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(filename) self.assertEqual({'__apples.beancount__', 'apples.beancount'}, set(os.listdir(tmp)))
def test_bake_directory(self, filename): """ 2013-01-01 open Expenses:Restaurant 2013-01-01 open Assets:Cash 2014-03-02 * "Some basic transaction" Expenses:Restaurant 50.02 USD Assets:Cash """ with test_utils.tempdir() as tmpdir: outdir = path.join(tmpdir, 'output') with test_utils.capture('stdout', 'stderr') as (output, _): test_utils.run_with_args(bake.main, self.get_args() + [filename, outdir]) self.assertTrue(output.getvalue()) self.assertTrue(path.exists(outdir) and path.isdir(outdir)) directories = [root for root, _, _ in os.walk(outdir)] self.assertGreater(len(directories), 10)
def test_bake_bad_link(self, filename): """ plugin "beancount.plugins.auto_accounts" 2014-03-02 * "Something" ^2015-06-14.something.pdf Expenses:Restaurant 1 USD Assets:Cash """ with test_utils.tempdir(delete=0) as tmpdir: tmpdir = path.join(tmpdir, 'output') with test_utils.capture() as output: test_utils.run_with_args(bake.main, self.get_args() + [filename, tmpdir]) self.assertTrue(output.getvalue()) self.assertFalse(path.exists( path.join(tmpdir, 'link/2015-06-14.something.pdf'))) self.assertTrue(path.exists( path.join(tmpdir, 'link/2015-06-14.something.pdf.html')))
def test_load_file_with_relative_include(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "fruits/oranges.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertFalse(errors) self.assertEqual(2, len(entries))
def test_load_cache_disable(self): with test_utils.tempdir() as tmp: cache_filename = path.join(tmp, "__{filename}__") for kwargs in [ dict(use_cache=False), dict(use_cache=False, cache_filename=cache_filename) ]: loader.initialize(**kwargs) test_utils.create_temporary_files( tmp, { 'apples.beancount': """ 2014-01-01 open Assets:Apples """ }) filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(filename) self.assertEqual({'apples.beancount'}, set(os.listdir(tmp)))
def test_bake_archive__known(self, filename): """ 2013-01-01 open Expenses:Restaurant 2013-01-01 open Assets:Cash 2014-03-02 * "Some basic transaction" Expenses:Restaurant 50.02 USD Assets:Cash """ with test_utils.tempdir() as tmpdir: for archive_name in ('archive.tar.gz', 'archive.tgz', 'archive.tar.bz2', 'archive.zip'): outfile = path.join(tmpdir, archive_name) with test_utils.capture(): test_utils.run_with_args(bake.main, self.get_args() + [filename, outfile]) self.assertFalse(path.exists(file_utils.path_greedy_split(outfile)[0])) self.assertTrue(path.exists(outfile) and path.getsize(outfile) > 0)
def test_load_file_with_absolute_include(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "{root}/fruits/oranges.beancount" 2014-01-01 open Assets:Apples """, 'fruits/oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) entries, errors, options_map = loader.load_file( path.join(tmp, 'apples.beancount')) self.assertFalse(errors) self.assertEqual(2, len(entries)) self.assertEqual(['apples.beancount', 'oranges.beancount'], list(map(path.basename, options_map['include'])))
def test_load_cache_moved_file(self): # Create an initial set of files and load file, thus creating a cache. with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "oranges.beancount" 2014-01-01 open Assets:Apples """, 'oranges.beancount': """ 2014-01-02 open Assets:Oranges """ }) top_filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(top_filename) self.assertFalse(errors) self.assertEqual(2, len(entries)) self.assertEqual(1, self.num_calls) # Make sure the cache was created. self.assertTrue( path.exists(path.join(tmp, '.apples.beancount.picklecache'))) # CHeck that it doesn't need refresh self.assertFalse(loader.needs_refresh(options_map)) # Move the input file. new_top_filename = path.join(tmp, 'bigapples.beancount') os.rename(top_filename, new_top_filename) # Check that it needs refresh. self.assertTrue(loader.needs_refresh(options_map)) # Load the root file again, make sure the cache is being hit. entries, errors, options_map = loader.load_file(top_filename) self.assertEqual(2, self.num_calls)
def test_aggregate_commodities(self): with test_utils.tempdir() as tmp: test_utils.create_temporary_files( tmp, { 'apples.beancount': """ include "oranges.beancount" include "bananas.beancount" option "operating_currency" "USD" """, 'oranges.beancount': """ 2015-12-12 open Assets:CA:Checking CAD """, 'bananas.beancount': """ 2015-12-13 open Assets:FR:Checking EUR """ }) top_filename = path.join(tmp, 'apples.beancount') entries, errors, options_map = loader.load_file(top_filename) self.assertEqual({'EUR', 'CAD'}, options_map['commodities'])