示例#1
0
    def test_hash_entries_with_duplicates(self):
        entries, _, __ = loader.load_string("""
          2014-08-01 price HOOL  603.10 USD
        """)
        hashes, errors = compare.hash_entries(entries)
        self.assertEqual(1, len(hashes))

        entries, _, __ = loader.load_string("""
          2014-08-01 price HOOL  603.10 USD
          2014-08-01 price HOOL  603.10 USD
          2014-08-01 price HOOL  603.10 USD
          2014-08-01 price HOOL  603.10 USD
          2014-08-01 price HOOL  603.10 USD
        """)
        hashes, errors = compare.hash_entries(entries)
        self.assertEqual(1, len(hashes))
示例#2
0
    def test_extract_from_file__min_date(self):
        entries, _, __ = loader.load_string("""

          2016-02-01 * "A"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-02 * "B"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-03 * "C"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

        """)
        imp = mock.MagicMock()
        imp.identify = mock.MagicMock(return_value=True)
        imp.extract = mock.MagicMock(return_value=entries)
        new_entries, dup_entries = extract.extract_from_file(
            '/tmp/blabla.ofx', imp, min_date=datetime.date(2016, 2, 2))
        self.assertEqual(2, len(new_entries))
        self.assertEqual(
            [datetime.date(2016, 2, 2),
             datetime.date(2016, 2, 3)], [entry.date for entry in new_entries])
        self.assertEqual([], dup_entries)
示例#3
0
    def setUp(self, entries, _, __):
        """
          ;; Existing file.
          2015-01-05 price HDV                                 75.56 USD
          2015-01-23 price HDV                                 77.34 USD
          2015-02-06 price HDV                                 77.16 USD
          2015-02-12 price HDV                                 78.17 USD
          2015-05-01 price HDV                                 77.48 USD
          2015-06-02 price HDV                                 76.33 USD
          2015-06-29 price HDV                                 73.74 USD
          2015-07-06 price HDV                                 73.79 USD
          2015-08-11 price HDV                                 74.19 USD
          2015-09-04 price HDV                                 68.98 USD
        """
        self.entries = entries

        # New entries.
        self.price_entries, _, __ = loader.load_string("""
          2015-01-27 price HDV                                 76.83 USD
          2015-02-06 price HDV                                 77.16 USD
          2015-02-19 price HDV                                  77.5 USD
          2015-06-02 price HDV                                 76.33 USD
          2015-06-19 price HDV                                    76 USD
          2015-07-06 price HDV                                 73.79 USD
          2015-07-31 price HDV                                 74.64 USD
          2015-08-11 price HDV                                 74.20 USD ;; Different
        """, dedent=True)
示例#4
0
    def test_extract_from_file__explicitly_marked_duplicates_entries(self):
        entries, _, __ = loader.load_string("""

          2016-02-01 * "A"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-02 * "B"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

        """)
        entries[1].meta[extract.DUPLICATE_META] = True
        imp = mock.MagicMock()
        imp.identify = mock.MagicMock(return_value=True)
        imp.extract = mock.MagicMock(return_value=entries)

        new_entries, dup_entries = extract.extract_from_file(
            '/tmp/blabla.ofx', imp, [])
        self.assertEqual(1, len(dup_entries))
        self.assertEqual(
            [datetime.date(2016, 2, 1),
             datetime.date(2016, 2, 2)], [entry.date for entry in new_entries])
        self.assertEqual([datetime.date(2016, 2, 2)],
                         [entry.date for entry in dup_entries])
