frankfurter/spec/blender_spec.rb

111 lines
3.7 KiB
Ruby
Raw Permalink Normal View History

2026-05-21 01:38:14 -06:00
# frozen_string_literal: true
require_relative "helper"
require "blender"
describe Blender do
let(:date) { Date.parse("2024-01-15") }
it "averages rates across providers" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
{ date: date, base: "EUR", quote: "GBP", rate: 0.84, provider: "ECB" },
{ date: date, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
{ date: date, base: "EUR", quote: "GBP", rate: 0.86, provider: "BOC" },
]
result = Blender.new(rates, base: "EUR").blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:rate]).must_be_close_to((1.08 + 1.10) / 2.0)
end
it "handles mixed bases within a provider" do
rates = [
{ date: date, base: "USD", quote: "JPY", rate: 150.0, provider: "FRED" },
{ date: date, base: "USD", quote: "CHF", rate: 0.88, provider: "FRED" },
{ date: date, base: "EUR", quote: "USD", rate: 1.10, provider: "FRED" },
]
result = Blender.new(rates, base: "USD").blend
jpy = result.find { |r| r[:quote] == "JPY" }
eur = result.find { |r| r[:quote] == "EUR" }
_(jpy[:rate]).must_be_close_to(150.0)
_(eur[:rate]).must_be_close_to(1.0 / 1.10)
end
it "blends rates consistently across providers with different bases" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
{ date: date, base: "USD", quote: "CAD", rate: 1.37, provider: "BOC" },
{ date: date, base: "EUR", quote: "CAD", rate: 1.48, provider: "BOC" },
]
result = Blender.new(rates, base: "EUR").blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:rate]).must_be_close_to(1.08, 0.05)
end
it "blends rates equally within the grace period" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
{ date: date - 1, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
]
result = Blender.new(rates, base: "EUR").blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:rate]).must_be_close_to((1.08 + 1.10) / 2.0)
_(usd[:date]).must_equal(date)
end
it "discounts stale rates beyond the grace period" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
{ date: date - 7, base: "EUR", quote: "USD", rate: 1.20, provider: "BOC" },
]
result = Blender.new(rates, base: "EUR").blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:rate]).must_be_close_to(1.08, 0.02)
_(usd[:date]).must_equal(date)
end
it "excludes outliers from the blend" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "A" },
{ date: date, base: "EUR", quote: "USD", rate: 1.09, provider: "B" },
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "C" },
{ date: date, base: "EUR", quote: "USD", rate: 9.99, provider: "D" },
]
blender = Blender.new(rates, base: "EUR")
result = blender.blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:rate]).must_be_close_to(1.083, 0.01)
end
it "exposes contributing providers and marks outliers as excluded" do
rates = [
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "A" },
{ date: date, base: "EUR", quote: "USD", rate: 1.09, provider: "B" },
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "C" },
{ date: date, base: "EUR", quote: "USD", rate: 9.99, provider: "D" },
]
result = Blender.new(rates, base: "EUR").blend
usd = result.find { |r| r[:quote] == "USD" }
_(usd[:providers]).must_equal([
{ key: "A", rate: 1.08 },
{ key: "B", rate: 1.09 },
{ key: "C", rate: 1.08 },
{ key: "D", rate: 9.99, excluded: true },
])
end
end