Skip to content

Commit 67a26c5

Browse files
committed
feat: add positive and negative number constraints
1 parent dd8ddd3 commit 67a26c5

File tree

2 files changed

+82
-24
lines changed

2 files changed

+82
-24
lines changed

lib/vx/number.ex

+28
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,34 @@ defmodule Vx.Number do
6666
end)
6767
end
6868

69+
@doc """
70+
Requires the number to be positive.
71+
"""
72+
@spec positive(type) :: type when type: numeric
73+
def positive(type \\ t()) do
74+
constrain_num(type, :positive, fn value ->
75+
if value > 0 do
76+
:ok
77+
else
78+
{:error, "must be positive"}
79+
end
80+
end)
81+
end
82+
83+
@doc """
84+
Requires the number to be negative.
85+
"""
86+
@spec negative(type) :: type when type: numeric
87+
def negative(type \\ t()) do
88+
constrain_num(type, :negative, fn value ->
89+
if value < 0 do
90+
:ok
91+
else
92+
{:error, "must be negative"}
93+
end
94+
end)
95+
end
96+
6997
@doc """
7098
Requires the number to be greater than the given value.
7199
"""

test/vx/number_test.exs

+54-24
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ defmodule Vx.NumberTest do
55

66
describe "t/0" do
77
test "match" do
8-
assert :ok = Vx.validate(Vx.Number.t(), 123)
9-
assert :ok = Vx.validate(Vx.Number.t(), 123.0)
10-
assert :ok = Vx.validate(Vx.Number.t(), 123.4)
8+
assert :ok = Vx.validate!(Vx.Number.t(), 123)
9+
assert :ok = Vx.validate!(Vx.Number.t(), 123.0)
10+
assert :ok = Vx.validate!(Vx.Number.t(), 123.4)
1111
end
1212

1313
test "no match" do
@@ -20,7 +20,7 @@ defmodule Vx.NumberTest do
2020

2121
describe "lt/1" do
2222
test "match" do
23-
assert :ok = Vx.validate(Vx.Number.lt(100), 99)
23+
assert :ok = Vx.validate!(Vx.Number.lt(100), 99)
2424
end
2525

2626
test "no match" do
@@ -33,8 +33,8 @@ defmodule Vx.NumberTest do
3333

3434
describe "lteq/1" do
3535
test "match" do
36-
assert :ok = Vx.validate(Vx.Number.lteq(100), 100)
37-
assert :ok = Vx.validate(Vx.Number.lteq(100), 99)
36+
assert :ok = Vx.validate!(Vx.Number.lteq(100), 100)
37+
assert :ok = Vx.validate!(Vx.Number.lteq(100), 99)
3838
end
3939

4040
test "no match" do
@@ -45,7 +45,7 @@ defmodule Vx.NumberTest do
4545

4646
describe "gt/1" do
4747
test "match" do
48-
assert :ok = Vx.validate(Vx.Number.gt(100), 101)
48+
assert :ok = Vx.validate!(Vx.Number.gt(100), 101)
4949
end
5050

5151
test "no match" do
@@ -58,8 +58,8 @@ defmodule Vx.NumberTest do
5858

5959
describe "gteq/1" do
6060
test "match" do
61-
assert :ok = Vx.validate(Vx.Number.gteq(100), 100)
62-
assert :ok = Vx.validate(Vx.Number.gteq(100), 101)
61+
assert :ok = Vx.validate!(Vx.Number.gteq(100), 100)
62+
assert :ok = Vx.validate!(Vx.Number.gteq(100), 101)
6363
end
6464

6565
test "no match" do
@@ -70,10 +70,10 @@ defmodule Vx.NumberTest do
7070

