Repository: livebook-dev/kino (elixir)

Issue:
Kino.Input.utc_datetime uses DateTime.compare to compare NaiveDateTime values
_Found while working on #327, thanks to `ElixirLS Dialyzer`._

Turns out that passing any option to `Kino.Input.utc_datetime` will cause a `FunctionClauseError (no function clause matching in DateTime.compare/2)`.

Pull request description:
Fix Kino.Input.utc_datetime opts validation
The min, max and default options are all converted to a `NaiveDateTime`, so we cannot compare them using `DateTime`.

Fixes #335.

Patch:
diff --git a/lib/kino/input.ex b/lib/kino/input.ex
index f44789c..556cdd2 100644
--- a/lib/kino/input.ex
+++ b/lib/kino/input.ex
@@ -275,7 +275,7 @@ defmodule Kino.Input do
     max = Keyword.get(opts, :max, nil) |> truncate_datetime()
     default = Keyword.get(opts, :default, nil) |> truncate_datetime()
 
-    if min && max && DateTime.compare(min, max) == :gt do
+    if min && max && NaiveDateTime.compare(min, max) == :gt do
       raise ArgumentError,
             "expected :min to be less than :max, got: #{inspect(min)} and #{inspect(max)}"
     end
@@ -286,11 +286,11 @@ defmodule Kino.Input do
       &(is_struct(&1, NaiveDateTime) or &1 == nil)
     )
 
-    if min && default && DateTime.compare(default, min) == :lt do
+    if min && default && NaiveDateTime.compare(default, min) == :lt do
       raise ArgumentError, "expected :default to be bigger than :min, got: #{inspect(default)} "
     end
 
-    if max && default && DateTime.compare(default, max) == :gt do
+    if max && default && NaiveDateTime.compare(default, max) == :gt do
       raise ArgumentError, "expected :default to be smaller than :max, got: #{inspect(default)}"
     end
 


Test patch:
diff --git a/test/kino/input_test.exs b/test/kino/input_test.exs
index 7f7c28e..abd4f20 100644
--- a/test/kino/input_test.exs
+++ b/test/kino/input_test.exs
@@ -62,6 +62,35 @@ defmodule Kino.InputTest do
     end
   end
 
+  describe "utc_datetime/2" do
+    test "raises when :min is after :max" do
+      assert_raise ArgumentError, fn ->
+        Kino.Input.utc_datetime("Input",
+          min: ~U[2023-02-01 17:32:12Z],
+          max: ~U[2023-01-01 17:32:12Z]
+        )
+      end
+    end
+
+    test "raises when :default is before :min" do
+      assert_raise ArgumentError, fn ->
+        Kino.Input.utc_datetime("Input",
+          default: ~U[2023-01-01 17:32:12Z],
+          min: ~U[2023-02-01 17:32:12Z]
+        )
+      end
+    end
+
+    test "raises when :default is after :max" do
+      assert_raise ArgumentError, fn ->
+        Kino.Input.utc_datetime("Input",
+          default: ~U[2023-02-01 17:32:12Z],
+          max: ~U[2023-01-01 17:32:12Z]
+        )
+      end
+    end
+  end
+
   describe "file/2" do
     test "raises an error when :accept is an empty list" do
       assert_raise ArgumentError, "expected :accept to be a non-empty list, got: []", fn ->