示例#5
0
    def test_extract_from_file__ensure_sorted(self):
        entries, _, __ = loader.load_string("""

          2016-02-03 * "C"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-01 * "A"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-02 * "B"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

        """)

        imp = mock.MagicMock()
        imp.identify = mock.MagicMock(return_value=True)
        imp.extract = mock.MagicMock(return_value=entries)
        new_entries, dup_entries = extract.extract_from_file(
            '/tmp/blabla.ofx', imp)
        self.assertEqual(3, len(entries))
        self.assertTrue(
            misc_utils.is_sorted(new_entries, key=lambda entry: entry.date))
        self.assertEqual([], dup_entries)
    def test_interline_spacing(self):
        input_text = textwrap.dedent("""\
        2014-01-01 open Assets:Account1
        2014-01-01 open Assets:Account2
        2014-01-01 open Assets:Cash

        2014-06-08 *
          Assets:Account1       111.00 BEAN
          Assets:Cash

        2014-06-08 * "Narration"
          Assets:Account1       111.00 BEAN
          Assets:Cash

        2014-06-08 * "Payee" "Narration"
          Assets:Account2       111.00 BEAN
          Assets:Cash

        2014-10-01 close Assets:Account2

        2014-10-11 price BEAN   10 USD
        2014-10-12 price BEAN   11 USD
        2014-10-13 price BEAN   11 USD
        """)
        entries, _, __ = loader.load_string(input_text)

        oss = io.StringIO()
        printer.print_entries(entries, file=oss)

        expected_classes = characterize_spaces(input_text)
        actual_classes = characterize_spaces(oss.getvalue())

        self.assertEqual(expected_classes, actual_classes)
    def test_extract_from_file__existing_entries(self):
        entries, _, __ = loader.load_string("""

          2016-02-01 * "A"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-02 * "B"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-03 * "C"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

          2016-02-04 * "D"
            Assets:Account1    10.00 USD
            Assets:Account2   -10.00 USD

        """)
        imp = mock.MagicMock()
        imp.identify = mock.MagicMock(return_value=True)
        imp.extract = mock.MagicMock(return_value=[entries[1], entries[3]])

        new_entries = extract.extract_from_file(
            '/tmp/blabla.ofx', imp, entries)
        self.assertEqual(2, len(new_entries))
        self.assertEqual([datetime.date(2016, 2, 2), datetime.date(2016, 2, 4)],
                         [entry.date for entry in new_entries])

        # Check that the entries have also been marked.
        marked_entries = [entry
                          for entry in new_entries
                          if extract.DUPLICATE_META in entry.meta]
        self.assertEqual(new_entries, marked_entries)
示例#8
0
    def test_generate(self):
        rv = self.run_with_args(example.main)
        self.assertTrue(rv.stdout)

        loaded_entries, errors, _ = loader.load_string(
            rv.stdout, extra_validations=validation.HARDCORE_VALIDATIONS)
        self.assertFalse(errors)
示例#9
0
 def test_get_values_meta__multi(self):
     entries, _, options_map = loader.load_string(TEST_INPUT)
     commodity_map = getters.get_commodity_map(entries, options_map)
     values = getters.get_values_meta(commodity_map, 'name', 'ticker')
     self.assertEqual({'HOOL': ('Hooli Corp.', 'NYSE:HOOLI'),
                       'PIPA': ('Pied Piper', None),
                       'USD': (None, None)},
                      values)
示例#10
0
 def test_get_values_meta__single(self):
     entries, _, options_map = loader.load_string(TEST_INPUT)
     commodity_map = getters.get_commodity_map(entries, options_map)
     values = getters.get_values_meta(commodity_map, 'name', default='BLA')
     self.assertEqual({'USD': 'BLA',
                       'PIPA': 'Pied Piper',
                       'HOOL': 'Hooli Corp.'},
                      values)
示例#11
0
 def test_get_accounts(self):
     entries = loader.load_string(TEST_INPUT)[0]
     accounts = getters.get_accounts(entries)
     self.assertEqual(
         {
             'Assets:US:Cash', 'Assets:US:Credit-Card', 'Expenses:Grocery',
             'Expenses:Coffee', 'Expenses:Restaurant'
         }, accounts)
