mirror of
https://github.com/arsenetar/dupeguru.git
synced 2024-11-16 20:29:02 +00:00
212 lines
7.7 KiB
Python
212 lines
7.7 KiB
Python
# Created By: Virgil Dupras
|
|
# Created On: 2008-04-20
|
|
# Copyright 2013 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
|
# which should be included with this package. The terms are also available at
|
|
# http://www.hardcoded.net/licenses/bsd_license
|
|
|
|
from datetime import date
|
|
import sqlite3 as sqlite
|
|
|
|
from .. import io
|
|
from ..testutil import eq_, assert_almost_equal
|
|
from ..currency import Currency, RatesDB, CAD, EUR, USD
|
|
|
|
PLN = Currency(code='PLN')
|
|
|
|
def setup_module(module):
|
|
global FOO
|
|
global BAR
|
|
FOO = Currency.register('FOO', 'Currency with start date', start_date=date(2009, 1, 12), start_rate=2)
|
|
BAR = Currency.register('BAR', 'Currency with stop date', stop_date=date(2010, 1, 12), latest_rate=2)
|
|
|
|
def teardown_module(module):
|
|
# We must unset our test currencies or else we might mess up with other tests.
|
|
from .. import currency
|
|
import imp
|
|
imp.reload(currency)
|
|
|
|
def teardown_function(function):
|
|
Currency.set_rates_db(None)
|
|
|
|
def test_currency_creation():
|
|
# Different ways to create a currency.
|
|
eq_(Currency('CAD'), CAD)
|
|
eq_(Currency(name='Canadian dollar'), CAD)
|
|
|
|
def test_currency_copy():
|
|
# Currencies can be copied.
|
|
import copy
|
|
eq_(copy.copy(CAD), CAD)
|
|
eq_(copy.deepcopy(CAD), CAD)
|
|
|
|
def test_get_rate_on_empty_db():
|
|
# When there is no data available, use the start_rate.
|
|
eq_(CAD.value_in(USD, date(2008, 4, 20)), 1 / USD.latest_rate)
|
|
|
|
def test_physical_rates_db_remember_rates(tmpdir):
|
|
# When a rates db uses a real file, rates are remembered
|
|
dbpath = str(tmpdir.join('foo.db'))
|
|
db = RatesDB(dbpath)
|
|
db.set_CAD_value(date(2008, 4, 20), 'USD', 1/0.996115)
|
|
db = RatesDB(dbpath)
|
|
assert_almost_equal(db.get_rate(date(2008, 4, 20), 'CAD', 'USD'), 0.996115)
|
|
|
|
def test_db_with_connection():
|
|
# the supplied connection is used by the rates db.
|
|
con = sqlite.connect(':memory:')
|
|
db = RatesDB(con)
|
|
try:
|
|
con.execute("select * from rates where 1=2")
|
|
except sqlite.OperationalError: # new db
|
|
raise AssertionError()
|
|
|
|
def test_corrupt_db(tmpdir):
|
|
dbpath = str(tmpdir.join('foo.db'))
|
|
fh = io.open(dbpath, 'w')
|
|
fh.write('corrupted')
|
|
fh.close()
|
|
db = RatesDB(dbpath) # no crash. deletes the old file and start a new db
|
|
db.set_CAD_value(date(2008, 4, 20), 'USD', 42)
|
|
db = RatesDB(dbpath)
|
|
eq_(db.get_rate(date(2008, 4, 20), 'USD', 'CAD'), 42)
|
|
|
|
#--- Daily rate
|
|
def setup_daily_rate():
|
|
USD.set_CAD_value(1/0.996115, date(2008, 4, 20))
|
|
|
|
def test_get_rate_with_daily_rate():
|
|
# Getting the rate exactly as set_rate happened returns the same rate.
|
|
setup_daily_rate()
|
|
assert_almost_equal(CAD.value_in(USD, date(2008, 4, 20)), 0.996115)
|
|
|
|
def test_get_rate_different_currency():
|
|
# Use fallback rates when necessary.
|
|
setup_daily_rate()
|
|
eq_(CAD.value_in(EUR, date(2008, 4, 20)), 1 / EUR.latest_rate)
|
|
eq_(EUR.value_in(USD, date(2008, 4, 20)), EUR.latest_rate * 0.996115)
|
|
|
|
def test_get_rate_reverse():
|
|
# It's possible to get the reverse value of a rate using the same data.
|
|
setup_daily_rate()
|
|
assert_almost_equal(USD.value_in(CAD, date(2008, 4, 20)), 1 / 0.996115)
|
|
|
|
def test_set_rate_twice():
|
|
# When setting a rate for an index that already exists, the old rate is replaced by the new.
|
|
setup_daily_rate()
|
|
USD.set_CAD_value(1/42, date(2008, 4, 20))
|
|
assert_almost_equal(CAD.value_in(USD, date(2008, 4, 20)), 42)
|
|
|
|
def test_set_rate_after_get():
|
|
# When setting a rate after a get of the same rate, the rate cache is correctly updated.
|
|
setup_daily_rate()
|
|
CAD.value_in(USD, date(2008, 4, 20)) # value will be cached
|
|
USD.set_CAD_value(1/42, date(2008, 4, 20))
|
|
assert_almost_equal(CAD.value_in(USD, date(2008, 4, 20)), 42)
|
|
|
|
def test_set_rate_after_get_the_day_after():
|
|
# When setting a rate, the cache for the whole currency is reset, or else we get old fallback
|
|
# values for dates where the currency server returned no value.
|
|
setup_daily_rate()
|
|
CAD.value_in(USD, date(2008, 4, 21)) # value will be cached
|
|
USD.set_CAD_value(1/42, date(2008, 4, 20))
|
|
assert_almost_equal(CAD.value_in(USD, date(2008, 4, 21)), 42)
|
|
|
|
#--- Two daily rates
|
|
def setup_two_daily_rate():
|
|
# Don't change the set order, it's important for the tests
|
|
USD.set_CAD_value(1/0.997115, date(2008, 4, 25))
|
|
USD.set_CAD_value(1/0.996115, date(2008, 4, 20))
|
|
|
|
def test_date_range_range():
|
|
# USD.rates_date_range() returns the USD's limits.
|
|
setup_two_daily_rate()
|
|
eq_(USD.rates_date_range(), (date(2008, 4, 20), date(2008, 4, 25)))
|
|
|
|
def test_date_range_for_unfetched_currency():
|
|
# If the curency is not in the DB, return None.
|
|
setup_two_daily_rate()
|
|
assert PLN.rates_date_range() is None
|
|
|
|
def test_seek_rate_middle():
|
|
# A rate request with seek in the middle will return the lowest date.
|
|
setup_two_daily_rate()
|
|
eq_(USD.value_in(CAD, date(2008, 4, 24)), 1/0.996115)
|
|
|
|
def test_seek_rate_after():
|
|
# Make sure that the *nearest* lowest rate is returned. Because the 25th have been set
|
|
# before the 20th, an order by clause is required in the seek SQL to make this test pass.
|
|
setup_two_daily_rate()
|
|
eq_(USD.value_in(CAD, date(2008, 4, 26)), 1/0.997115)
|
|
|
|
def test_seek_rate_before():
|
|
# If there are no rate in the past, seek for a rate in the future.
|
|
setup_two_daily_rate()
|
|
eq_(USD.value_in(CAD, date(2008, 4, 19)), 1/0.996115)
|
|
|
|
#--- Rates of multiple currencies
|
|
def setup_rates_of_multiple_currencies():
|
|
USD.set_CAD_value(1/0.996115, date(2008, 4, 20))
|
|
EUR.set_CAD_value(1/0.633141, date(2008, 4, 20))
|
|
|
|
def test_get_rate_multiple_currencies():
|
|
# Don't mix currency rates up.
|
|
setup_rates_of_multiple_currencies()
|
|
assert_almost_equal(CAD.value_in(USD, date(2008, 4, 20)), 0.996115)
|
|
assert_almost_equal(CAD.value_in(EUR, date(2008, 4, 20)), 0.633141)
|
|
|
|
def test_get_rate_with_pivotal():
|
|
# It's possible to get a rate by using 2 records.
|
|
# if 1 CAD = 0.996115 USD and 1 CAD = 0.633141 then 0.996115 USD = 0.633141 then 1 USD = 0.633141 / 0.996115 EUR
|
|
setup_rates_of_multiple_currencies()
|
|
assert_almost_equal(USD.value_in(EUR, date(2008, 4, 20)), 0.633141 / 0.996115)
|
|
|
|
def test_get_rate_doesnt_exist():
|
|
# Don't crash when trying to do pivotal calculation with non-existing currencies.
|
|
setup_rates_of_multiple_currencies()
|
|
eq_(USD.value_in(PLN, date(2008, 4, 20)), 1 / 0.996115 / PLN.latest_rate)
|
|
|
|
#--- Problems after connection
|
|
def get_problematic_db():
|
|
class MockConnection(sqlite.Connection): # can't mock sqlite3.Connection's attribute, so we subclass it
|
|
mocking = False
|
|
def execute(self, *args, **kwargs):
|
|
if self.mocking:
|
|
raise sqlite.OperationalError()
|
|
else:
|
|
return sqlite.Connection.execute(self, *args, **kwargs)
|
|
|
|
con = MockConnection(':memory:')
|
|
db = RatesDB(con)
|
|
con.mocking = True
|
|
return db
|
|
|
|
def test_date_range_with_problematic_db():
|
|
db = get_problematic_db()
|
|
db.date_range('USD') # no crash
|
|
|
|
def test_get_rate_with_problematic_db():
|
|
db = get_problematic_db()
|
|
db.get_rate(date(2008, 4, 20), 'USD', 'CAD') # no crash
|
|
|
|
def test_set_rate_with_problematic_db():
|
|
db = get_problematic_db()
|
|
db.set_CAD_value(date(2008, 4, 20), 'USD', 42) # no crash
|
|
|
|
#--- DB that doesn't allow get_rate calls
|
|
def setup_db_raising_error_on_getrate():
|
|
db = RatesDB()
|
|
def mock_get_rate(*args, **kwargs):
|
|
raise AssertionError()
|
|
db.get_rate = mock_get_rate
|
|
Currency.set_rates_db(db)
|
|
|
|
def test_currency_with_start_date():
|
|
setup_db_raising_error_on_getrate()
|
|
eq_(FOO.value_in(CAD, date(2009, 1, 11)), 2)
|
|
|
|
def test_currency_with_stop_date():
|
|
setup_db_raising_error_on_getrate()
|
|
eq_(BAR.value_in(CAD, date(2010, 1, 13)), 2)
|