Skip to content

Commit e4828ca

Browse files
authored
Merge pull request #177 from opanel-mc/test/build-test-framework
Add test framework
2 parents 934dac6 + df469cf commit e4828ca

File tree

8 files changed

+3061
-653
lines changed

8 files changed

+3061
-653
lines changed

.github/workflows/build.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ jobs:
2828
cache: 'npm'
2929
cache-dependency-path: ./frontend/package-lock.json
3030
- run: npm i
31+
- run: npm run prelaunch
32+
33+
- name: Run lint
34+
run: npm run lint
3135

32-
- name: Test building frontend
33-
run: npm run build
36+
- name: Run unit tests
37+
run: npm run test
3438

3539
jar:
3640

frontend/lib/tests/utils.test.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { describe, expect, it } from "vitest";
2+
import { NbtBool, NbtList, NbtObject, NbtString } from "snbt-js";
3+
import { base64ToString, formatDataSize, gameModeToString, getCurrentArgumentIndex, getInputtedArgumentStr, isNumeric, stringToBase64, textComponentToString } from "../utils";
4+
import { GameMode } from "../types";
5+
6+
describe("test gameModeToString", () => {
7+
it("should return the correct string for each game mode", () => {
8+
expect(gameModeToString(GameMode.SURVIVAL)).toBe("[common.gamemode.survival]");
9+
expect(gameModeToString(GameMode.CREATIVE)).toBe("[common.gamemode.creative]");
10+
expect(gameModeToString(GameMode.ADVENTURE)).toBe("[common.gamemode.adventure]");
11+
expect(gameModeToString(GameMode.SPECTATOR)).toBe("[common.gamemode.spectator]");
12+
});
13+
});
14+
15+
describe("test getInputtedArgumentStr", () => {
16+
it("should return the inputted argument string based on cursor position", () => {
17+
expect(getInputtedArgumentStr("do hello world", 5)).toBe("he");
18+
expect(getInputtedArgumentStr("do hello world", 13)).toBe("worl");
19+
});
20+
21+
it("should return empty string when the cursor is at 0", () => {
22+
expect(getInputtedArgumentStr("do hello world", 0)).toBe("");
23+
});
24+
25+
it("should throw error if the given cursor position is out of the string length", () => {
26+
expect(() => getInputtedArgumentStr("do hello world", -1)).toThrowError("Cursor position is out of the length of the string.");
27+
expect(() => getInputtedArgumentStr("do hello world", 15)).toThrowError("Cursor position is out of the length of the string.");
28+
});
29+
});
30+
31+
describe("test getCurrentArgumentIndex", () => {
32+
it("should return the current argument index based on cursor position", () => {
33+
expect(getCurrentArgumentIndex("do hello world", 5)).toBe(2);
34+
expect(getCurrentArgumentIndex("do hello world", 13)).toBe(3);
35+
});
36+
37+
it("should return 1 when the cursor is at 0", () => {
38+
expect(getCurrentArgumentIndex("do hello world", 0)).toBe(1);
39+
});
40+
41+
it("should throw error if the given cursor position is out of the string length", () => {
42+
expect(() => getCurrentArgumentIndex("do hello world", -1)).toThrowError("Cursor position is out of the length of the string.");
43+
expect(() => getCurrentArgumentIndex("do hello world", 15)).toThrowError("Cursor position is out of the length of the string.");
44+
});
45+
});
46+
47+
describe("test formatDataSize", () => {
48+
it("should format data size correctly", () => {
49+
expect(formatDataSize(1024)).toBe("1.00 KB");
50+
expect(formatDataSize(1048576)).toBe("1.00 MB");
51+
expect(formatDataSize(1073741824)).toBe("1.00 GB");
52+
expect(formatDataSize(1099511627776)).toBe("1.00 TB");
53+
expect(formatDataSize(1125899906842624)).toBe("1.00 PB");
54+
});
55+
56+
it("should format data size less than 1 KB correctly", () => {
57+
expect(formatDataSize(256)).toBe("0.25 KB");
58+
expect(formatDataSize(512)).toBe("0.50 KB");
59+
});
60+
61+
it("should round data size to 2 decimal places", () => {
62+
expect(formatDataSize(1536)).toBe("1.50 KB");
63+
expect(formatDataSize(1572864)).toBe("1.50 MB");
64+
});
65+
});
66+
67+
describe("test stringToBase64 and base64ToString", () => {
68+
it("should convert string to base64 and back correctly", () => {
69+
const str = "Hello, World!";
70+
const base64 = stringToBase64(str);
71+
expect(base64ToString(base64)).toBe(str);
72+
});
73+
74+
it("should handle empty string correctly", () => {
75+
const str = "";
76+
const base64 = stringToBase64(str);
77+
expect(base64ToString(base64)).toBe(str);
78+
});
79+
80+
it("should handle unicode characters correctly", () => {
81+
const str = "你好,世界!";
82+
const base64 = stringToBase64(str);
83+
expect(base64ToString(base64)).toBe(str);
84+
});
85+
});
86+
87+
describe("test isNumeric", () => {
88+
it("should return true for numeric strings", () => {
89+
expect(isNumeric("123")).toBe(true);
90+
expect(isNumeric("-123")).toBe(true);
91+
expect(isNumeric("3.14")).toBe(true);
92+
expect(isNumeric("-3.14")).toBe(true);
93+
});
94+
95+
it("should return true for Infinity", () => {
96+
expect(isNumeric("Infinity")).toBe(true);
97+
expect(isNumeric("-Infinity")).toBe(true);
98+
});
99+
100+
it("should return false for non-numeric strings", () => {
101+
expect(isNumeric("abc")).toBe(false);
102+
expect(isNumeric("123abc")).toBe(false);
103+
expect(isNumeric(" ")).toBe(false);
104+
});
105+
106+
it("should return false for empty string and NaN", () => {
107+
expect(isNumeric("")).toBe(false);
108+
expect(isNumeric("NaN")).toBe(false);
109+
});
110+
});
111+
112+
describe("test textComponentToString", () => {
113+
it("should directly return the string value if the inputted nbt is NbtString", () => {
114+
const str = "Hello, World!";
115+
expect(textComponentToString(new NbtString(str))).toBe(str);
116+
});
117+
118+
it("should only return the text value of the inputted nbt if the component is NbtObject (text component)", () => {
119+
const str = "Hello, World!";
120+
const nbt = new NbtObject({
121+
text: new NbtString(str),
122+
extra: new NbtList([
123+
new NbtObject({
124+
text: new NbtString(" This is extra text."),
125+
}),
126+
]),
127+
bold: new NbtBool(true),
128+
});
129+
expect(textComponentToString(nbt)).toBe(str);
130+
});
131+
132+
it("should return null if the inputted nbt is not a text component", () => {
133+
const nbt1 = new NbtObject({
134+
extra: new NbtList([
135+
new NbtObject({
136+
text: new NbtString(" This is extra text."),
137+
}),
138+
]),
139+
bold: new NbtBool(true),
140+
});
141+
expect(textComponentToString(nbt1)).toBeNull();
142+
143+
const nbt2 = new NbtList([]);
144+
expect(textComponentToString(nbt2 as any)).toBeNull();
145+
});
146+
});

