1
1
const test = require ( 'node:test' ) ;
2
2
const assert = require ( 'assert' ) ;
3
- const fs = require ( 'fs' ) ;
4
3
const { Application, MailSystem } = require ( './main' ) ;
5
4
6
5
// TODO: write your tests here
7
- < << << << HEAD
8
- // Remember to use Stub, Mock, and Spy when necessary
9
- test ( 'Test getNames' , async ( t ) => {
10
- const mockContent = 'John\nJane\nJim' ;
11
- const tempFilePath = 'name_list.txt' ;
12
-
13
- // create mock file
14
- fs . writeFileSync ( tempFilePath , mockContent , 'utf-8' ) ;
15
-
16
- // create instance
17
- const app = new Application ( ) ;
18
- const names = await app . getNames ( ) ;
19
- app . people = mockContent . split ( '\n' ) ;
20
-
21
- assert . deepStrictEqual ( names [ 0 ] , [ 'John' , 'Jane' , 'Jim' ] ) ;
22
- assert . deepStrictEqual ( names [ 1 ] , [ ] ) ;
23
-
24
- if ( fs . existsSync ( tempFilePath ) ) {
25
- fs . unlinkSync ( tempFilePath ) ;
26
- }
27
- } ) ;
28
- test ( 'Test getNames with empty file' , async ( t ) => {
29
- const tempFilePath = 'name_list.txt' ;
30
-
31
- // 創建空文件
32
- fs . writeFileSync ( tempFilePath , "" , 'utf-8' ) ;
33
-
34
- const app = new Application ( ) ;
35
- const names = await app . getNames ( ) ;
36
-
37
- assert . deepStrictEqual ( names [ 0 ] , [ '' ] ) ;
38
- assert . deepStrictEqual ( names [ 1 ] , [ ] ) ;
39
-
40
- if ( fs . existsSync ( tempFilePath ) ) {
41
- fs . unlinkSync ( tempFilePath ) ;
42
- }
43
- } ) ;
44
- test ( 'Test getNames with file read error' , async ( t ) => {
45
- const tempFilePath = 'name_list.txt' ;
46
- // create mock file
47
- fs . writeFileSync ( tempFilePath , '' , 'utf-8' ) ;
48
-
49
- // 禁用實際的 constructor 調用
50
- const originalConstructor = Application . prototype . constructor ;
51
-
52
- try {
53
- const app = new Application ( ) ;
54
- // await app.getNames();
55
- assert . fail ( "ENOENT: no such file or directory, open 'name_list.txt'" ) ;
56
- } catch ( error ) {
57
- assert . strictEqual ( error . message , "ENOENT: no such file or directory, open 'name_list.txt'" ) ;
58
- } finally {
59
- // 恢復原始的 constructor
60
- Application . prototype . constructor = originalConstructor ;
61
- }
62
- if ( fs . existsSync ( tempFilePath ) ) {
63
- fs . unlinkSync ( tempFilePath ) ;
64
- }
65
- } ) ;
66
- test ( 'Test getRandomPerson' , async ( t ) => {
67
- const mockContent = 'John\nJane\nJim' ;
68
- const tempFilePath = 'name_list.txt' ;
69
-
70
- // create mock file
71
- fs . writeFileSync ( tempFilePath , mockContent , 'utf-8' ) ;
72
-
73
- // create instance
74
- const app = new Application ( ) ;
75
- app . people = mockContent . split ( '\n' ) ;
76
- const person = app . getRandomPerson ( ) ;
77
- // console.log('person = ', person);
78
- assert ( [ 'John' , 'Jane' , 'Jim' ] . includes ( person ) ) ;
79
-
80
- if ( fs . existsSync ( tempFilePath ) ) {
81
- fs . unlinkSync ( tempFilePath ) ;
82
- }
83
- } ) ;
84
-
85
- test ( 'Test getRandomPerson with empty people array' , async ( t ) => {
86
- const tempFilePath = 'name_list.txt' ;
87
-
88
- // 創建臨時文件
89
- fs . writeFileSync ( tempFilePath , '' , 'utf-8' ) ;
90
-
91
- try {
92
- // 創建實例
93
- const app = new Application ( ) ;
94
-
95
- // 設置空的 people 陣列
96
- app . people = [ ] ;
97
-
98
- // 測試 getRandomPerson
99
- const person = app . getRandomPerson ( ) ;
100
-
101
- // 驗證結果
102
- // 在空陣列的情況下,getRandomPerson 可能返回 undefined
103
- // 或者拋出異常(這取決於代碼的實現)
104
- assert . strictEqual ( person , undefined ) ;
105
-
106
- } finally {
107
- // 無論測試成功或失敗,都確保刪除臨時文件
108
- if ( fs . existsSync ( tempFilePath ) ) {
109
- fs . unlinkSync ( tempFilePath ) ;
110
- }
111
- }
112
- } ) ;
113
- test ( 'Test selectNextPerson' , async ( t ) => {
114
- const mockContent = 'John\nJane\nJim' ;
115
- const tempFilePath = 'name_list.txt' ;
116
- const mockContent2 = '' ;
117
- // create mock file
118
- fs . writeFileSync ( tempFilePath , mockContent , 'utf-8' ) ;
119
-
120
- // 創建實例
121
- const app = new Application ( ) ;
122
- await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
123
-
124
- app . people = mockContent . split ( '\n' ) ;
125
- app . selected = [ ] ;
126
- const person = app . selectNextPerson ( ) ;
127
-
128
- // 驗證結果
129
- assert ( [ 'John' , 'Jane' , 'Jim' ] . includes ( person ) ) ;
130
- assert . strictEqual ( app . selected . length , 1 ) ;
131
- assert ( [ 'John' , 'Jane' , 'Jim' ] . includes ( app . selected [ 0 ] ) ) ;
132
-
133
- // 設置所有人都已被選擇
134
- app . people = mockContent2 . split ( '\n' ) ;
135
- app . selected = [ ...app . people ] ; // 所有人都已選擇
136
-
137
- // 測試選擇下一個人應該返回 null
138
- const person2 = app . selectNextPerson ( ) ;
139
-
140
- // 驗證結果
141
- assert . strictEqual ( person2 , null ) ;
142
-
143
- if ( fs . existsSync ( tempFilePath ) ) {
144
- fs . unlinkSync ( tempFilePath ) ;
145
- }
146
- } ) ;
147
- test ( 'Test selectNextPerson with already selected person' , async ( t ) => {
148
- const tempFilePath = 'name_list.txt' ;
149
-
150
- // 創建臨時文件
151
- fs . writeFileSync ( tempFilePath , 'John\nJane\nJim' , 'utf-8' ) ;
152
-
153
- try {
154
- // 創建實例
155
- const app = new Application ( ) ;
156
- await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ; // 等待初始化完成
157
-
158
- // 設置特定的 people 陣列和 selected 陣列
159
- app . people = [ 'John' , 'Jane' , 'Jim' ] ;
160
- app . selected = [ 'John' , 'Jane' ] ; // 已經選擇了 John 和 Jane
161
-
162
- // 強制 getRandomPerson 返回已選擇的人,然後返回未選擇的人
163
- let callCount = 0 ;
164
- const originalGetRandomPerson = app . getRandomPerson ;
165
- app . getRandomPerson = function ( ) {
166
- callCount ++ ;
167
- if ( callCount === 1 ) {
168
- return 'John' ; // 第一次返回已選擇的人
169
- } else {
170
- return 'Jim' ; // 第二次返回未選擇的人
171
- }
172
- } ;
173
-
174
- // 測試 selectNextPerson
175
- const person = app . selectNextPerson ( ) ;
176
-
177
- // 恢復原始 getRandomPerson 方法
178
- app . getRandomPerson = originalGetRandomPerson ;
179
-
180
- // 驗證結果
181
- assert . strictEqual ( person , 'Jim' ) ;
182
- assert . strictEqual ( callCount , 2 ) ; // 確保 getRandomPerson 被調用了兩次
183
- assert . strictEqual ( app . selected . length , 3 ) ;
184
- assert ( app . selected . includes ( 'Jim' ) ) ;
185
-
186
- } finally {
187
- // 無論測試成功或失敗,都確保刪除臨時文件
188
- if ( fs . existsSync ( tempFilePath ) ) {
189
- fs . unlinkSync ( tempFilePath ) ;
190
- }
191
- }
192
- } ) ;
193
- test ( 'Test notifySelected' , async ( t ) => {
194
- const mockContent = 'John\nJane\nJim' ;
195
- const tempFilePath = 'name_list.txt' ;
196
-
197
- // 創建臨時文件
198
- fs . writeFileSync ( tempFilePath , mockContent , 'utf8' ) ;
199
-
200
- try {
201
- // 使用原始的構造函數
202
- const app = new Application ( ) ;
203
-
204
- // 等待初始化完成
205
- await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
206
-
207
- // 測試前準備
208
- app . selected = [ 'John' ] ;
209
-
210
- // 創建 spy 來追踪 MailSystem 的方法調用
211
- let writeCallCount = 0 ;
212
- let sendCallCount = 0 ;
213
-
214
- await t . mock . method ( app . mailSystem , 'write' , ( name ) => {
215
- writeCallCount ++ ;
216
- assert . strictEqual ( name , 'John' ) ;
217
- return 'Mocked content' ;
218
- } ) ;
219
-
220
- await t . mock . method ( app . mailSystem , 'send' , ( name , content ) => {
221
- sendCallCount ++ ;
222
- assert . strictEqual ( name , 'John' ) ;
223
- assert . strictEqual ( content , 'Mocked content' ) ;
224
- return true ;
225
- } ) ;
226
-
227
- // test notifySelected
228
- app . notifySelected ( ) ;
229
-
230
- // verify result
231
- assert . strictEqual ( writeCallCount , 1 ) ;
232
- assert . strictEqual ( sendCallCount , 1 ) ;
233
- } finally {
234
- // ensure delete temp file
235
- if ( fs . existsSync ( tempFilePath ) ) {
236
- fs . unlinkSync ( tempFilePath ) ;
237
- }
238
- }
239
- } ) ;
240
-
241
- test ( 'Test notifySelected with multiple people' , async ( t ) => {
242
- const mockContent = 'John\nJane\nJim' ;
243
- const tempFilePath = 'name_list.txt' ;
244
-
245
- // 創建臨時文件
246
- fs . writeFileSync ( tempFilePath , mockContent , 'utf8' ) ;
247
-
248
- try {
249
- // 使用原始的構造函數
250
- const app = new Application ( ) ;
251
-
252
- // 等待初始化完成
253
- await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
254
-
255
- // 測試前準備 - 設置多個人被選中
256
- app . selected = [ 'John' , 'Jane' , 'Jim' ] ;
257
-
258
- // 跟踪每個人的通知情況
259
- const notifiedPeople = [ ] ;
260
- const writtenContents = { } ;
261
-
262
- // 創建 spy 來追踪 MailSystem 的方法調用
263
- await t . mock . method ( app . mailSystem , 'write' , ( name ) => {
264
- notifiedPeople . push ( name ) ;
265
- const content = `Mocked content for ${ name } ` ;
266
- writtenContents [ name ] = content ;
267
- return content ;
268
- } ) ;
269
-
270
- await t . mock . method ( app . mailSystem , 'send' , ( name , content ) => {
271
- assert . strictEqual ( content , writtenContents [ name ] ) ;
272
- return true ;
273
- } ) ;
274
-
275
- // 測試 notifySelected
276
- app . notifySelected ( ) ;
277
-
278
- // 驗證結果 - 確保所有人都被通知到
279
- assert . strictEqual ( notifiedPeople . length , 3 ) ;
280
- assert ( notifiedPeople . includes ( 'John' ) ) ;
281
- assert ( notifiedPeople . includes ( 'Jane' ) ) ;
282
- assert ( notifiedPeople . includes ( 'Jim' ) ) ;
283
- } finally {
284
- // ensure delete temp file
285
- if ( fs . existsSync ( tempFilePath ) ) {
286
- fs . unlinkSync ( tempFilePath ) ;
287
- }
288
- }
289
- } ) ;
290
-
291
- // Test MailSystem
292
- test ( 'Test MailSystem write' , async ( t ) => {
293
- const mailSystem = new MailSystem ( ) ;
294
- const name = 'John' ;
295
- const result = mailSystem . write ( name ) ;
296
- assert . strictEqual ( result , 'Congrats, John!' ) ;
297
- } ) ;
298
- test ( 'Test MailSystem send success path' , async ( t ) => {
299
- const mailSystem = new MailSystem ( ) ;
300
-
301
- // mock Math.random method
302
- const originalRandom = Math . random ;
303
- Math . random = ( ) => 1 ; // 強制返回 1,確保大於 0.5
304
-
305
- try {
306
- const result = mailSystem . send ( 'John' , 'Congrats, John!' ) ;
307
- assert . strictEqual ( result , true ) ;
308
- } finally {
309
- // restore original method
310
- Math . random = originalRandom ;
311
- }
312
- } ) ;
313
-
314
- test ( 'Test MailSystem send failure path' , async ( t ) => {
315
- const mailSystem = new MailSystem ( ) ;
316
-
317
- // mock Math.random method
318
- const originalRandom = Math . random ;
319
- Math . random = ( ) => 0 ; // 強制返回 0,確保小於 0.5
320
-
321
- try {
322
- const result = mailSystem . send ( 'John' , 'Congrats, John!' ) ;
323
- assert . strictEqual ( result , false ) ;
324
- } finally {
325
- // 恢復原始方法
326
- Math . random = originalRandom ;
327
- }
328
- } ) ;
6
+ // Remember to use Stub, Mock, and Spy when necessary
0 commit comments