import2ledger/tests/test_importers.py
Brett Smith ab8559c75b csv: Support importing squared CSV spreadsheets.
See the test comment for more rationale.
2019-08-28 10:22:10 -04:00

66 lines
2.6 KiB
Python

import csv
import datetime
import decimal
import io
import importlib
import itertools
import pathlib
import shutil
import re
import pytest
import yaml
from import2ledger import importers, strparse
from . import DATA_DIR
class TestImporters:
with pathlib.Path(DATA_DIR, 'imports.yml').open() as yaml_file:
test_data = yaml.load(yaml_file)
for test in test_data:
test['source'] = DATA_DIR / test['source']
module_name, class_name = test['importer'].rsplit('.', 1)
module = importlib.import_module('.' + module_name, 'import2ledger.importers')
test['importer'] = getattr(module, class_name)
@pytest.mark.parametrize('source_path,importer', [
(t['source'], t['importer']) for t in test_data
])
def test_can_import(self, source_path, importer):
with source_path.open() as source_file:
assert importer.can_import(source_file)
@pytest.mark.parametrize('source_path,importer,header_rows,header_cols', [
(t['source'], t['importer'], t['header_rows'], t['header_cols'])
for t in test_data if t.get('header_rows')
])
def test_can_import_squared_csv(self, source_path, importer, header_rows, header_cols):
# Sometimes when we munge spreadsheets by hand (e.g., to filter by
# project) tools like LibreOffice Calc write a "squared" spreadsheet,
# where every row has the same length. This test ensures the results
# are still recognized for import.
with io.StringIO() as squared_file:
csv_writer = csv.writer(squared_file)
with source_path.open() as source_file:
for row in itertools.islice(csv.reader(source_file), header_rows):
padding = [None] * (header_cols - len(row))
csv_writer.writerow(row + padding)
shutil.copyfileobj(source_file, squared_file)
squared_file.seek(0)
assert importer.can_import(squared_file)
@pytest.mark.parametrize('source_path,import_class,expect_results', [
(t['source'], t['importer'], t['expect']) for t in test_data
])
def test_import(self, source_path, import_class, expect_results):
with source_path.open() as source_file:
importer = import_class(source_file)
for actual, expected in itertools.zip_longest(importer, expect_results):
actual['amount'] = strparse.currency_decimal(actual['amount'])
assert actual == expected
def test_loader(self):
all_importers = list(importers.load_all())
for test in self.test_data:
assert test['importer'] in all_importers