frontend/lib/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function getCurrentState<T>(setState: SetState<T>): Promise<T> {
4949
* ```
5050
*/
5151
export function getInputtedArgumentStr(str: string, cursor: number): string {
52-
if(cursor > str.length) throw new Error("Cursor position is out of the length of the string.");
52+
if(cursor < 0 || cursor > str.length) throw new Error("Cursor position is out of the length of the string.");
5353

5454
const trimmed = str.substring(0, cursor);
5555
const arr = trimmed.split(" ");
@@ -64,7 +64,7 @@ export function getInputtedArgumentStr(str: string, cursor: number): string {
6464
* ```
6565
*/
6666
export function getCurrentArgumentIndex(str: string, cursor: number): number {
67-
if(cursor > str.length) throw new Error("Cursor position is out of the length of the string.");
67+
if(cursor < 0 || cursor > str.length) throw new Error("Cursor position is out of the length of the string.");
6868

6969
const trimmed = str.substring(0, cursor);
7070
const arr = trimmed.split(" ");
@@ -106,6 +106,7 @@ export function base64ToString(base64: string): string {
106106
}
107107

108108
export function isNumeric(str: string): boolean {
109+
str = str.trim();
109110
if(str === "") return false;
110111
return !Number.isNaN(Number(str));
111112
}

0 commit comments

Comments
 (0)