示例#12
0
 def test_get_entry_accounts(self):
     entries = loader.load_string(TEST_INPUT)[0]
     accounts = getters.get_entry_accounts(
         next(entry for entry in entries
              if isinstance(entry, data.Transaction)))
     self.assertEqual(
         {'Assets:US:Cash', 'Expenses:Grocery', 'Expenses:Restaurant'},
         accounts)
示例#13
0
 def test_string_latin1(self):
     utf8_bytes = textwrap.dedent("""
       2015-01-01 open Assets:Something
       2015-05-23 note Assets:Something "¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼ "
     """).encode('latin1')
     entries, errors, options_map = loader.load_string(utf8_bytes,
                                                       encoding='latin1')
     self.assertFalse(errors)
示例#14
0
 def test_renamed_plugin_warnings(self, warn):
     with test_utils.capture('stderr'):
         entries, errors, options_map = loader.load_string("""
           plugin "beancount.ops.auto_accounts"
         """,
                                                           dedent=True)
     self.assertTrue(warn.called)
     self.assertFalse(errors)
示例#15
0
 def test_get_account_components(self):
     entries = loader.load_string(TEST_INPUT)[0]
     components = getters.get_account_components(entries)
     expected_components = {
         'US', 'Assets', 'Restaurant', 'Grocery', 'Cash', 'Coffee',
         'Expenses', 'Credit-Card'
     }
     self.assertEqual(sorted(expected_components), components)
示例#16
0
def is_processed(variant, input_txns, errors, config, input_txn_text,
                 setup_txns_text, output_txns):
    input_txns[:], _, _ = load_string(setup_txns_text + input_txn_text)

    if variant == 'depr':
        prefix_plugin_text = 'plugin "beancount_interpolate.depreciate" "' + config.strip(
            '\n') + '"\n'
    elif variant == 'recur':
        prefix_plugin_text = 'plugin "beancount_interpolate.recur" "' + config.strip(
            '\n') + '"\n'
    elif variant == 'split':
        prefix_plugin_text = 'plugin "beancount_interpolate.split" "' + config.strip(
            '\n') + '"\n'
    elif variant == 'spread':
        prefix_plugin_text = 'plugin "beancount_interpolate.spread" "' + config.strip(
            '\n') + '"\n'
    elif variant == 'all':
        prefix_plugin_text = 'plugin "beancount_interpolate.depreciate" "' + config.strip(
            '\n') + '"\n'
        prefix_plugin_text = prefix_plugin_text + 'plugin "beancount_interpolate.recur" "' + config.strip(
            '\n') + '"\n'
        prefix_plugin_text = prefix_plugin_text + 'plugin "beancount_interpolate.split" "' + config.strip(
            '\n') + '"\n'
        prefix_plugin_text = prefix_plugin_text + 'plugin "beancount_interpolate.spread" "' + config.strip(
            '\n') + '"\n'
    else:
        raise RuntimeError('Unknown variant: "{}".'.format(variant))

    full_text = prefix_plugin_text + setup_txns_text + input_txn_text
    print(
        '\nInput (full & raw):\n------------------------------------------------'
    )
    print(full_text + '\n')
    output_txns[:], errors[:], _ = load_string(full_text)
    print(
        '\nOutput (Transactions):\n------------------------------------------------\n'
    )
    for txn in output_txns:
        print(printer.format_entry(txn))
    print(
        '\nOutput (Errors):\n------------------------------------------------\n'
    )
    for error in errors:
        print(printer.format_error(error))
示例#17
0
 def test_hash_entries(self):
     previous_hashes = None
     for _ in range(64):
         entries, errors, options_map = loader.load_string(TEST_INPUT)
         hashes, errors = compare.hash_entries(entries)
         self.assertFalse(errors)
         if previous_hashes is None:
             previous_hashes = hashes
         else:
             self.assertEqual(previous_hashes.keys(), hashes.keys())
