Runtime assertions for Ruby
literal.fun
ruby
1# frozen_string_literal: true
2
3extend Literal::Types
4
5class Color < Literal::Enum(Integer)
6 prop :hex, String
7
8 index :hex, String
9
10 index :lower_hex, String, unique: false do |color|
11 color.hex.downcase
12 end
13
14 Red = new(1, hex: "#FF0000")
15 Green = new(2, hex: "#00FF00")
16 Blue = new(3, hex: "#0000FF")
17 SPRING_GREEN = new(4, hex: "#00FF7F")
18
19 __after_defined__ if RUBY_ENGINE == "truffleruby"
20end
21
22class Switch < Literal::Enum(_Boolean)
23 On = new(true) do
24 def toggle = Off
25 end
26
27 Off = new(false) do
28 def toggle = On
29 end
30
31 __after_defined__ if RUBY_ENGINE == "truffleruby"
32end
33
34class SymbolTypedEnum < Literal::Enum(Symbol)
35 A = new(:B)
36 B = new(:A)
37end
38
39test ".coerce from value" do
40 assert_equal Color.coerce(1), Color::Red
41end
42
43test ".coerce from enum" do
44 assert_equal Color.coerce(Color::Red), Color::Red
45end
46
47test ".coerce from symbol" do
48 assert_equal Color.coerce(:Red), Color::Red
49end
50
51test ".coerce with invalid symbol raises an ArgumentError" do
52 assert_raises ArgumentError do
53 Color.coerce(:Invalid)
54 end
55end
56
57test ".coerce with invalid value raises an ArgumenError" do
58 assert_raises ArgumentError do
59 Color.coerce("invalid value")
60 end
61end
62
63test ".[] looks up the key by value" do
64 assert_equal Color[1], Color::Red
65end
66
67test ".[] returns nil if the member can't be found" do
68 assert_equal Color[10], nil
69end
70
71test ".cast looks up the key by value" do
72 assert_equal Color.cast(1), Color::Red
73end
74
75test ".cast returns nil if the member can't be found" do
76 assert_equal Color.cast(10), nil
77end
78
79test ".cast goes with the value when there are conflicts with the keys" do
80 assert_equal SymbolTypedEnum.coerce(:A), SymbolTypedEnum::B
81end
82
83test ".position_of with member" do
84 assert_equal Color.position_of(Color::Red), 0
85 assert_equal Color.position_of(Color::Green), 1
86 assert_equal Color.position_of(Color::Blue), 2
87end
88
89test ".position_of with name" do
90 assert_equal Color.position_of(:Red), 0
91 assert_equal Color.position_of(:Green), 1
92 assert_equal Color.position_of(:Blue), 2
93end
94
95test ".position_of with value" do
96 assert_equal Color.position_of(1), 0
97 assert_equal Color.position_of(2), 1
98 assert_equal Color.position_of(3), 2
99end
100
101test ".at_position" do
102 assert_equal Color.at_position(0), Color::Red
103 assert_equal Color.at_position(1), Color::Green
104 assert_equal Color.at_position(2), Color::Blue
105end
106
107test ".to_set" do
108 assert_equal Color.to_set, Set[
109 Color::Red,
110 Color::Green,
111 Color::Blue,
112 Color::SPRING_GREEN
113 ]
114end
115
116test ".to_h without block" do
117 assert_equal Color.to_h, {
118 Color::Red => 1,
119 Color::Green => 2,
120 Color::Blue => 3,
121 Color::SPRING_GREEN => 4,
122 }
123end
124
125test ".to_proc coerces" do
126 assert_equal [1, :Green, Color::Blue].map(&Color), [
127 Color::Red,
128 Color::Green,
129 Color::Blue,
130 ]
131end
132
133test ".to_s" do
134 assert_equal Color::Red.to_s, "Red"
135 assert_equal Color::SPRING_GREEN.to_s, "SPRING_GREEN"
136 assert_equal Switch::On.to_s, "On"
137 assert_equal SymbolTypedEnum::A.to_s, "A"
138end
139
140test ".to_sym" do
141 assert_equal Color::Red.to_sym, :Red
142 assert_equal Color::SPRING_GREEN.to_sym, :SPRING_GREEN
143 assert_equal Switch::On.to_sym, :On
144 assert_equal SymbolTypedEnum::A.to_sym, :A
145end
146
147test "#succ" do
148 assert_equal Color::Red.succ, Color::Green
149 assert_equal Color::Green.succ, Color::Blue
150 assert_equal Color::Blue.succ, Color::SPRING_GREEN
151 assert_equal Color::SPRING_GREEN.succ, nil
152end
153
154test "#pred" do
155 assert_equal Color::Red.pred, nil
156 assert_equal Color::Green.pred, Color::Red
157 assert_equal Color::Blue.pred, Color::Green
158end
159
160test "#<=>" do
161 assert_equal Color::Red <=> Color::Green, -1
162 assert_equal Color::Red <=> Color::Red, 0
163 assert_equal Color::Green <=> Color::Red, 1
164end
165
166test "#name" do
167 assert Color::Red.name.end_with?("Color::Red")
168end
169
170test "enums are rangeable" do
171 range = (Color::Red..Color::Green)
172
173 assert Range === range
174 assert_equal Color::Red, range.begin
175 assert_equal Color::Green, range.end
176end
177
178test "#where" do
179 assert_equal [Color::Red], Color.where(hex: "#FF0000")
180end
181
182test "#where raises Literal::TypeError when index value has the wrong type" do
183 assert_raises(Literal::TypeError) do
184 Color.where(hex: 123)
185 end
186end
187
188test "#find_by" do
189 assert_equal Color::Red, Color.find_by(hex: "#FF0000")
190end
191
192test "index definitions raise Literal::TypeError when index key type is wrong" do
193 klass = Class.new(Literal::Enum(Integer)) do
194 index :bad, String, &:value
195
196 A = new(1)
197 end
198
199 assert_raises(Literal::TypeError) do
200 klass.__after_defined__
201 end
202end
203
204test "#find_by raises when used with a non-unique index" do
205 error = assert_raises(ArgumentError) { Color.find_by(lower_hex: "#ff0000") }
206 assert_equal error.message, "You can only use `find_by` on unique indexes."
207end
208
209test "#value returns the value" do
210 assert_equal Color::Red.value, 1
211end
212
213test "reading property readers" do
214 assert_equal Color::Red.hex, "#FF0000"
215end
216
217test "generated predicates" do
218 assert_equal Color::Red.red?, true
219 assert_equal Color::Red.green?, false
220 assert_equal Color::Red.blue?, false
221 assert_equal Color::Red.spring_green?, false
222 assert_equal Color::SPRING_GREEN.spring_green?, true
223end
224
225test "members are frozen" do
226 assert Color::Red.frozen?
227end
228
229test "classes are frozen" do
230 assert Color.frozen?
231end
232
233test "singleton methods" do
234 assert_equal Switch::Off.toggle, Switch::On
235 assert_equal Switch::On.toggle, Switch::Off
236end
237
238test do
239 assert_equal([Color::Blue, Color::Green, Color::Red], [3, 2, 1].map(&Color))
240 assert_equal([Color::Red, Color::Green], [Color::Red, 2].map(&Color))
241end
242
243test "pattern matching" do
244 match { Color::Red => Color }
245 match { Color::Red => Color[1] }
246 match { Color::Red => Color[hex: "#FF0000"] }
247end