Skip to content

Commit 6c98f26

Browse files
authored
Merge pull request #195 from banana1715/313551150
[LAB2] 313551150
2 parents ffd245b + 72ded48 commit 6c98f26

File tree

1 file changed

+173
-2
lines changed

1 file changed

+173
-2
lines changed

lab2/main_test.js

Lines changed: 173 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,177 @@
11
const test = require('node:test');
22
const assert = require('assert');
3+
const fs = require('fs');
34
const { Application, MailSystem } = require('./main');
45

5-
// TODO: write your tests here
6-
// Remember to use Stub, Mock, and Spy when necessary
6+
// Helper: create Application without triggering file read error.
7+
// Override getNames so that it immediately returns a resolved promise.
8+
function createTestApplicationWithoutFileRead() {
9+
const originalGetNames = Application.prototype.getNames;
10+
Application.prototype.getNames = function() {
11+
return Promise.resolve([this.people, this.selected]);
12+
};
13+
const app = new Application();
14+
// Immediately restore the original getNames for any later use.
15+
Application.prototype.getNames = originalGetNames;
16+
return app;
17+
}
18+
19+
// Utility function for a small delay.
20+
function delay(ms) {
21+
return new Promise(resolve => setTimeout(resolve, ms));
22+
}
23+
24+
// Test: Application.getNames should read names from file.
25+
test('Application.getNames should read names from file', async () => {
26+
const testData = "Alice\nBob\nCharlie";
27+
fs.writeFileSync('name_list.txt', testData, 'utf8');
28+
29+
// Use the real getNames.
30+
const app = new Application();
31+
const [people, selected] = await app.getNames();
32+
assert.deepStrictEqual(people, ['Alice', 'Bob', 'Charlie']);
33+
34+
fs.unlinkSync('name_list.txt');
35+
});
36+
37+
// Test: Application constructor should initialize people and selected.
38+
test('Application constructor should initialize people and selected', async () => {
39+
const testData = "Alice\nBob";
40+
fs.writeFileSync('name_list.txt', testData, 'utf8');
41+
42+
const app = new Application();
43+
// Wait a bit for the asynchronous constructor to complete.
44+
await delay(20);
45+
assert.deepStrictEqual(app.people, ['Alice', 'Bob']);
46+
assert.deepStrictEqual(app.selected, []);
47+
48+
fs.unlinkSync('name_list.txt');
49+
});
50+
51+
// Test: getRandomPerson returns a valid name.
52+
test('Application.getRandomPerson should return a valid name', () => {
53+
const app = createTestApplicationWithoutFileRead();
54+
app.people = ['Alice', 'Bob', 'Charlie'];
55+
56+
const originalRandom = Math.random;
57+
Math.random = () => 0.5; // floor(0.5 * 3) = 1, expecting 'Bob'
58+
59+
const person = app.getRandomPerson();
60+
assert.strictEqual(person, 'Bob');
61+
62+
Math.random = originalRandom;
63+
});
64+
65+
// Test: selectNextPerson avoids duplicate selections.
66+
test('Application.selectNextPerson should avoid duplicates', () => {
67+
const app = createTestApplicationWithoutFileRead();
68+
app.people = ['Alice', 'Bob', 'Charlie'];
69+
app.selected = ['Alice'];
70+
71+
const originalRandom = Math.random;
72+
// Force Math.random to return a value that selects 'Charlie'
73+
Math.random = () => 0.8; // floor(0.8 * 3) = 2 -> 'Charlie'
74+
75+
const person = app.selectNextPerson();
76+
assert.strictEqual(person, 'Charlie');
77+
assert.strictEqual(app.selected.length, 2);
78+
79+
Math.random = originalRandom;
80+
});
81+
82+
// Test: selectNextPerson returns null if all persons have been selected.
83+
test('Application.selectNextPerson should return null if all selected', () => {
84+
const app = createTestApplicationWithoutFileRead();
85+
app.people = ['Alice', 'Bob'];
86+
app.selected = ['Alice', 'Bob'];
87+
88+
const person = app.selectNextPerson();
89+
assert.strictEqual(person, null);
90+
});
91+
92+
// Test: selectNextPerson loops until a non-duplicate is selected.
93+
test('Application.selectNextPerson should loop until a non-duplicate is selected', () => {
94+
const app = createTestApplicationWithoutFileRead();
95+
app.people = ['Alice', 'Bob', 'Charlie'];
96+
app.selected = ['Alice']; // 'Alice' already selected
97+
98+
// Override getRandomPerson to simulate a duplicate on first call,
99+
// then a unique name on the second call.
100+
let callCount = 0;
101+
app.getRandomPerson = function() {
102+
callCount++;
103+
if (callCount === 1) {
104+
return 'Alice'; // duplicate value
105+
} else {
106+
return 'Bob'; // new value
107+
}
108+
};
109+
110+
const selectedPerson = app.selectNextPerson();
111+
assert.strictEqual(selectedPerson, 'Bob');
112+
assert.strictEqual(callCount, 2); // getRandomPerson should be called twice
113+
});
114+
115+
// Test: MailSystem.write generates the correct mail content.
116+
test('MailSystem.write should generate correct mail content', () => {
117+
const mailSystem = new MailSystem();
118+
const content = mailSystem.write('Alice');
119+
assert.strictEqual(content, 'Congrats, Alice!');
120+
});
121+
122+
// Test: MailSystem.send returns true when Math.random is high.
123+
test('MailSystem.send should return true when Math.random is high', () => {
124+
const mailSystem = new MailSystem();
125+
const originalRandom = Math.random;
126+
Math.random = () => 0.9; // Simulate success
127+
128+
const result = mailSystem.send('Alice', 'Congrats, Alice!');
129+
assert.strictEqual(result, true);
130+
131+
Math.random = originalRandom;
132+
});
133+
134+
// Test: MailSystem.send returns false when Math.random is low.
135+
test('MailSystem.send should return false when Math.random is low', () => {
136+
const mailSystem = new MailSystem();
137+
const originalRandom = Math.random;
138+
Math.random = () => 0.1; // Simulate failure
139+
140+
const result = mailSystem.send('Alice', 'Congrats, Alice!');
141+
assert.strictEqual(result, false);
142+
143+
Math.random = originalRandom;
144+
});
145+
146+
// Test: notifySelected calls write and send for each selected person.
147+
test('Application.notifySelected should call write and send for each person', () => {
148+
const app = createTestApplicationWithoutFileRead();
149+
app.selected = ['Alice', 'Bob'];
150+
151+
let writeCalls = [];
152+
let sendCalls = [];
153+
154+
const originalWrite = app.mailSystem.write;
155+
const originalSend = app.mailSystem.send;
156+
157+
// Override write and send to record calls.
158+
app.mailSystem.write = function(name) {
159+
writeCalls.push(name);
160+
return 'Congrats!';
161+
};
162+
163+
app.mailSystem.send = function(name, context) {
164+
sendCalls.push({ name, context });
165+
return true;
166+
};
167+
168+
app.notifySelected();
169+
170+
assert.deepStrictEqual(writeCalls, ['Alice', 'Bob']);
171+
assert.strictEqual(sendCalls.length, 2);
172+
assert.deepStrictEqual(sendCalls[0], { name: 'Alice', context: 'Congrats!' });
173+
assert.deepStrictEqual(sendCalls[1], { name: 'Bob', context: 'Congrats!' });
174+
175+
app.mailSystem.write = originalWrite;
176+
app.mailSystem.send = originalSend;
177+
});

0 commit comments

Comments
 (0)