188 lines
5.9 KiB
Ruby
188 lines
5.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "helper"
|
|
require "rate"
|
|
require "carry_forward"
|
|
|
|
describe Rate do
|
|
describe CarryForward, ".apply" do
|
|
it "returns latest available rates on given date" do
|
|
date = Fixtures.latest_date
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
data = CarryForward.apply(rows, date:)
|
|
|
|
_(data.map { |r| r[:date] }.max).must_equal(date)
|
|
end
|
|
|
|
it "snaps to nearest prior date when requested date has no rates" do
|
|
sunday = Fixtures.recent_sunday
|
|
friday = Fixtures.preceding_friday(sunday)
|
|
rows = Rate.where(provider: "ECB", date: (sunday - 14)..sunday).naked.all
|
|
data = CarryForward.apply(rows, date: sunday)
|
|
|
|
_(data.map { |r| r[:date] }.uniq).must_equal([friday])
|
|
end
|
|
|
|
it "includes each provider's most recent date" do
|
|
date = Fixtures.latest_date
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
data = CarryForward.apply(rows, date:)
|
|
providers = data.map { |r| r[:provider] }.uniq.sort
|
|
|
|
_(providers).must_include("ECB")
|
|
_(providers).must_include("BOC")
|
|
end
|
|
|
|
it "excludes providers more than 14 days behind the target" do
|
|
date = Fixtures.latest_date
|
|
Rate.dataset.insert(date: date - 20, base: "EUR", quote: "XTS", rate: 1.08, provider: "STALE")
|
|
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
data = CarryForward.apply(rows, date:)
|
|
providers = data.map { |r| r[:provider] }.uniq
|
|
|
|
_(providers).must_include("ECB")
|
|
_(providers).wont_include("STALE")
|
|
end
|
|
|
|
it "includes providers within 14 days of the target" do
|
|
date = Fixtures.latest_date
|
|
Rate.dataset.insert(date: date - 10, base: "USD", quote: "XTS", rate: 0.92, provider: "FRED")
|
|
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
data = CarryForward.apply(rows, date:)
|
|
providers = data.map { |r| r[:provider] }.uniq
|
|
|
|
_(providers).must_include("ECB")
|
|
_(providers).must_include("FRED")
|
|
end
|
|
|
|
it "includes rates from different dates within the same provider" do
|
|
date = Fixtures.latest_date
|
|
older_date = date - 3
|
|
Rate.dataset.insert(date: older_date, base: "XTS", quote: "PLN", rate: 0.05, provider: "ECB")
|
|
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
data = CarryForward.apply(rows, date:)
|
|
quotes = data.select { |r| r[:provider] == "ECB" }.map { |r| r[:quote] }
|
|
|
|
_(quotes).must_include("PLN")
|
|
end
|
|
|
|
it "returns nothing if date predates dataset" do
|
|
date = Date.parse("1901-01-01")
|
|
rows = Rate.where(date: (date - 14)..date).naked.all
|
|
|
|
_(CarryForward.apply(rows, date:)).must_be_empty
|
|
end
|
|
|
|
it "returns latest rates when client date is ahead of server" do
|
|
future_date = Date.today + 1
|
|
rows = Rate.where(date: (future_date - 14)..future_date).naked.all
|
|
data = CarryForward.apply(rows, date: future_date)
|
|
|
|
_(data).wont_be_empty
|
|
|
|
today_rows = Rate.where(date: (Date.today - 14)..Date.today).naked.all
|
|
today_data = CarryForward.apply(today_rows, date: Date.today)
|
|
|
|
_(data.map { |r| r[:date] }.uniq.sort).must_equal(today_data.map { |r| r[:date] }.uniq.sort)
|
|
end
|
|
end
|
|
|
|
describe ".between" do
|
|
it "returns rates between given working dates" do
|
|
start_date = Fixtures.latest_date - 30
|
|
end_date = Fixtures.latest_date
|
|
dates = Rate.between(start_date..end_date).map(:date).sort.uniq
|
|
|
|
_(dates.first).must_be(:<=, start_date)
|
|
_(dates.last).must_equal(end_date)
|
|
end
|
|
|
|
it "starts on preceding business day if start date is a weekend" do
|
|
sunday = Fixtures.recent_sunday
|
|
monday = sunday + 1
|
|
friday = Fixtures.preceding_friday(sunday)
|
|
dates = Rate.between(sunday..monday).map(:date).uniq
|
|
|
|
_(dates).must_include(friday)
|
|
end
|
|
|
|
it "returns nothing if end date predates dataset" do
|
|
interval = (Date.parse("1901-01-01")..Date.parse("1901-01-31"))
|
|
|
|
_(Rate.between(interval)).must_be_empty
|
|
end
|
|
|
|
it "allows start date to predate dataset" do
|
|
start_date = Date.parse("1901-01-01")
|
|
end_date = Fixtures.latest_date
|
|
dates = Rate.between(start_date..end_date).map(:date)
|
|
|
|
_(dates).wont_be_empty
|
|
end
|
|
|
|
it "returns nothing when start date is in the future" do
|
|
start_date = Date.today + 1
|
|
end_date = start_date + 1
|
|
dates = Rate.between(start_date..end_date).map(:date)
|
|
|
|
_(dates).must_be_empty
|
|
end
|
|
end
|
|
|
|
describe ".only" do
|
|
it "returns only rate pairs involving the given currencies" do
|
|
currencies = ["CAD", "USD"]
|
|
date = Fixtures.latest_date
|
|
data = Rate.where(date: (date - 14)..date).only(*currencies).all
|
|
|
|
data.each do |r|
|
|
_([r.base, r.quote].any? { |c| currencies.include?(c) }).must_equal(true)
|
|
end
|
|
end
|
|
|
|
it "includes rates from providers where currency appears as base" do
|
|
date = Fixtures.latest_date
|
|
data = Rate.where(date: (date - 14)..date).only("USD", "EUR").all
|
|
providers = data.map(&:provider).uniq
|
|
|
|
_(providers).must_include("BOC")
|
|
end
|
|
|
|
it "includes providers whose rates span both sides of the pair" do
|
|
date = Fixtures.latest_date
|
|
data = Rate.where(date: (date - 14)..date).only("JPY", "EUR").all
|
|
providers = data.map(&:provider).uniq
|
|
|
|
_(providers).must_include("BOJ")
|
|
end
|
|
|
|
it "returns nothing if no matches" do
|
|
_(Rate.only("FOO").all).must_be_empty
|
|
end
|
|
end
|
|
|
|
describe ".downsample" do
|
|
let(:interval) { (Fixtures.latest_date - 366)..Fixtures.latest_date }
|
|
|
|
it "groups by week" do
|
|
dates = Rate.between(interval).downsample("week")
|
|
|
|
_(dates.map(:date).uniq.count).must_be(:<=, 55)
|
|
end
|
|
|
|
it "groups by month" do
|
|
dates = Rate.between(interval).downsample("month")
|
|
|
|
_(dates.map(:date).uniq.count).must_be(:<=, 14)
|
|
end
|
|
|
|
it "sorts by date" do
|
|
dates = Rate.between(interval).downsample("week").map(:date)
|
|
|
|
_(dates).must_equal(dates.sort)
|
|
end
|
|
end
|
|
end
|