7171
describe "range/1" do
7272
test "match" do
73-
assert :ok = Vx.validate(Vx.Number.range(1..10), 1)
74-
assert :ok = Vx.validate(Vx.Number.range(1..10), 5)
75-
assert :ok = Vx.validate(Vx.Number.range(1..10), 10)
76-
assert :ok = Vx.validate(Vx.Number.range(1..10//2), 3)
73+
assert :ok = Vx.validate!(Vx.Number.range(1..10), 1)
74+
assert :ok = Vx.validate!(Vx.Number.range(1..10), 5)
75+
assert :ok = Vx.validate!(Vx.Number.range(1..10), 10)
76+
assert :ok = Vx.validate!(Vx.Number.range(1..10//2), 3)
7777
end
7878

7979
test "no match" do
@@ -88,13 +88,13 @@ defmodule Vx.NumberTest do
8888

8989
describe "between/2" do
9090
test "match" do
91-
assert :ok = Vx.validate(Vx.Number.between(1, 10), 1)
92-
assert :ok = Vx.validate(Vx.Number.between(1, 10), 5)
93-
assert :ok = Vx.validate(Vx.Number.between(1, 10), 10)
94-
assert :ok = Vx.validate(Vx.Number.between(10, 1), 1)
95-
assert :ok = Vx.validate(Vx.Number.between(10, 1), 5)
96-
assert :ok = Vx.validate(Vx.Number.between(10, 1), 10)
97-
assert :ok = Vx.validate(Vx.Number.between(3, 3), 3)
91+
assert :ok = Vx.validate!(Vx.Number.between(1, 10), 1)
92+
assert :ok = Vx.validate!(Vx.Number.between(1, 10), 5)
93+
assert :ok = Vx.validate!(Vx.Number.between(1, 10), 10)
94+
assert :ok = Vx.validate!(Vx.Number.between(10, 1), 1)
95+
assert :ok = Vx.validate!(Vx.Number.between(10, 1), 5)
96+
assert :ok = Vx.validate!(Vx.Number.between(10, 1), 10)
97+
assert :ok = Vx.validate!(Vx.Number.between(3, 3), 3)
9898
end
9999

100100
test "no match" do
@@ -112,8 +112,8 @@ defmodule Vx.NumberTest do
112112

113113
describe "integer/0" do
114114
test "match" do
115-
assert :ok = Vx.validate(Vx.Number.integer(), 1)
116-
assert :ok = Vx.validate(Vx.Number.integer(), 1.0)
115+
assert :ok = Vx.validate!(Vx.Number.integer(), 1)
116+
assert :ok = Vx.validate!(Vx.Number.integer(), 1.0)
117117
end
118118

119119
test "no match" do
@@ -124,8 +124,8 @@ defmodule Vx.NumberTest do
124124

125125
describe "integer/1" do
126126
test "match" do
127-
assert :ok = Vx.validate(Vx.Integer.t() |> Vx.Number.integer(), 1)
128-
assert :ok = Vx.validate(Vx.Float.t() |> Vx.Number.integer(), 1.0)
127+
assert :ok = Vx.validate!(Vx.Integer.t() |> Vx.Number.integer(), 1)
128+
assert :ok = Vx.validate!(Vx.Float.t() |> Vx.Number.integer(), 1.0)
129129
end
130130

131131
test "no match" do
@@ -135,4 +135,34 @@ defmodule Vx.NumberTest do
135135
assert Exception.message(error) == "must be an integer"
136136
end
137137
end
138+
139+
describe "positive/1" do
140+
test "match" do
141+
assert :ok = Vx.validate!(Vx.Number.positive(), 1)
142+
assert :ok = Vx.validate!(Vx.Number.positive(), 0.1)
143+
end
144+
145+
test "no match" do
146+
assert {:error, error} = Vx.validate(Vx.Number.positive(), 0)
147+
assert Exception.message(error) == "must be positive"
148+
149+
assert {:error, _} = Vx.validate(Vx.Number.positive(), -1)
150+
assert {:error, _} = Vx.validate(Vx.Number.positive(), -0.1)
151+
end
152+
end
153+
154+
describe "negative/1" do
155+
test "match" do
156+
assert :ok = Vx.validate!(Vx.Number.negative(), -1)
157+
assert :ok = Vx.validate!(Vx.Number.negative(), -0.1)
158+
end
159+
160+
test "no match" do
161+
assert {:error, error} = Vx.validate(Vx.Number.negative(), 0)
162+
assert Exception.message(error) == "must be negative"
163+
164+
assert {:error, _} = Vx.validate(Vx.Number.negative(), 1)
165+
assert {:error, _} = Vx.validate(Vx.Number.negative(), 0.1)
166+
end
167+
end
138168
end

0 commit comments

Comments
 (0)