def test_exchange_rate_weekend_date(USD_exchange_rates_mock): # set the date on a Sunday, expect fridays rate friday = date(2020, 5, 22) sunday = date(2020, 5, 24) er = ExchangeRate('USD', friday, sunday) expected_rate = er.get_rate(friday) assert er.get_rate(sunday) == expected_rate
def test_ticker_gains_ok(transactions, exchange_rates_mock): tg = TickerGains(transactions[0].ticker) er = ExchangeRate('USD', transactions[0].date, transactions[3].date) er_map = {'USD': er} # Add first transaction - 'BUY' # Add second transaction - 'BUY' # Add third transaction - 'SELL' transactions_to_test = [transactions[0], transactions[2], transactions[3]] tg.add_transactions(transactions_to_test, er_map) assert transactions[0].exchange_rate == 2.0 assert transactions[0].share_balance == 100 assert transactions[0].proceeds == 10000.0 assert transactions[0].capital_gain == 0.0 assert transactions[0].acb == 10020.00 assert transactions[0].superficial_loss is False assert transactions[0].expenses == 20.0 assert transactions[2].exchange_rate == 2.0 assert transactions[2].share_balance == 50 assert transactions[2].proceeds == 12000.00 assert transactions[2].capital_gain == 6970.00 assert transactions[2].acb == 5010.00 assert transactions[2].superficial_loss is False assert transactions[2].expenses == 20.0 assert transactions[3].exchange_rate == 2.0 assert transactions[3].share_balance == 100 assert transactions[3].proceeds == 13000.00 assert transactions[3].capital_gain == 0.0 assert transactions[3].acb == 13020.00 assert transactions[3].superficial_loss is False assert transactions[3].expenses == 20.0
def _request_error_throwing_test(requests_mock, expected_error, expected_message): requests_mock.get(rm.ANY, exc=expected_error) day = date(2020, 5, 22) with pytest.raises(ClickException) as excinfo: ExchangeRate("USD", day, day) assert expected_message == excinfo.value.message
def test_exchange_rate_after_max_date(): """Test that we throw an error when we request exchange rates after the maximum date (which is today's date) """ today = datetime.today().date() tmr = today + timedelta(days=1) with pytest.raises(ClickException) as excinfo: ExchangeRate('USD', today, tmr) assert (excinfo.value.message == "We do not support having transactions past today's date")
def test_ticker_gains_negative_balance(transactions, exchange_rates_mock): """If the first transaction added is a sell, it is illegal since this causes a negative balance, which is impossible""" sell_transaction = transactions[2] tg = TickerGains(sell_transaction.ticker) er = ExchangeRate('USD', transactions[2].date, transactions[2].date) er_map = {'USD': er} with pytest.raises(ClickException) as excinfo: tg.add_transactions([sell_transaction], er_map) assert excinfo.value.message == "Transaction caused negative share balance"
def test_superficial_loss_no_purchase_after_loss(exchange_rates_mock): """Testing if transaction is marked as a superficial loss even if there are no purchases made after the loss""" transactions = [ Transaction(date(2018, 1, 1), 'ESPP PURCHASE', 'ANET', 'BUY', 100, 100.00, 10.00, 'USD'), Transaction(date(2018, 1, 2), 'RSU VEST', 'ANET', 'SELL', 99, 50.00, 10.00, 'USD') ] tg = TickerGains(transactions[0].ticker) er = ExchangeRate('USD', transactions[0].date, transactions[1].date) er_map = {'USD': er} tg.add_transactions(transactions, er_map) assert transactions[1].superficial_loss assert transactions[1].capital_gain == 0
def test_gain_not_marked_as_superficial_loss(exchange_rates_mock): """Testing if transaction is not marked as a superficial loss if it does not result in a loss""" transactions = [ Transaction(date(2018, 1, 1), 'ESPP PURCHASE', 'ANET', 'BUY', 100, 1.00, 10.00, 'USD'), Transaction(date(2018, 8, 1), 'RSU VEST', 'ANET', 'SELL', 100, 50.00, 10.00, 'USD') ] tg = TickerGains(transactions[0].ticker) er = ExchangeRate('USD', transactions[0].date, transactions[1].date) er_map = {'USD': er} tg.add_transactions(transactions, er_map) assert not transactions[1].superficial_loss assert transactions[1].capital_gain > 0
def _get_map_of_currencies_to_exchange_rates(transactions): """First, split the list of transactions into sublists where each sublist will only contain transactions with the same currency""" currency_groups = [ list(g) for _, g in groupby(transactions, lambda t: t.currency) ] currencies_to_exchange_rates = dict() # Create a separate ExchangeRate object for each currency for currency_group in currency_groups: currency = currency_group[0].currency min_date = currency_group[0].date max_date = currency_group[-1].date currencies_to_exchange_rates[currency] = ExchangeRate( currency, min_date, max_date) return currencies_to_exchange_rates
def test_loss_no_balance_after_window(exchange_rates_mock): """Testing if transaction is not marked as a superficial loss if there is no share balance 30 days after the loss""" transactions = [ Transaction(date(2018, 1, 1), 'ESPP PURCHASE', 'ANET', 'BUY', 100, 100.00, 10.00, 'USD'), Transaction(date(2018, 1, 2), 'RSU VEST', 'ANET', 'SELL', 99, 50.00, 10.00, 'USD'), Transaction(date(2018, 1, 3), 'RSU VEST', 'ANET', 'SELL', 1, 100.00, 10.00, 'USD'), Transaction(date(2018, 2, 10), 'RSU VEST', 'ANET', 'BUY', 1, 100.00, 10.00, 'USD') ] tg = TickerGains(transactions[0].ticker) er = ExchangeRate('USD', transactions[0].date, transactions[1].date) er_map = {'USD': er} tg.add_transactions(transactions, er_map) assert not transactions[1].superficial_loss assert transactions[1].capital_gain < 0
def test_unsupported_currency_returns_error(): day = date(2020, 5, 22) with pytest.raises(ClickException) as excinfo: ExchangeRate("BLAHBLAH", day, day) assert excinfo.value.message == "Currency (BLAHBLAH) is not currently supported. The supported currencies are ['CAD', 'USD']" # noqa: E501
def test_exchange_rate_ok_date(USD_exchange_rates_mock): # set the date on a Friday thursday = date(2020, 5, 21) friday = date(2020, 5, 22) er = ExchangeRate('USD', thursday, friday) assert er.get_rate(friday) == Decimal('1.3')
def test_exchange_rate_init_before_min_date(): early = date(2007, 4, 30) with pytest.raises(ClickException) as excinfo: ExchangeRate('USD', early, early) assert (excinfo.value.message == "We do not support having transactions before 2007-05-01")
def test_exchange_rate_noon_only(USD_exchange_rates_mock): noon_rate_date = date(2016, 5, 21) er = ExchangeRate('USD', noon_rate_date, noon_rate_date) expected_rate = er.get_rate(noon_rate_date) assert expected_rate == Decimal('1.1')
def test_exchange_rate_end_after_start(): end = date(2020, 5, 22) start = end + timedelta(days=1) with pytest.raises(ClickException) as excinfo: ExchangeRate('USD', start, end) assert excinfo.value.message == "End date must be after start date"
def test_get_rate_before_min_date_exception(USD_exchange_rates_mock): er = ExchangeRate('USD', date(2020, 5, 22), date(2020, 5, 25)) with pytest.raises(ClickException) as excinfo: er.get_rate(date(2017, 1, 2)) assert excinfo.value.message == "Unable to find exchange rate on 2017-01-02" # noqa: E501
def test_no_observations_found_exception(requests_mock): day = date(2020, 5, 22) requests_mock.get(rm.ANY, json={}) with pytest.raises(ClickException) as excinfo: ExchangeRate("USD", day, day) assert excinfo.value.message == "No observations were found using currency USD" # noqa: E501
def test_exchange_rate_noon_and_indicative(USD_exchange_rates_mock): noon_rate_date = date(2016, 5, 21) indicative_rate_date = date(2020, 5, 22) er = ExchangeRate('USD', noon_rate_date, indicative_rate_date) assert er.get_rate(noon_rate_date) == Decimal('1.1') assert er.get_rate(indicative_rate_date) == Decimal('1.3')
def test_cad_to_cad_rate_is_1(): day = date(2020, 5, 22) er = ExchangeRate('CAD', day, day) assert er.get_rate(day) == 1