👁️
1import { describe, expect, it } from "vitest";
2import {
3 getDeckNameWords,
4 getSingularForms,
5 isNonCreatureLand,
6 textMatchesDeckTitle,
7} from "./deck-preview-utils";
8
9describe("getSingularForms", () => {
10 describe("irregular plurals", () => {
11 it.each([
12 ["geese", ["geese", "goose"]],
13 ["teeth", ["teeth", "tooth"]],
14 ["feet", ["feet", "foot"]],
15 ["men", ["men", "man"]],
16 ["mice", ["mice", "mouse"]],
17 ["children", ["children", "child"]],
18 ["oxen", ["oxen", "ox"]],
19 ["people", ["people", "person"]],
20 ])("%s -> %j", (input, expected) => {
21 expect(getSingularForms(input)).toEqual(expected);
22 });
23 });
24
25 describe("typal deck names", () => {
26 it.each([
27 // -s plurals (most common)
28 ["goblins", ["goblins", "goblin"]],
29 ["spirits", ["spirits", "spirit"]],
30 ["humans", ["humans", "human"]],
31 ["wizards", ["wizards", "wizard"]],
32 ["knights", ["knights", "knight"]],
33 ["angels", ["angels", "angel"]],
34 ["dragons", ["dragons", "dragon"]],
35 ["slivers", ["slivers", "sliver"]],
36 ["rogues", ["rogues", "rogue"]],
37 ["warriors", ["warriors", "warrior"]],
38 ["clerics", ["clerics", "cleric"]],
39 ["shamans", ["shamans", "shaman"]],
40 ["soldiers", ["soldiers", "soldier"]],
41 ["bogles", ["bogles", "bogle"]],
42 ["vampires", ["vampires", "vampire"]],
43 ["horses", ["horses", "horse"]],
44 // -ves -> -f and -fe plurals
45 ["elves", ["elves", "elf", "elfe"]],
46 ["wolves", ["wolves", "wolf", "wolfe"]],
47 ["werewolves", ["werewolves", "werewolf", "werewolfe"]],
48 ["knives", ["knives", "knif", "knife"]],
49 // -ies plurals (both -y and -ie forms)
50 ["zombies", ["zombies", "zomby", "zombie"]],
51 ["faeries", ["faeries", "faery", "faerie"]],
52 ["pixies", ["pixies", "pixy", "pixie"]],
53 ["allies", ["allies", "ally", "allie"]],
54 // -xes/-ches/-shes/-sses/-zzes plurals (strip -es)
55 ["boxes", ["boxes", "box"]],
56 ["matches", ["matches", "match"]],
57 ["dishes", ["dishes", "dish"]],
58 ["passes", ["passes", "pass"]],
59 ["buzzes", ["buzzes", "buzz"]],
60 // Words that don't need singularization
61 ["merfolk", ["merfolk"]],
62 ["equipment", ["equipment"]],
63 // Words ending in -ss (not plurals)
64 ["prowess", ["prowess"]],
65 ["boss", ["boss"]],
66 ["moss", ["moss"]],
67 ])("%s -> %j", (input, expected) => {
68 expect(getSingularForms(input)).toEqual(expected);
69 });
70 });
71
72 describe("edge cases", () => {
73 it.each([
74 ["as", ["as", "a"]],
75 ["is", ["is", "i"]],
76 ["s", ["s"]],
77 ["es", ["es", "e"]],
78 ["ves", ["ves", "ve"]],
79 ["ies", ["ies", "ie"]],
80 ])("%s -> %j", (input, expected) => {
81 expect(getSingularForms(input)).toEqual(expected);
82 });
83 });
84});
85
86describe("getDeckNameWords", () => {
87 it.each([
88 ["Selesnya Elves", ["selesnya", "elves", "elf", "elfe"]],
89 ["Mono-Green Elves", ["mono-green", "elves", "elf", "elfe"]],
90 ["Bant Spirits", ["bant", "spirits", "spirit"]],
91 ["Selesnya Bogles", ["selesnya", "bogles", "bogle"]],
92 ["Simic Merfolk", ["simic", "merfolk"]],
93 ["Azorius Faeries", ["azorius", "azoriu", "faeries", "faery", "faerie"]],
94 ["GOBLINS", ["goblins", "goblin"]],
95 ])("%s -> %j", (input, expected) => {
96 expect(getDeckNameWords(input)).toEqual(expected);
97 });
98
99 it("filters words shorter than 3 chars", () => {
100 const words = getDeckNameWords("UW Spirits");
101 expect(words).not.toContain("uw");
102 expect(words).toContain("spirits");
103 });
104});
105
106describe("textMatchesDeckTitle", () => {
107 it.each([
108 ["Slippery Bogle", "Selesnya Bogles", true],
109 ["Gladecover Scout", "Selesnya Bogles", false],
110 ["Llanowar Elves", "Mono-Green Elves", true],
111 ["Heritage Druid", "Mono-Green Elves", false],
112 ["Whenever another Elf enters...", "Mono-Green Elves", true],
113 ["GOBLIN GUIDE", "goblins", true],
114 ["Gilded Goose", "Food Geese", true],
115 ["Tireless Tracker", "Food Geese", false],
116 ["Cheeky House-Mouse", "Boros Mice", true],
117 ["Manifold Mouse", "Boros Mice", true],
118 ])("'%s' matches deck '%s' -> %s", (text, deckName, expected) => {
119 const deckWords = getDeckNameWords(deckName);
120 expect(textMatchesDeckTitle(text, deckWords)).toBe(expected);
121 });
122
123 it("handles empty/undefined inputs", () => {
124 const deckWords = getDeckNameWords("Elves");
125 expect(textMatchesDeckTitle(undefined, deckWords)).toBe(false);
126 expect(textMatchesDeckTitle("", deckWords)).toBe(false);
127 expect(textMatchesDeckTitle("Llanowar Elves", [])).toBe(false);
128 });
129});
130
131describe("isNonCreatureLand", () => {
132 it.each([
133 ["Basic Land — Forest", true],
134 ["Basic Land — Island", true],
135 ["Land", true],
136 ["Land — Gate", true],
137 ["Legendary Land", true],
138 ["Land Creature — Elemental", false],
139 ["Creature Land", false],
140 ["Creature — Elf", false],
141 ["Instant", false],
142 ["Enchantment", false],
143 [undefined, false],
144 ])("isNonCreatureLand(%j) -> %s", (input, expected) => {
145 expect(isNonCreatureLand(input)).toBe(expected);
146 });
147});