A world-class math input for the web
1import { describe, expect, test } from "vitest";
2import {
3 AddNode,
4 DecimalNode,
5 DivideNode,
6 EquationNode,
7 ExponentNode,
8 FunctionCallNode,
9 MultiplyNode,
10 RadicalNode,
11 toText,
12 VariableNode,
13} from ".";
14
15test("Convert x to text", () => {
16 expect(toText(VariableNode.from("x"))).toStrictEqual("x");
17});
18
19test("Convert 3 to text", () => {
20 expect(toText(DecimalNode.from("3"))).toStrictEqual("3");
21});
22
23test("Convert x+2.5 to text", () => {
24 expect(
25 toText(AddNode.from([VariableNode.from("x"), DecimalNode.from("2.5")])),
26 ).toStrictEqual("x plus 2.5");
27});
28
29test("Convert a^2 + b^2 = c^2 to text", () => {
30 expect(
31 toText(
32 EquationNode.from([
33 AddNode.from([
34 ExponentNode.from(VariableNode.from("a"), DecimalNode.from("2")),
35 ExponentNode.from(VariableNode.from("b"), DecimalNode.from("2")),
36 ]),
37 ExponentNode.from(VariableNode.from("c"), DecimalNode.from("2")),
38 ]),
39 ),
40 ).toStrictEqual("a squared plus b squared equals c squared"); // TODO: Find a better output that pronounces 'a' as "aye" rather than "uh"
41});
42
43test("Convert sqrt(x+1) to text", () => {
44 expect(
45 toText(
46 RadicalNode.from(
47 AddNode.from([VariableNode.from("x"), DecimalNode.from("1")]),
48 ),
49 ),
50 ).toStrictEqual("square root of x plus 1");
51});
52
53test("Convert sqrt(x)+1 to text", () => {
54 expect(
55 toText(
56 AddNode.from([
57 RadicalNode.from(VariableNode.from("x")),
58 DecimalNode.from("1"),
59 ]),
60 ),
61 ).toStrictEqual("square root of x, plus 1");
62});
63
64test("Convert f(x+1)+1 to text", () => {
65 expect(
66 toText(
67 AddNode.from([
68 FunctionCallNode.from("f", [
69 AddNode.from([VariableNode.from("x"), DecimalNode.from("1")]),
70 ]),
71 DecimalNode.from("1"),
72 ]),
73 ),
74 ).toStrictEqual("f of x plus 1, plus 1");
75});
76
77test("Convert f(a)*b to text", () => {
78 expect(
79 toText(
80 MultiplyNode.from([
81 FunctionCallNode.from("f", [VariableNode.from("a")]),
82 VariableNode.from("b"),
83 ]),
84 ),
85 ).toStrictEqual("f of a, times b");
86});
87
88test("Convert (a+b)*c to text", () => {
89 expect(
90 toText(
91 MultiplyNode.from([
92 AddNode.from([VariableNode.from("a"), VariableNode.from("b")]),
93 VariableNode.from("c"),
94 ]),
95 ),
96 ).toStrictEqual("a plus b, times c");
97});
98
99describe("Convert fractions to text", () => {
100 const fracText = (num: string, den: string) => {
101 return toText(
102 DivideNode.from(DecimalNode.from(num), DecimalNode.from(den)),
103 );
104 };
105
106 test("0/0", () => void expect(fracText("0", "0")).toBe("0 over 0"));
107
108 test("0/1", () => void expect(fracText("0", "1")).toBe("0 over 1"));
109 test("1/1", () => void expect(fracText("1", "1")).toBe("1 over 1"));
110
111 test("0/2", () => void expect(fracText("0", "2")).toBe("0 halves"));
112 test("1/2", () => void expect(fracText("1", "2")).toBe("1 half"));
113 test("2/2", () => void expect(fracText("2", "2")).toBe("2 halves"));
114 test("0/3", () => void expect(fracText("0", "3")).toBe("0 thirds"));
115
116 test("1/3", () => void expect(fracText("1", "3")).toBe("1 third"));
117 test("2/3", () => void expect(fracText("2", "3")).toBe("2 thirds"));
118 test("3/3", () => void expect(fracText("3", "3")).toBe("3 thirds"));
119 test("4/3", () => void expect(fracText("4", "3")).toBe("4 thirds"));
120
121 test("1/4", () => void expect(fracText("1", "4")).toBe("1 fourth"));
122 test("2/4", () => void expect(fracText("2", "4")).toBe("2 fourths"));
123
124 test("1/5", () => void expect(fracText("1", "5")).toBe("1 fifth"));
125 test("2/5", () => void expect(fracText("2", "5")).toBe("2 fifths"));
126
127 test("1/6", () => void expect(fracText("1", "6")).toBe("1 sixth"));
128 test("2/6", () => void expect(fracText("2", "6")).toBe("2 sixths"));
129
130 test("1/7", () => void expect(fracText("1", "7")).toBe("1 seventh"));
131 test("2/7", () => void expect(fracText("2", "7")).toBe("2 sevenths"));
132
133 test("1/8", () => void expect(fracText("1", "8")).toBe("1 eighth"));
134 test("2/8", () => void expect(fracText("2", "8")).toBe("2 eighths"));
135
136 test("1/9", () => void expect(fracText("1", "9")).toBe("1 ninth"));
137 test("2/9", () => void expect(fracText("2", "9")).toBe("2 ninths"));
138
139 test("1/10", () => void expect(fracText("1", "10")).toBe("1 tenth"));
140 test("2/10", () => void expect(fracText("2", "10")).toBe("2 tenths"));
141
142 test("1/11", () => void expect(fracText("1", "11")).toBe("1 eleventh"));
143 test("2/11", () => void expect(fracText("2", "11")).toBe("2 elevenths"));
144
145 test("1/12", () => void expect(fracText("1", "12")).toBe("1 twelfth"));
146 test("2/12", () => void expect(fracText("2", "12")).toBe("2 twelfths"));
147});