Skip to content

Commit 967a9b5

Browse files
committed
improve test coverage to 90%
1 parent 3e98258 commit 967a9b5

3 files changed

Lines changed: 60 additions & 18 deletions

File tree

src/simulator.js

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,27 +63,19 @@ function move(state) {
6363
}
6464

6565
function turn(cmd, state) {
66-
let { f: face } = state;
66+
const { f: face } = state;
6767
const facingIdx = Directions.indexOf(face);
68-
const lastIdx = Directions.length - 1;
69-
70-
if (face === Directions[0] && cmd === "LEFT") {
71-
face = Directions[lastIdx];
72-
} else if (face === Directions[lastIdx] && cmd === "RIGHT") {
73-
face = Directions[0];
74-
} else if (cmd === "RIGHT") {
75-
face = Directions[facingIdx + 1];
76-
} else if (cmd === "LEFT") {
77-
face = Directions[facingIdx - 1];
78-
}
68+
const delta = cmd === "RIGHT" ? 1 : -1;
69+
const nextIdx = (facingIdx + delta + Directions.length) % Directions.length;
70+
const nextFace = Directions[nextIdx];
7971

8072
return {
8173
state: {
8274
...state,
83-
f: face,
75+
f: nextFace,
8476
},
8577
status: "success",
86-
message: `Command success: Robot now faces ${face}`,
78+
message: `Command success: Robot now faces ${nextFace}`,
8779
};
8880
}
8981

@@ -142,13 +134,15 @@ function runCommand(input, state = initialState) {
142134
const { cmd, args } = parseInput(input);
143135
return executeCommand(cmd, args, state);
144136
} catch (error) {
137+
const message =
138+
error && typeof error === "object" && "message" in error && error.message
139+
? error.message
140+
: "Command failed: Unknown parsing error";
141+
145142
return {
146143
state,
147144
status: "fail",
148-
message:
149-
error instanceof Error
150-
? error.message
151-
: "Command failed: Unknown parsing error",
145+
message,
152146
command: null,
153147
};
154148
}

test/serve-static.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe("serve-static security checks", () => {
2121
expect(resolveFilePath(rootDir, "/../package.json")).toBeNull();
2222
expect(resolveFilePath(rootDir, "/..\\..\\secret.txt")).toBeNull();
2323
expect(resolveFilePath(rootDir, "/%2e%2e/%2e%2e/secret.txt")).toBeNull();
24+
expect(resolveFilePath(rootDir, "/C:/Windows/system32")).toBeNull();
2425
});
2526

2627
test("blocks malformed and null-byte request paths", () => {
@@ -159,4 +160,32 @@ describe("serve-static integration", () => {
159160

160161
await new Promise((resolve) => cliServer.close(resolve));
161162
});
163+
164+
test("bootstraps using default dist folder when argv path is omitted", async () => {
165+
const originalCwd = process.cwd();
166+
const tempCwd = fs.mkdtempSync(path.join(os.tmpdir(), "toyrobot-cli-cwd-"));
167+
const distDir = path.join(tempCwd, "dist");
168+
fs.mkdirSync(distDir, { recursive: true });
169+
fs.writeFileSync(path.join(distDir, "index.html"), "<h1>Default Dist</h1>");
170+
171+
const messages = [];
172+
173+
try {
174+
process.chdir(tempCwd);
175+
const cliServer = startServerFromCli(
176+
["node", "serve-static.js"],
177+
{ PORT: "0" },
178+
(msg) => messages.push(msg),
179+
);
180+
await new Promise((resolve) => cliServer.on("listening", resolve));
181+
182+
expect(messages.some((msg) => msg.includes("Serving"))).toBe(true);
183+
expect(messages.some((msg) => msg.includes(distDir))).toBe(true);
184+
185+
await new Promise((resolve) => cliServer.close(resolve));
186+
} finally {
187+
process.chdir(originalCwd);
188+
fs.rmSync(tempCwd, { recursive: true, force: true });
189+
}
190+
});
162191
});

test/simulator.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ describe("simulator runCommand", () => {
9090
runCommand("PLACE 1,1,SOUTH", { ...initialState }).state,
9191
).state;
9292
expect(southToEast.f).toBe("EAST");
93+
94+
const eastToNorth = runCommand(
95+
"LEFT",
96+
runCommand("PLACE 1,1,EAST", { ...initialState }).state,
97+
).state;
98+
expect(eastToNorth.f).toBe("NORTH");
9399
});
94100

95101
test("allows re-PLACE after initial placement", () => {
@@ -105,4 +111,17 @@ describe("simulator runCommand", () => {
105111
const result = runCommand("PLACE 0,0,NORTH", { ...initialState });
106112
expect(result.command).toBe("PLACE");
107113
});
114+
115+
test("uses default initial state when state argument is omitted", () => {
116+
const result = runCommand("PLACE 0,0,NORTH");
117+
expect(result.status).toBe("success");
118+
expect(result.state).toMatchObject({ x: 0, y: 0, f: "NORTH", Placed: true });
119+
});
120+
121+
test("returns fail result for non-string input with default state", () => {
122+
const result = runCommand(null);
123+
expect(result.status).toBe("fail");
124+
expect(result.command).toBeNull();
125+
expect(result.state).toEqual(initialState);
126+
});
108127
});

0 commit comments

Comments
 (0)