示例#18
0
 def test_get_commodities_map(self):
     entries, _, options_map = loader.load_string(TEST_INPUT)
     commodity_map = getters.get_commodity_map(entries, options_map)
     self.assertEqual({'HOOL', 'PIPA', 'USD'}, commodity_map.keys())
     self.assertTrue(all(isinstance(value, data.Commodity)
                         for value in commodity_map.values()))
     self.assertEqual(commodity_map['HOOL'],
                      next(entry
                           for entry in entries
                           if isinstance(entry, data.Commodity)))
示例#19
0
    def test_generate(self):
        # Basic test that calls out the generator.
        with test_utils.capture('stdout', 'stderr') as (stdout, _):
            result = test_utils.run_with_args(example.main, [])
        self.assertEqual(0, result, str(result))
        file_contents = stdout.getvalue()
        self.assertTrue(file_contents)

        loaded_entries, errors, _ = loader.load_string(
            file_contents, extra_validations=validation.HARDCORE_VALIDATIONS)
        self.assertFalse(errors)
示例#20
0
    def test_forecast(self):
        input_text = textwrap.dedent("""

            plugin "beancount.plugins.forecast"

            2011-01-01 open Expenses:Restaurant
            2011-01-01 open Assets:Cash

            2011-05-17 # "Something [MONTHLY UNTIL 2011-12-31]"
              Expenses:Restaurant   50.02 USD
              Assets:Cash

        """)
        entries, errors, __ = loader.load_string(input_text)
        self.assertFalse(errors)
        self.assertEqualEntries(
            """

            2011-01-01 open Expenses:Restaurant
            2011-01-01 open Assets:Cash

            2011-05-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-06-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-07-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-08-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-09-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-10-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-11-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD

            2011-12-17 # "Something"
              Expenses:Restaurant           50.02 USD
              Assets:Cash                  -50.02 USD
        """, entries)
示例#21
0
def bean_to_json(bean_str: str):
    if 'beancount.plugins.auto_accounts' not in bean_str:
        bean_str = 'plugin "beancount.plugins.auto_accounts"\n' + bean_str
    entries, errors, options = loader.load_string(bean_str)
    data = {
        "variant": "beancount",
        "version": "2.2.1",
        "entries": list(map(wrap_entry, entries)),
        "errors": errors,
        "options": options,
    }
    return json_dumps_decimal(data), data
示例#22
0
    def test_verify_document_files_exist(self):
        entries, _, options_map = loader.load_string(textwrap.dedent("""
          option "plugin_processing_mode" "raw"
          2014-06-08 document Assets:US:Bank:Checking "ROOT/Assets/US/Bank/Checking/2014-06-08.bank-statement.pdf"
          2014-07-01 document Assets:US:Bank:Savings  "ROOT/Assets/US/Bank/Savings/2014-07-01.savings.pdf"
          2014-07-10 document Assets:US:Bank:Savings  "ROOT/Assets/US/Bank/Savings/2014-07-10.something-else.pdf"
        """).replace('ROOT', self.root))

        _, errors = documents.verify_document_files_exist(entries, options_map)
        self.assertEqual(1, len(errors))
        document_error = errors[0]
        self.assertTrue(
            document_error.entry.filename.endswith('2014-07-10.something-else.pdf'))
示例#23
0
    def test_tolerances__number_on_cost_fail_to_succ(self):
        # An example of a transaction that would fail without the inferred
        # tolerances and succeed with them.
        input_string = textwrap.dedent("""
          plugin "beancount.plugins.auto_accounts"

          2014-02-25 *
            Assets:Account3       5.111 VHT {1000.00 USD}
            Assets:Account4      -5110.80 USD
        """)
        input_option = textwrap.dedent("""
          option "infer_tolerance_from_cost" "True"
        """)

        entries, errors, options_map = loader.load_string(input_string)
        self.assertFalse(options_map["infer_tolerance_from_cost"])
        self.assertEqual(1, len(errors))
        self.assertRegex(errors[0].message, 'Transaction does not balance:.*0.20000 USD')

        entries, errors, options_map = loader.load_string(input_option + input_string)
        self.assertTrue(options_map["infer_tolerance_from_cost"])
        self.assertFalse(errors)
