Coverage for tests/test_app_settings.py: 100%
124 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-05 04:36 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-05 04:36 +0000
1import pandas as pd
2import pytest
4from sankey_cashflow import AppSettings
7class TestDefaultInitialization:
9 def test_default_initialization(self, default_app_settings):
10 settings = default_app_settings
11 assert settings.data_source == 'sample_data/expenses.csv'
12 assert settings.audit_mode is False
13 assert settings.data_sheet == 'Transactions_*'
14 assert settings._labels_source == 'sample_data/labels.csv'
15 assert settings.filter_dates is None
16 assert settings.separate_taxes is False
17 assert settings.verbose is False
18 assert settings._g_creds == './google_service_account_key.json'
19 assert settings.distribute_amounts is False
20 assert settings.all_time is False
21 assert settings.recurring is False
22 assert settings.base_title == 'Cashflow'
23 assert settings._date_filter_start is None
24 assert settings._date_filter_end is None
25 assert settings.tags is None
26 assert settings.feed_in is None
27 assert settings.exclude_tags is None
28 assert settings.stores is None
29 assert settings.tag_override is False
30 assert settings.hover == 'Category'
31 assert settings.chart_resolution is None
32 assert settings.sales_tax_classification == 'Taxes'
33 assert settings.tip_classification == 'xTips'
34 assert settings.diagram_type == 'sankey'
35 assert settings.colors == {}
37 def test_verbose_logging(self, make_args):
38 settings = AppSettings(make_args(verbose=True))
39 assert settings.verbose is True
42class TestHoverOption:
44 @pytest.mark.parametrize('hover_arg', ['desc', 'stores', 'description', 'DESC'])
45 def test_hover_maps_to_description(self, make_args, hover_arg):
46 settings = AppSettings(make_args(hover=hover_arg))
47 assert settings.hover == 'Description'
49 @pytest.mark.parametrize('hover_arg', ['none', 'no', 'false', 'NONE'])
50 def test_hover_disabled(self, make_args, hover_arg):
51 settings = AppSettings(make_args(hover=hover_arg))
52 assert settings.hover is None
54 def test_hover_unrecognized_keeps_default(self, make_args):
55 settings = AppSettings(make_args(hover='unknown-option'))
56 assert settings.hover == 'Category'
59class TestDiagramType:
61 @pytest.mark.parametrize('dtype_arg,expected', [('sankey', 'sankey'), ('line', 'line'), ('LINE', 'line')])
62 def test_recognized_dtype(self, make_args, dtype_arg, expected):
63 settings = AppSettings(make_args(dtype=dtype_arg))
64 assert settings.diagram_type == expected
66 def test_unrecognized_dtype_keeps_default(self, make_args):
67 settings = AppSettings(make_args(dtype='pie'))
68 assert settings.diagram_type == 'sankey'
71class TestTagsStoresExclude:
73 def test_tags_split_and_stripped(self, make_args):
74 settings = AppSettings(make_args(tags=' Ford , Dodge '))
75 assert settings.tags == ['Ford', 'Dodge']
77 def test_tag_override_requires_tags(self, make_args):
78 settings = AppSettings(make_args(tags='Ford', tag_override=True))
79 assert settings.tag_override is True
81 def test_tag_override_ignored_without_tags(self, make_args):
82 settings = AppSettings(make_args(tags=None, tag_override=True))
83 assert settings.tag_override is False
85 def test_feed_in_requires_tags(self, make_args):
86 settings = AppSettings(make_args(tags='Ford', feed_in=True))
87 assert settings.feed_in is True
89 def test_feed_in_ignored_without_tags(self, make_args):
90 settings = AppSettings(make_args(tags=None, feed_in=True))
91 assert settings.feed_in is None
93 def test_exclude_split_and_stripped(self, make_args):
94 settings = AppSettings(make_args(exclude=' Onetime , Refund '))
95 assert settings.exclude_tags == ['Onetime', 'Refund']
97 def test_stores_split_and_stripped(self, make_args):
98 settings = AppSettings(make_args(stores=' Costco , Amazon '))
99 assert settings.stores == ['Costco', 'Amazon']
101 def test_tags_and_stores_together_raises(self, make_args):
102 with pytest.raises(Exception):
103 AppSettings(make_args(tags='Ford', stores='Costco'))
106class TestDateFilterSetters:
108 def test_date_filter_start_setter(self, default_app_settings):
109 default_app_settings.date_filter_start = '2023-01-01'
110 assert default_app_settings.date_filter_start == pd.to_datetime('2023-01-01')
112 def test_date_filter_start_setter_empty_is_none(self, default_app_settings):
113 default_app_settings.date_filter_start = ''
114 assert default_app_settings.date_filter_start is None
116 def test_date_filter_end_setter(self, default_app_settings):
117 default_app_settings.date_filter_end = '2023-12-31'
118 assert default_app_settings.date_filter_end == pd.to_datetime('2023-12-31')
120 def test_date_filter_end_setter_empty_is_none(self, default_app_settings):
121 default_app_settings.date_filter_end = ''
122 assert default_app_settings.date_filter_end is None
125class TestCredsAndLabelsSetters:
127 def test_g_creds_setter_missing_file_raises(self, default_app_settings):
128 with pytest.raises(Exception):
129 default_app_settings.g_creds = 'invalid_path.json'
131 def test_labels_source_setter_missing_file_raises(self, default_app_settings):
132 with pytest.raises(Exception):
133 default_app_settings.labels_source = 'invalid_path.csv'
135 def test_labels_source_setter_valid_csv(self, default_app_settings):
136 default_app_settings.labels_source = 'sample_data/labels.csv'
137 assert default_app_settings.labels_source == 'sample_data/labels.csv'
140class TestSourceValidation:
142 def test_source_data_location_csv(self, default_app_settings):
143 assert default_app_settings.source_data_location() == 'sample_data/expenses.csv'
145 def test_source_data_location_gsheet(self, make_args):
146 settings = AppSettings(make_args(
147 source='My Workbook', sheet='Transactions_2023', creds='sample_data/labels.csv'
148 ))
149 assert settings.source_data_location() == 'My Workbook: Transactions_2023'
151 def test_validate_sources_missing_source_raises(self, default_app_settings):
152 default_app_settings.data_source = None
153 with pytest.raises(Exception):
154 default_app_settings.validate_sources()
156 def test_validate_sources_csv_requires_csv_labels(self, make_args):
157 with pytest.raises(Exception):
158 AppSettings(make_args(source='sample_data/expenses.csv', srcmap='Sources-Targets'))
160 def test_validate_sources_missing_csv_file_raises(self, make_args):
161 with pytest.raises(Exception):
162 AppSettings(make_args(source='does_not_exist.csv'))
164 def test_validate_sources_gsheet_requires_sheet_name(self, make_args):
165 with pytest.raises(Exception):
166 AppSettings(make_args(source='My Workbook', sheet=None, srcmap='Sources-Targets'))
168 def test_validate_sources_gsheet_requires_creds_file(self, make_args):
169 with pytest.raises(Exception):
170 AppSettings(make_args(
171 source='My Workbook', sheet='Transactions_2023',
172 srcmap='Sources-Targets', creds='missing_creds.json'
173 ))