1import { describe, it } from "@effect/vitest"
2import { Match, pipe } from "effect"
3import { strictEqual } from "./utils/assert.ts"
4
5describe("Match", () => {
6 it("fn keeps the selector arguments", () => {
7 type Todo = { readonly completed: boolean }
8 type Todos = Array<Todo>
9 type Filter = "All" | "Active" | "Completed"
10
11 const filterTodos = Match.fn((_todos: Todos, filter: Filter) => filter).pipe(
12 Match.withReturnType<Todos>(),
13 Match.when("All", (_filter, todos) => todos),
14 Match.when("Active", (_filter, todos) => todos.filter((todo) => !todo.completed)),
15 Match.when("Completed", (_filter, todos) => todos.filter((todo) => todo.completed)),
16 Match.exhaustive
17 )
18 const todos: Todos = [{ completed: false }, { completed: true }]
19
20 strictEqual(filterTodos(todos, "All"), todos)
21 strictEqual(filterTodos(todos, "Active").length, 1)
22 strictEqual(filterTodos(todos, "Active")[0], todos[0])
23 strictEqual(filterTodos(todos, "Completed").length, 1)
24 strictEqual(filterTodos(todos, "Completed")[0], todos[1])
25 })
26
27 it("fn can match a projected value", () => {
28 type Todo = { readonly status: "Active" | "Completed"; readonly title: string }
29 const formatTodo = Match.fn((todo: Todo) => todo.status).pipe(
30 Match.when("Active", (_status, todo) => `Active: ${todo.title}`),
31 Match.when("Completed", (_status, todo) => `Completed: ${todo.title}`),
32 Match.exhaustive
33 )
34
35 strictEqual(formatTodo({ status: "Active", title: "Write tests" }), "Active: Write tests")
36 })
37
38 it("tag matches an exact _tag and falls through for null", () => {
39 const match = pipe(
40 Match.type<{ _tag: "A" } | null>(),
41 Match.tag("A", () => "hit"),
42 Match.orElse(() => "miss")
43 )
44
45 strictEqual(match({ _tag: "A" }), "hit")
46 strictEqual(match(null), "miss")
47 })
48
49 it("tagStartsWith matches a _tag prefix and falls through otherwise", () => {
50 const match = pipe(
51 Match.type<{ _tag: "A.one" } | null>(),
52 Match.tagStartsWith("A", () => "hit"),
53 Match.orElse(() => "miss")
54 )
55
56 strictEqual(match({ _tag: "A.one" }), "hit")
57 strictEqual(match(null), "miss")
58 })
59
60 it("checks symbol-keyed object pattern properties", () => {
61 const key = Symbol("key")
62 const match = pipe(
63 Match.type<{ readonly [key]: "expected" | "other" }>(),
64 Match.when({ [key]: "expected" }, () => "hit"),
65 Match.orElse(() => "miss")
66 )
67
68 strictEqual(match({ [key]: "expected" }), "hit")
69 strictEqual(match({ [key]: "other" }), "miss")
70 strictEqual(match({} as any), "miss")
71 })
72})