示例#24
0
def main():
    argparser = argparse.ArgumentParser(description=__doc__)
    argparser.add_argument('infile',
                           type=argparse.FileType('r'),
                           help='Filename or "-" for stdin')
    args = argparser.parse_args()

    # Read input from stdin or a given filename.
    entries, errors, options = loader.load_string(args.infile.read())

    # Print out sorted entries.
    for entry in data.sorted(entries):
        printer.print_entry(entry)
示例#25
0
    def test_render_missing(self):
        # We want to make sure we never render with scientific notation.
        input_string = textwrap.dedent("""

          2019-01-19 * "Fitness First" "Last training session"
            Expenses:Sports:Gym:Martin
            Assets:Martin:Cash

        """)
        entries, errors, options_map = loader.load_string(input_string)
        txn = errors[0].entry
        oss = io.StringIO()
        printer.print_entry(txn, file=oss)
示例#26
0
    def test_find_similar_entries(self, entries, _, __):
        """
            plugin "beancount.plugins.auto_accounts"

            2016-01-03 *
              Expenses:Tips         1.03 USD
              Assets:Other

            2016-01-04 *
              Expenses:Coffee       1.04 USD
              Assets:Other

            2016-01-05 *
              Expenses:Restaurant   1.05 USD
              Assets:Other

            2016-01-06 *
              Expenses:Groceries    1.06 USD
              Assets:Other

            2016-01-07 *
              Expenses:Alcohol      1.07 USD
              Assets:Other

            2016-01-08 *
              Expenses:Smoking      1.08 USD
              Assets:Other

            2016-01-09 *
              Expenses:Taxi         1.09 USD
              Assets:Other
        """
        new_entries, _, __ = loader.load_string("""
            plugin "beancount.plugins.auto_accounts"

            2016-01-06 *
              Expenses:Groceries    1.06 USD
              Assets:Other
        """)
        for days, num_comparisons in [(0, 1), (1, 1), (2, 1)]:
            duplicates = similar.find_similar_entries(new_entries,
                                                      entries,
                                                      lambda e1, e2: True,
                                                      window_days=days)
            self.assertEqual(num_comparisons, len(duplicates))

            duplicates = similar.find_similar_entries(new_entries,
                                                      entries,
                                                      lambda e1, e2: False,
                                                      window_days=days)
            self.assertEqual(0, len(duplicates))
示例#27
0
    def test_compare_entries(self):
        entries1, _, __ = loader.load_string(TEST_INPUT)
        entries2, _, __ = loader.load_string(TEST_INPUT)

        # Check two equal sets.
        same, missing1, missing2 = compare.compare_entries(entries1, entries2)
        self.assertTrue(same)
        self.assertFalse(missing1)
        self.assertFalse(missing2)

        # First > Second.
        same, missing1, missing2 = compare.compare_entries(
            entries1, entries2[:-1])
        self.assertFalse(same)
        self.assertTrue(missing1)
        self.assertFalse(missing2)
        self.assertEqual(1, len(missing1))
        self.assertTrue(isinstance(missing1.pop(), data.Close))

        # First < Second.
        same, missing1, missing2 = compare.compare_entries(
            entries1[:-1], entries2)
        self.assertFalse(same)
        self.assertFalse(missing1)
        self.assertTrue(missing2)
        self.assertEqual(1, len(missing2))
        self.assertTrue(isinstance(missing2.pop(), data.Close))

        # Both have missing.
        same, missing1, missing2 = compare.compare_entries(
            entries1[1:], entries2[:-1])
        self.assertFalse(same)
        self.assertTrue(missing1)
        self.assertTrue(missing2)
        self.assertEqual(1, len(missing1))
        self.assertTrue(isinstance(missing1.pop(), data.Close))
        self.assertEqual(1, len(missing2))
        self.assertTrue(isinstance(missing2.pop(), data.Open))
