1import * as Boolean from "effect/Boolean"
2import { pipe } from "effect/Function"
3import assert from "node:assert/strict"
4import { describe, it } from "vitest"
5
6describe("Boolean", () => {
7 it("re-exports the global Boolean constructor", () => {
8 assert.strictEqual(Boolean.Boolean, globalThis.Boolean)
9 })
10
11 it("coerces values with Boolean semantics", () => {
12 assert.strictEqual(Boolean.Boolean(1), true)
13 assert.strictEqual(Boolean.Boolean(0), false)
14 assert.strictEqual(Boolean.Boolean(""), false)
15 assert.strictEqual(Boolean.Boolean("hello"), true)
16 assert.strictEqual(Boolean.Boolean(null), false)
17 assert.strictEqual(Boolean.Boolean(undefined), false)
18 })
19})
20
21describe("isBoolean", () => {
22 it("returns true for boolean values", () => {
23 assert.strictEqual(Boolean.isBoolean(true), true)
24 assert.strictEqual(Boolean.isBoolean(false), true)
25 })
26
27 it("returns false for non-boolean values", () => {
28 assert.strictEqual(Boolean.isBoolean(0), false)
29 assert.strictEqual(Boolean.isBoolean(1), false)
30 assert.strictEqual(Boolean.isBoolean("true"), false)
31 assert.strictEqual(Boolean.isBoolean(null), false)
32 assert.strictEqual(Boolean.isBoolean(undefined), false)
33 })
34})
35
36describe("match", () => {
37 const options = {
38 onFalse: () => "false" as const,
39 onTrue: () => "true" as const
40 }
41
42 it("calls onTrue when value is true (data-first)", () => {
43 assert.strictEqual(Boolean.match(true, options), "true")
44 })
45
46 it("calls onFalse when value is false (data-first)", () => {
47 assert.strictEqual(Boolean.match(false, options), "false")
48 })
49
50 it("works in data-last (pipeable) form", () => {
51 assert.strictEqual(pipe(true, Boolean.match(options)), "true")
52 assert.strictEqual(pipe(false, Boolean.match(options)), "false")
53 })
54})
55
56describe("Order", () => {
57 it("false < true", () => {
58 assert.strictEqual(Boolean.Order(false, true), -1)
59 })
60
61 it("true > false", () => {
62 assert.strictEqual(Boolean.Order(true, false), 1)
63 })
64
65 it("equal values return 0", () => {
66 assert.strictEqual(Boolean.Order(true, true), 0)
67 assert.strictEqual(Boolean.Order(false, false), 0)
68 })
69})
70
71describe("Equivalence", () => {
72 it("returns true for equal booleans", () => {
73 assert.strictEqual(Boolean.Equivalence(true, true), true)
74 assert.strictEqual(Boolean.Equivalence(false, false), true)
75 })
76
77 it("returns false for different booleans", () => {
78 assert.strictEqual(Boolean.Equivalence(true, false), false)
79 assert.strictEqual(Boolean.Equivalence(false, true), false)
80 })
81})
82
83describe("not", () => {
84 it("negates the value", () => {
85 assert.strictEqual(Boolean.not(true), false)
86 assert.strictEqual(Boolean.not(false), true)
87 })
88
89 it("is self-inverse", () => {
90 assert.strictEqual(Boolean.not(Boolean.not(true)), true)
91 assert.strictEqual(Boolean.not(Boolean.not(false)), false)
92 })
93})
94
95describe("and", () => {
96 it("truth table (data-first)", () => {
97 assert.strictEqual(Boolean.and(true, true), true)
98 assert.strictEqual(Boolean.and(true, false), false)
99 assert.strictEqual(Boolean.and(false, true), false)
100 assert.strictEqual(Boolean.and(false, false), false)
101 })
102
103 it("supports data-last form with the pipe value as the left operand", () => {
104 assert.strictEqual(pipe(true, Boolean.and(true)), true)
105 assert.strictEqual(pipe(true, Boolean.and(false)), false)
106 })
107})
108
109describe("nand", () => {
110 it("truth table (data-first)", () => {
111 assert.strictEqual(Boolean.nand(true, true), false)
112 assert.strictEqual(Boolean.nand(true, false), true)
113 assert.strictEqual(Boolean.nand(false, true), true)
114 assert.strictEqual(Boolean.nand(false, false), true)
115 })
116
117 it("supports data-last form with the pipe value as the left operand", () => {
118 assert.strictEqual(pipe(true, Boolean.nand(true)), false)
119 assert.strictEqual(pipe(false, Boolean.nand(false)), true)
120 })
121})
122
123describe("or", () => {
124 it("truth table (data-first)", () => {
125 assert.strictEqual(Boolean.or(true, true), true)
126 assert.strictEqual(Boolean.or(true, false), true)
127 assert.strictEqual(Boolean.or(false, true), true)
128 assert.strictEqual(Boolean.or(false, false), false)
129 })
130
131 it("supports data-last form with the pipe value as the left operand", () => {
132 assert.strictEqual(pipe(false, Boolean.or(true)), true)
133 assert.strictEqual(pipe(false, Boolean.or(false)), false)
134 })
135})
136
137describe("nor", () => {
138 it("truth table (data-first)", () => {
139 assert.strictEqual(Boolean.nor(true, true), false)
140 assert.strictEqual(Boolean.nor(true, false), false)
141 assert.strictEqual(Boolean.nor(false, true), false)
142 assert.strictEqual(Boolean.nor(false, false), true)
143 })
144
145 it("supports data-last form with the pipe value as the left operand", () => {
146 assert.strictEqual(pipe(true, Boolean.nor(true)), false)
147 assert.strictEqual(pipe(false, Boolean.nor(false)), true)
148 })
149})
150
151describe("xor", () => {
152 it("truth table (data-first)", () => {
153 assert.strictEqual(Boolean.xor(true, true), false)
154 assert.strictEqual(Boolean.xor(true, false), true)
155 assert.strictEqual(Boolean.xor(false, true), true)
156 assert.strictEqual(Boolean.xor(false, false), false)
157 })
158
159 it("supports data-last form with the pipe value as the left operand", () => {
160 assert.strictEqual(pipe(true, Boolean.xor(false)), true)
161 assert.strictEqual(pipe(false, Boolean.xor(false)), false)
162 })
163})
164
165describe("eqv", () => {
166 it("truth table (data-first)", () => {
167 assert.strictEqual(Boolean.eqv(true, true), true)
168 assert.strictEqual(Boolean.eqv(true, false), false)
169 assert.strictEqual(Boolean.eqv(false, true), false)
170 assert.strictEqual(Boolean.eqv(false, false), true)
171 })
172
173 it("supports data-last form with the pipe value as the left operand", () => {
174 assert.strictEqual(pipe(true, Boolean.eqv(true)), true)
175 assert.strictEqual(pipe(true, Boolean.eqv(false)), false)
176 })
177
178 it("is the negation of xor", () => {
179 for (const a of [true, false]) {
180 for (const b of [true, false]) {
181 assert.strictEqual(Boolean.eqv(a, b), !Boolean.xor(a, b))
182 }
183 }
184 })
185})
186
187describe("implies", () => {
188 it("truth table (data-first)", () => {
189 assert.strictEqual(Boolean.implies(true, true), true)
190 assert.strictEqual(Boolean.implies(true, false), false)
191 assert.strictEqual(Boolean.implies(false, true), true)
192 assert.strictEqual(Boolean.implies(false, false), true)
193 })
194
195 it("supports data-last form with the pipe value as the left operand", () => {
196 assert.strictEqual(pipe(true, Boolean.implies(false)), false)
197 assert.strictEqual(pipe(false, Boolean.implies(false)), true)
198 })
199})
200
201describe("every", () => {
202 it("returns true when all elements are true", () => {
203 assert.strictEqual(Boolean.every([true, true, true]), true)
204 })
205
206 it("returns false when any element is false", () => {
207 assert.strictEqual(Boolean.every([true, false, true]), false)
208 })
209
210 it("returns true for empty collection", () => {
211 assert.strictEqual(Boolean.every([]), true)
212 })
213
214 it("short-circuits on first false", () => {
215 const iterable: Iterable<boolean> = {
216 [Symbol.iterator]: function*() {
217 yield true
218 yield false
219 throw new Error("should not reach here")
220 }
221 }
222 assert.strictEqual(Boolean.every(iterable), false)
223 })
224})
225
226describe("some", () => {
227 it("returns true when any element is true", () => {
228 assert.strictEqual(Boolean.some([true, false, false]), true)
229 })
230
231 it("returns false when all elements are false", () => {
232 assert.strictEqual(Boolean.some([false, false, false]), false)
233 })
234
235 it("returns false for empty collection", () => {
236 assert.strictEqual(Boolean.some([]), false)
237 })
238
239 it("short-circuits on first true", () => {
240 const iterable: Iterable<boolean> = {
241 [Symbol.iterator]: function*() {
242 yield false
243 yield true
244 throw new Error("should not reach here")
245 }
246 }
247 assert.strictEqual(Boolean.some(iterable), true)
248 })
249})
250
251describe("ReducerAnd", () => {
252 it("initialValue is true (identity for AND)", () => {
253 assert.strictEqual(Boolean.ReducerAnd.initialValue, true)
254 })
255
256 it("truth table", () => {
257 assert.strictEqual(Boolean.ReducerAnd.combine(true, true), true)
258 assert.strictEqual(Boolean.ReducerAnd.combine(true, false), false)
259 assert.strictEqual(Boolean.ReducerAnd.combine(false, true), false)
260 assert.strictEqual(Boolean.ReducerAnd.combine(false, false), false)
261 })
262
263 it("initialValue acts as identity element", () => {
264 assert.strictEqual(Boolean.ReducerAnd.combine(Boolean.ReducerAnd.initialValue, true), true)
265 assert.strictEqual(Boolean.ReducerAnd.combine(Boolean.ReducerAnd.initialValue, false), false)
266 assert.strictEqual(Boolean.ReducerAnd.combine(true, Boolean.ReducerAnd.initialValue), true)
267 assert.strictEqual(Boolean.ReducerAnd.combine(false, Boolean.ReducerAnd.initialValue), false)
268 })
269})
270
271describe("ReducerOr", () => {
272 it("initialValue is false (identity for OR)", () => {
273 assert.strictEqual(Boolean.ReducerOr.initialValue, false)
274 })
275
276 it("truth table", () => {
277 assert.strictEqual(Boolean.ReducerOr.combine(true, true), true)
278 assert.strictEqual(Boolean.ReducerOr.combine(true, false), true)
279 assert.strictEqual(Boolean.ReducerOr.combine(false, true), true)
280 assert.strictEqual(Boolean.ReducerOr.combine(false, false), false)
281 })
282
283 it("initialValue acts as identity element", () => {
284 assert.strictEqual(Boolean.ReducerOr.combine(Boolean.ReducerOr.initialValue, true), true)
285 assert.strictEqual(Boolean.ReducerOr.combine(Boolean.ReducerOr.initialValue, false), false)
286 assert.strictEqual(Boolean.ReducerOr.combine(true, Boolean.ReducerOr.initialValue), true)
287 assert.strictEqual(Boolean.ReducerOr.combine(false, Boolean.ReducerOr.initialValue), false)
288 })
289})