Functional Weave
Code in Python

telecoms.roaming-charge@1.0.1

vectors.json

5,877 bytes · view raw

[
  {"name": "a week in France on a daily pass: only the daily fee is charged", "args": ["ILLUSTRATIVE", "FR", "2026-07-10", {"days": 7, "dataMb": 3000, "callOutMinutes": 60, "callInMinutes": 20, "smsOut": 15}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 1750, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 1750, "currency": "GBP"}}},
  {"name": "the same week a year earlier uses the older daily fee", "args": ["ILLUSTRATIVE", "FR", "2025-07-10", {"days": 7, "dataMb": 3000, "callOutMinutes": 60, "callInMinutes": 20, "smsOut": 15}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 1400, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 1400, "currency": "GBP"}}},
  {"name": "the last day of the old price", "args": ["ILLUSTRATIVE", "ES", "2025-12-31", {"days": 1, "dataMb": 10, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 200, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 200, "currency": "GBP"}}},
  {"name": "the first day of the new price", "args": ["ILLUSTRATIVE", "ES", "2026-01-01", {"days": 1, "dataMb": 10, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 250, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 250, "currency": "GBP"}}},
  {"name": "Norway is in the EEA, so in the European zone though not in the EU", "args": ["ILLUSTRATIVE", "NO", "2026-08-01", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 250, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 250, "currency": "GBP"}}},
  {"name": "pay as you go in the USA: data, calls both ways and texts", "args": ["ILLUSTRATIVE", "US", "2026-05-01", {"days": 5, "dataMb": 200, "callOutMinutes": 12, "callInMinutes": 30, "smsOut": 10}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "WORLD-1", "dailyFees": {"minor": 0, "currency": "GBP"}, "data": {"minor": 10000, "currency": "GBP"}, "calls": {"minor": 4800, "currency": "GBP"}, "sms": {"minor": 400, "currency": "GBP"}, "total": {"minor": 15200, "currency": "GBP"}}},
  {"name": "Japan is in the dearer zone", "args": ["ILLUSTRATIVE", "JP", "2026-05-01", {"days": 3, "dataMb": 50, "callOutMinutes": 3, "callInMinutes": 0, "smsOut": 2}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "WORLD-2", "dailyFees": {"minor": 0, "currency": "GBP"}, "data": {"minor": 15000, "currency": "GBP"}, "calls": {"minor": 750, "currency": "GBP"}, "sms": {"minor": 100, "currency": "GBP"}, "total": {"minor": 15850, "currency": "GBP"}}},
  {"name": "a phone taken abroad but not used costs nothing", "args": ["ILLUSTRATIVE", "US", "2026-05-01", {"days": 0, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "WORLD-1", "dailyFees": {"minor": 0, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 0, "currency": "GBP"}}},
  {"name": "no days of use in a daily-pass zone costs nothing", "args": ["ILLUSTRATIVE", "DE", "2026-05-01", {"days": 0, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expect": {"tariff": "ILLUSTRATIVE", "zone": "EUROPE", "dailyFees": {"minor": 0, "currency": "GBP"}, "data": {"minor": 0, "currency": "GBP"}, "calls": {"minor": 0, "currency": "GBP"}, "sms": {"minor": 0, "currency": "GBP"}, "total": {"minor": 0, "currency": "GBP"}}},
  {"name": "use in the home country is not roaming and has no zone", "args": ["ILLUSTRATIVE", "GB", "2026-07-10", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "no roaming zone for GB in tariff ILLUSTRATIVE on 2026-07-10"},
  {"name": "an unknown tariff has no zones", "args": ["ACME", "FR", "2026-07-10", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "no roaming zone for FR in tariff ACME"},
  {"name": "a date before the tariff's first row is an error", "args": ["ILLUSTRATIVE", "FR", "2023-06-01", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "no roaming zone for FR in tariff ILLUSTRATIVE on 2023-06-01"},
  {"name": "a lowercase country code is an error", "args": ["ILLUSTRATIVE", "fr", "2026-07-10", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "country must be an ISO 3166-1 alpha-2 code"},
  {"name": "an impossible date is an error", "args": ["ILLUSTRATIVE", "FR", "2026-02-30", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "is not a real calendar date"},
  {"name": "negative usage is an error", "args": ["ILLUSTRATIVE", "FR", "2026-07-10", {"days": 1, "dataMb": -5, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "usage must be whole numbers of 0 or more"},
  {"name": "a trailing newline is not part of a country code", "args": ["ILLUSTRATIVE", "FR\n", "2026-07-10", {"days": 1, "dataMb": 0, "callOutMinutes": 0, "callInMinutes": 0, "smsOut": 0}], "expectError": "country must be an ISO 3166-1 alpha-2 code"}
]