From c2ea89eb3236c0338672f1cf0862bf97c2a2b002 Mon Sep 17 00:00:00 2001 From: Kip Cole Date: Sat, 3 Aug 2024 09:53:27 +0930 Subject: [PATCH] Improve error messages when options may be malformed --- .tool-versions | 2 -- lib/cldr/date.ex | 9 +++++++-- lib/cldr/date_time.ex | 4 ++++ lib/cldr/time.ex | 9 +++++++-- mix.lock | 10 +++++----- test/cldr_dates_times_test.exs | 22 ++++++++++++++++++++-- 6 files changed, 43 insertions(+), 13 deletions(-) delete mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 229bbe0..0000000 --- a/.tool-versions +++ /dev/null @@ -1,2 +0,0 @@ -elixir 1.16.2-otp-26 -erlang 26.2.2 diff --git a/lib/cldr/date.ex b/lib/cldr/date.ex index c41aaa3..07b343d 100644 --- a/lib/cldr/date.ex +++ b/lib/cldr/date.ex @@ -20,7 +20,7 @@ defmodule Cldr.Date do alias Cldr.Locale import Cldr.DateTime, - only: [resolve_plural_format: 4, apply_preference: 2] + only: [resolve_plural_format: 4, apply_preference: 2, has_date: 1] @typep options :: Keyword.t() | map() @@ -164,7 +164,8 @@ defmodule Cldr.Date do to_string(date, backend, options) end - def to_string(%{} = date, backend, options) do + def to_string(%{} = date, backend, options) + when is_atom(backend) and has_date(date) do options = normalize_options(date, backend, options) format_backend = Module.concat(backend, DateTime.Formatter) @@ -189,6 +190,10 @@ defmodule Cldr.Date do {:error, {e.__struct__, e.message}} end + def to_string(date, value, []) when is_map(date) do + {:error, {ArgumentError, "Unexpected option value #{inspect value}. Options must be a keyword list"}} + end + def to_string(date, _backend, _options) do error_return(date, [:year, :month, :day, :calendar]) end diff --git a/lib/cldr/date_time.ex b/lib/cldr/date_time.ex index 532130e..b35ba78 100644 --- a/lib/cldr/date_time.ex +++ b/lib/cldr/date_time.ex @@ -257,6 +257,10 @@ defmodule Cldr.DateTime do Cldr.Time.to_string(datetime, backend, options) end + def to_string(datetime, value, []) when is_map(datetime) do + {:error, {ArgumentError, "Unexpected option value #{inspect value}. Options must be a keyword list"}} + end + def to_string(datetime, _backend, _options) do error_return(datetime, [:year, :month, :day, :hour, :minute, :second, :calendar]) end diff --git a/lib/cldr/time.ex b/lib/cldr/time.ex index c6b2523..10ab60a 100644 --- a/lib/cldr/time.ex +++ b/lib/cldr/time.ex @@ -22,7 +22,7 @@ defmodule Cldr.Time do alias Cldr.Locale import Cldr.DateTime, - only: [resolve_plural_format: 4, apply_preference: 2] + only: [resolve_plural_format: 4, apply_preference: 2, has_time: 1] @typep options :: Keyword.t() | map() @@ -169,7 +169,8 @@ defmodule Cldr.Time do to_string(time, backend, options) end - def to_string(%{} = time, backend, options) do + def to_string(%{} = time, backend, options) + when is_atom(backend) and has_time(time) do options = normalize_options(time, backend, options) format_backend = Module.concat(backend, DateTime.Formatter) @@ -194,6 +195,10 @@ defmodule Cldr.Time do {:error, {e.__struct__, e.message}} end + def to_string(time, value, []) when is_map(time) do + {:error, {ArgumentError, "Unexpected option value #{inspect value}. Options must be a keyword list"}} + end + def to_string(time, _backend, _options) do error_return(time, [:hour, :minute, :second]) end diff --git a/mix.lock b/mix.lock index a1af044..7774039 100644 --- a/mix.lock +++ b/mix.lock @@ -11,11 +11,11 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ex_cldr": {:hex, :ex_cldr, "2.40.0", "624717778dbf0a8cd307f1576eabbd44470c16190172abf293fed24150440a5a", [:mix], [{:cldr_utils, "~> 2.28", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "113394b6dd23aaf7912da583aab103d9cf082b9821bc4a6e287543a895af7cb4"}, - "ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.26.0", "855721dedb3c1eddcb6ad219257b8896e8c4993ef1db65a4f281f119c7235ab1", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.16", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9160acc0573ae72d0af91b58b7130c5058609acd3904224425bcb94d57bf9264"}, - "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.16.1", "29317f533cb5ec046d04523256cca4090291e9157028f28731395149b06ff8b2", [:mix], [{:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "095d5e973bf0ee066dd1153990d10cb6fa6d8ff0e028295bdce7a7821c70a0e4"}, + "ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.26.0", "d832996d30360ad68475b57da02ce1adbc5609459d89b779f9148f34cce09469", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.16", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6ace2824ae10c3f456714f031a5de168da05253baf9119582c87b2daa823af46"}, + "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.16.2", "670d96cc4fb18cfebd82488ed687742683be2d0725d66ec051578d4b13539aa8", [:mix], [{:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "2ccfac2838f4df8c8e5424dbc68eb2f3ac9eeb45e10365050901f7ac7a914ce1"}, "ex_cldr_lists": {:hex, :ex_cldr_lists, "2.11.0", "1d39e75f0e493ccc95adfc85c55b4ca34f0771626350ce326d9ab8813d91444e", [:mix], [{:ex_cldr_numbers, "~> 2.25", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "8132b30a5506ae8a09e5c9a21c23fd60c8837ce6c3a1de9966d813eb78951695"}, - "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.33.1", "49dc6e77e6d9ad22660aaa2480a7408ad3aedfbe517e4e83e5fe3a7bf5345770", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.16", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "c003bfaa3fdee6bab5195f128b94038c2ce1cf4879a759eef431dd075d9a5dac"}, - "ex_cldr_units": {:hex, :ex_cldr_units, "3.17.0", "f26dcde31a8fbb7808afa106ce2c7cbf38e0e0e0678ac523e795cdfdc67ab502", [:mix], [{:cldr_utils, "~> 2.25", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.33.0", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "b9f09c420f5e3b86ed41f135751086bc59bf2bb8e633516e8d3e9f24d6d9e777"}, + "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.33.2", "c5587a8d84214d9cc42e7827e4c3bed2aa9e52505a55b10540020725954ded2c", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.16", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "49f1dbaddc1ad6e3f496a97fa425d25b3ae89e8178ce0416d9909deaf2e5ad80"}, + "ex_cldr_units": {:hex, :ex_cldr_units, "3.17.1", "f03c7a138113511af903d0d2205b5cc01df1e599c28839ca2e1e78b7ca0bf2a2", [:mix], [{:cldr_utils, "~> 2.25", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.33.0", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "7de1bf7ff7599cf4da9dd0f1a7b6e19ca8db83b883301f5dcd0f565aa5eaec8c"}, "ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"}, "exprintf": {:hex, :exprintf, "0.2.1", "b7e895dfb00520cfb7fc1671303b63b37dc3897c59be7cbf1ae62f766a8a0314", [:mix], [], "hexpm", "20a0e8c880be90e56a77fcc82533c5d60c643915c7ce0cc8aa1e06ed6001da28"}, "exprof": {:hex, :exprof, "0.2.4", "13ddc0575a6d24b52e7c6809d2a46e9ad63a4dd179628698cdbb6c1f6e497c98", [:mix], [{:exprintf, "~> 0.2", [hex: :exprintf, repo: "hexpm", optional: false]}], "hexpm", "0884bcb66afc421c75d749156acbb99034cc7db6d3b116c32e36f32551106957"}, @@ -27,5 +27,5 @@ "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, "ratio": {:hex, :ratio, "2.4.2", "c8518f3536d49b1b00d88dd20d49f8b11abb7819638093314a6348139f14f9f9", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "441ef6f73172a3503de65ccf1769030997b0d533b1039422f1e5e0e0b4cbf89e"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "tz": {:hex, :tz, "0.26.6", "4d46178dd5bc4d2c1e78c9affcc3fd46764e29cd2a148c06666edb83cb18629f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "9ca97ea48b412f2404740867f6c321ee8ce112602035bb79b0b90c9c03174652"}, + "tz": {:hex, :tz, "0.27.1", "d8091d0c2d4f590e010c94830c3d842f548b4872a5b92028d74f0d0a3887aebe", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "215c9120dab5b7f7db4c93e91085c290b2efe478e147d84285a6583fd220727f"}, } diff --git a/test/cldr_dates_times_test.exs b/test/cldr_dates_times_test.exs index 77c17f2..920258e 100644 --- a/test/cldr_dates_times_test.exs +++ b/test/cldr_dates_times_test.exs @@ -87,8 +87,12 @@ defmodule Cldr.DatesTimes.Test do assert {:ok, "10:48 AM"} = Cldr.Time.to_string(~T[10:48:00], format: :hmj) assert {:ok, "10:48 AM"} = Cldr.Time.to_string(~T[10:48:00], format: :hmJ) - assert Cldr.Date.to_string(~T[10:48:00], format: :hmc) == - {:error, {Cldr.DateTime.UnresolvedFormat, "No available format resolved for :hmc"}} + assert Cldr.Date.to_string(~T"10:48:00", format: :hmc) == + {:error, + { + ArgumentError, + "Missing required date fields. The function requires a map with at least :year, :month, :day and :calendar. " <> + "Found: ~T[10:48:00 Cldr.Calendar.Gregorian]"}} assert Cldr.Time.to_string(~T[10:48:00], format: :hme) == {:error, {Cldr.DateTime.UnresolvedFormat, "No available format resolved for :hme"}} @@ -163,4 +167,18 @@ defmodule Cldr.DatesTimes.Test do assert {:ok, _} = Cldr.Time.available_formats() assert {:ok, _} = Cldr.DateTime.available_formats() end + + test "When to_string options is not a list" do + assert {:error, + {ArgumentError, + "Unexpected option value \"en-GB\". Options must be a keyword list"}} = Cldr.DateTime.to_string DateTime.utc_now(), "en-GB" + + assert {:error, + {ArgumentError, + "Unexpected option value \"en-GB\". Options must be a keyword list"}} = Cldr.Date.to_string Date.utc_today(), "en-GB" + + assert {:error, + {ArgumentError, + "Unexpected option value \"en-GB\". Options must be a keyword list"}} = Cldr.Time.to_string Time.utc_now(), "en-GB" + end end