def test_spreadsheet_with_misconfigured_income_columns(self): """ Test a spreadsheet that doesn't have the column headers that were set in config.ini. Having a required field set in the config.ini that doesn't exist in the corresponding .csv, should throw an assertion error. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') config.required_income_columns = set(['Foo', 'Bar']) self.assertRaises(AssertionError, SavingsRate, config)
def test_load_account_config_without_ini(self): """ Test the loading of account_config.ini. """ # Load the config config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') # Unset the conf_dir path so the account_config.ini won't be found config.user_conf_dir = '' self.assertRaises(FileNotFoundError, config.load_account_config_from_ini)
def test_load_account_config_without_ini(self): """ Test the loading of account_config.ini. """ # Load the config config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') # Unset the conf_dir path so the account_config.ini won't be found config.user_conf_dir = '' self.assertRaises(FileNotFoundError, config.load_account_config_from_ini)
def test_clean_num(self): config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) val1 = sr.clean_num('') val2 = sr.clean_num(' ') val3 = sr.clean_num(None) val4 = sr.clean_num(4) val5 = sr.clean_num(4.4) val6 = sr.clean_num(Decimal(4.4)) self.assertRaises(TypeError, sr.clean_num, 'Son of Mogh') self.assertRaises(TypeError, sr.clean_num, '4.4') self.assertEqual( val1, 0.0 ), 'An empty string should evaluate to 0.0. It evaluated to ' + str( val1) self.assertEqual( val2, 0.0 ), 'An empty string should evaluate to 0.0. It evaluated to ' + str( val2) self.assertEqual( val3, 0.0), 'None should evaluate to 0.0. It evaluated to ' + str(val3) self.assertEqual( val4, 4), '4 should evaluate to 4.4. It evaluated to ' + str(val4) self.assertEqual( val5, 4.4), '4.4 should evaluate to 4.4. It evaluated to ' + str(val5) self.assertEqual( val6, Decimal(4.4) ), '4.4 should evaluate to Decimal(4.4). It evaluated to ' + str(val6)
def test_get_monthly_savings_rates_0_0(self): """ %0 SR each month, %0 average """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) md = OrderedDict() md['2015-01'] = { 'income': [Decimal(0.0)], 'employer_match': [Decimal(0.0)], 'taxes_and_fees': [Decimal(0.0)], 'savings': [Decimal(0.0)] } md['2015-02'] = { 'income': [Decimal(0.0)], 'employer_match': [Decimal(0.0)], 'taxes_and_fees': [Decimal(0.0)], 'savings': [Decimal(0.0)] } r4 = sr.get_monthly_savings_rates(test_data=md) for item4 in r4: self.assertEqual(item4[1], Decimal(0.0), \ 'Incorrect savings rate. Calculated: ' + str(item4[1])) average_rates = sr.average_monthly_savings_rates(r4) self.assertEqual(average_rates, Decimal(0.0), \ 'Wrong average for monthly rates.')
def test_get_monthly_savings_rates_25_75(self): """ %25 SR first month, %75 second month, %50 average """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) md3 = OrderedDict() md3['2015-01'] = { 'income': [Decimal(2000.0)], 'employer_match': [Decimal(200.0)], 'taxes_and_fees': [Decimal(200.0)], 'savings': [Decimal(500.0)] } md3['2015-02'] = { 'income': [Decimal(2000.0)], 'employer_match': [Decimal(200.0)], 'taxes_and_fees': [Decimal(200.0)], 'savings': [Decimal(1500.0)] } r3 = sr.get_monthly_savings_rates(test_data=md3) self.assertEqual(r3[0][1], Decimal(25), \ 'Incorrect savings rate. Calculated: ' + str(r3[0][1])) self.assertEqual(r3[1][1], Decimal(75), \ 'Incorrect savings rate. Calculated: ' + str(r3[1][1])) average_rates = sr.average_monthly_savings_rates(r3) self.assertEqual(average_rates, Decimal(50.0), \ 'Wrong average for monthly rates.')
def run(): """ Run the application in, "ini" mode. Args: config_path: string, path to a directory of config .ini files. Should include a trailing "/". """ # Capture commandline arguments. prog='' argument must # match the command name in setup.py entry_points parser = argparse.ArgumentParser(prog='savingsrates') parser.add_argument('-p', nargs='?', help='A path to a directory of config files.') args = parser.parse_args() inputs = {'p': args.p} config_path = inputs['p'] # Instantiate a savings rate config object config = SRConfig('ini', config_path, 'config.ini') # Instantiate a savings rate object for a user savings_rate = SavingsRate(config) monthly_rates = savings_rate.get_monthly_savings_rates() # Plot the user's savings rate user_plot = Plot(savings_rate) user_plot.plot_savings_rates(monthly_rates)
def test_load_account_config_without_option(self): """ Load a config option without the required "self" option. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') config.account_config.remove_option('Users', 'self') self.assertRaises(configparser.NoOptionError, config.account_config.get, 'Users', 'self')
def test_load_account_config_without_section(self): """ Load an account config without the required [Users] section. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') config.account_config.remove_section('Users') self.assertRaises(configparser.NoSectionError, config.account_config.get, 'Users', 'self')
def test_load_account_config_without_enemies(self): """ Loading an account_config.ini wout enemies shouldn't blow up. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini', \ test=True, test_file='account-config-test-no-enemies.ini') self.assertEqual(config.user_enemies, None)
def test_required_account_sections(self): """ A missing required section in account-config.ini should throw an assertion error. """ for section in REQUIRED_INI_ACCOUNT_OPTIONS: config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') config.account_config.remove_section(section) self.assertRaises(AssertionError, config.validate_account_ini)
def test_get_taxes_from_csv(self): """ There should be as many items as commas in the config +1. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) commas_in_config = config.user_config.get('Sources', 'taxes_and_fees').count(',') self.assertEqual(len(sr.get_taxes_from_csv()), commas_in_config + 1)
def test_blank_csv_files(self): """ The files exist but they are totally blank. PROBLEM - this test shouldn't pass but it does. At a minimum, test_columns should throw an AssertionError, shouldn't it? What's going on here? """ config = SRConfig('ini', 'tests/test_config/', 'config-test-blank-csv.ini', \ test=True, test_file='account-config-blank-csv.ini') sr = SavingsRate(config)
def test_required_user_options(self): """ A missing required option in config.ini should throw an assertion error. """ for section in REQUIRED_INI_USER_OPTIONS: for option in REQUIRED_INI_USER_OPTIONS[section]: config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') config.user_config.remove_option(section, option) self.assertRaises(AssertionError, config.validate_user_ini)
def test_empty_csv_files(self): """ The files exist with the proper column headings but they don't have any rows populated. This shouldn't blow up. """ config = SRConfig('ini', 'tests/test_config/', 'config-test-empty-csv.ini', \ test=True, test_file='account-config-empty-csv.ini') sr = SavingsRate(config) self.assertEqual(sr.income, OrderedDict()) self.assertEqual(sr.savings, OrderedDict())
def test_load_account_config_with_good_ini(self): """ Load a good account-config.ini. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') self.assertEqual(len(config.user), 3, \ 'The "self" option in the [Users] section should have an id, name, and path to user config separated by commas.') user_ids = set([]) main_user_id = config.user[0] user_ids.add(main_user_id) if config.war_mode: for enemy in config.user_enemies: user_ids.add(enemy[0]) self.assertEqual(len(enemy), 3, \ 'If "war" is on. The "enemies" option must be se in the account-config.ini.') self.assertEqual(len(user_ids), 3, 'Every user ID must be unique.')
def test_average_monthly_savings_rates_1_month(self): """ %0 SR each month, %0 average """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) md = OrderedDict() md['2015-01'] = { 'income': [Decimal(2000.0)], 'employer_match': [Decimal(200.0)], 'taxes_and_fees': [Decimal(200.0)], 'savings': [Decimal(500.0)] } rates = sr.get_monthly_savings_rates(test_data=md) average_rates = sr.average_monthly_savings_rates(rates) self.assertEqual(average_rates, Decimal(25.0), \ 'Wrong average for monthly rates.')
def test_data_loaded_by_load_savings_from_csv(self): """ Dates should be in chronological order assuming they were entered that way. All required_income_columns should be present in the data structure. """ config = SRConfig('ini', 'tests/test_config/', 'config-test.ini') sr = SavingsRate(config) dates = [] i = 0 for d in sr.savings: for req in sr.config.required_savings_columns: self.assertEqual(req in sr.savings[d], True, \ 'Missing a field in SavingsRate.savings.') dates.append(d) if i > 0: assert d > dates[i-1], \ 'Income transaction dates are not in chronological order. Were they entered chronologically?' i += 1
def return_bad_config(): """ Return a bad account-config.ini. """ return SRConfig('ini', 'tests/test_config/', 'config-test.ini', \ test=True, test_file='account-config-test-bad.ini')