示例#28
0
    def test_get_account_open_close(self):
        entries = loader.load_string(TEST_INPUT)[0]
        ocmap = getters.get_account_open_close(entries)
        self.assertEqual(5, len(ocmap))

        def mapfound(account_name):
            open, close = ocmap[account_name]
            return (open is not None, close is not None)

        self.assertEqual(mapfound('Assets:US:Cash'), (True, True))
        self.assertEqual(mapfound('Assets:US:Credit-Card'), (True, True))
        self.assertEqual(mapfound('Expenses:Grocery'), (True, False))
        self.assertEqual(mapfound('Expenses:Coffee'), (True, False))
        self.assertEqual(mapfound('Expenses:Restaurant'), (True, False))
示例#29
0
    def assertRoundTrip(self, entries1, errors1):
        self.assertFalse(errors1)

        # Print out the entries and parse them back in.
        oss1 = io.StringIO()
        oss1.write('option "plugin_processing_mode" "raw"\n')
        printer.print_entries(entries1, file=oss1)
        entries2, errors, __ = loader.load_string(oss1.getvalue())

        self.assertEqualEntries(entries1, entries2)
        self.assertFalse(errors)

        # Print out those reparsed and parse them back in.
        oss2 = io.StringIO()
        oss2.write('option "plugin_processing_mode" "raw"\n')
        printer.print_entries(entries2, file=oss2)
        entries3, errors, __ = loader.load_string(oss2.getvalue())

        self.assertEqualEntries(entries1, entries3)
        self.assertFalse(errors)

        # Compare the two output texts.
        self.assertEqual(oss2.getvalue(), oss1.getvalue())
示例#30
0
def newly_generated_txns(output_txns, correctly_generated_txn_text):

    # Get transactions from output of plugin (should be tagged appropriately)
    transactions = [txn for txn in output_txns if isinstance(txn, Transaction)]

    # Get correctly generated transactions from feature file
    correctly_generated_txns, _, _ = load_string(correctly_generated_txn_text)

    has_correct, missing_entries = includes_entries(correctly_generated_txns,
                                                    transactions)

    print("Missing entries: {}".format(len(missing_entries)))

    assert has_correct
示例#31
0
def test_link_statements_missing(tmpdir):
    sample_folder = tmpdir.mkdir('fava_plugins').mkdir('documents')

    bfile = dedent("""
        option "documents" "{}"
        plugin "fava.plugins.link_statements"

        2016-10-31 open Expenses:Foo
        2016-10-31 open Assets:Cash

        2016-11-01 * "Foo" "Bar"
            statement: "test/Foobar.pdf"
            Expenses:Foo                100 EUR
            Assets:Cash
    """.format(sample_folder))

    entries, errors, _ = load_string(bfile)

    assert len(errors) == 1
    assert isinstance(errors[0], StatementDocumentError)
    assert len(entries) == 3
示例#32
0
def test_link_documents_missing(tmpdir):
    sample_folder = tmpdir.mkdir('fava_plugins').mkdir('documents')

    bfile = _format("""
        option "documents" "{}"
        plugin "fava.plugins.link_documents"

        2016-10-31 open Expenses:Foo
        2016-10-31 open Assets:Cash

        2016-11-01 * "Foo" "Bar"
            document: "{}"
            Expenses:Foo                100 EUR
            Assets:Cash
    """, (sample_folder, os.path.join('test', 'Foobar.pdf')))

    entries, errors, _ = load_string(bfile)

    assert len(errors) == 1
    assert isinstance(errors[0], DocumentError)
    assert len(entries) == 3
示例#33
0
def test_upcoming_events():
    entries, _, _ = load_string('{} event "some_event" "test"\n'
                                '2012-12-12 event "test" "test"'.format(
                                    str(datetime.date.today())))
    assert len(upcoming_events(entries, 1)) == 1
示例#34
0
def load_doc(request):
    return load_string(request.function.__doc__, dedent=True)