Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spect can't handle negative Decimals #19

Open
23Skidoo opened this issue Feb 16, 2022 · 2 comments · May be fixed by #20
Open

Spect can't handle negative Decimals #19

23Skidoo opened this issue Feb 16, 2022 · 2 comments · May be fixed by #20

Comments

@23Skidoo
Copy link

Using the decimal-2.0.0 package:

iex(20)> Spect.to_spec(Decimal.new("1.23"), Decimal)       
{:ok, #Decimal<1.23>}

iex(21)> Spect.to_spec(Decimal.new("-1.23"), Decimal)
{:error,
 %Spect.ConvertError{
   message: "expected: union of [{:integer, 0, 1}, {:op, 74, :-, {:integer, 74, 1}}], found: -1"
 }}

My guess is that it's due to sign() in decimal-2.0.0 being defined as

@type sign :: 1 | -1

which seems to be an invalid typespec.

@23Skidoo
Copy link
Author

The following type definition works as expected, however:

defmodule MyDecimal do
  import TypedStruct

  @type sign() :: 1 | 2 | 3

  typedstruct do
    field :sign, sign()
    field :num, integer()
  end
end

[...]

iex(3)> Spect.to_spec(%MyDecimal{sign: 1, num: 2}, MyDecimal)
{:ok, %MyDecimal{num: 2, sign: 1}}
iex(4)> Spect.to_spec(%MyDecimal{sign: 2, num: 2}, MyDecimal)
{:ok, %MyDecimal{num: 2, sign: 2}}
iex(5)> Spect.to_spec(%MyDecimal{sign: 3, num: 2}, MyDecimal)
{:ok, %MyDecimal{num: 2, sign: 3}}

@wojtekmach
Copy link

The problem is spect doesn't currently support negative integer literals. I haven't tested this thoroughly but here's an attempt at a patch:

diff --git a/lib/spect.ex b/lib/spect.ex
index d54a774..921aec8 100644
--- a/lib/spect.ex
+++ b/lib/spect.ex
@@ -156,6 +156,10 @@ defmodule Spect do
     to_kind!(data, module, type, params)
   end
 
+  defp to_kind!(data, _module, {:op, _, :-, {:integer, _, value}}, _params) do
+    to_lit!(data, :integer, -value)
+  end
+
   defp to_kind!(data, _module, {kind, _line, value}, _params) do
     to_lit!(data, kind, value)
   end
diff --git a/test/spect_test.exs b/test/spect_test.exs
index 4ea4407..dbaf09f 100644
--- a/test/spect_test.exs
+++ b/test/spect_test.exs
@@ -36,6 +36,9 @@ defmodule Spect.Test do
     assert to_spec(1, Specs, :literal_1) === {:ok, 1}
     {:error, %ConvertError{}} = to_spec(2, Specs, :literal_1)
 
+    assert to_spec(-1, Specs, :literal_minus_1) === {:ok, -1}
+    {:error, %ConvertError{}} = to_spec(-2, Specs, :literal_minus_1)
+
     assert to_spec([], Specs, :literal_list) === {:ok, []}
     {:error, %ConvertError{}} = to_spec(1, Specs, :literal_list)
 
diff --git a/test/support/specs.ex b/test/support/specs.ex
index 1ee4b03..f45ca62 100644
--- a/test/support/specs.ex
+++ b/test/support/specs.ex
@@ -6,6 +6,7 @@ defmodule Spect.Support.Specs do
   @type literal_true :: true
   @type literal_false :: false
   @type literal_1 :: 1
+  @type literal_minus_1 :: -1
   @type literal_list :: []
   @type literal_map :: %{}
 

feel free to go with it if you want!

@23Skidoo 23Skidoo linked a pull request Feb 16, 2022 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants