@gjsify/net 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.spec.ts CHANGED
@@ -1,84 +1,1076 @@
1
- import { describe, it, expect } from '@gjsify/unit';
1
+ // Ported from refs/node-test/parallel/test-net-isip.js, test-net-connect-buffer.js,
2
+ // test-net-settimeout.js, test-net-bytes-read.js, test-net-server-max-connections.js
3
+ // Original: MIT license, Node.js contributors
2
4
 
3
- import { isIP, isIPv4, isIPv6 } from 'net';
5
+ import { describe, it, expect, on } from '@gjsify/unit';
6
+ import net, { isIP, isIPv4, isIPv6, createServer, createConnection, connect, Socket, Server } from 'node:net';
7
+ import { Buffer } from 'node:buffer';
4
8
 
5
9
  export default async () => {
10
+ await describe('net', async () => {
6
11
 
7
- const v6AddrArr = ['::1'];
8
- const v4AddrArr = ['127.0.0.1'];
9
- const invalidAddrArr = ['127.000.000.001', '127.0.0.1/24', 'fhqwhgads'];
10
-
11
- await describe('net.isIP', async () => {
12
- await it('should be a function', async () => {
13
- expect(typeof isIP).toBe("function");
14
- });
15
-
16
- for (const v6 of v6AddrArr) {
17
- await it(`should return 6 for "${v6}"`, async () => {
18
- expect(isIP(v6)).toBe(6);
19
- });
20
- }
21
-
22
- for (const v4 of v4AddrArr) {
23
- await it(`should return 4 for "${v4}"`, async () => {
24
- expect(isIP(v4)).toBe(4);
25
- });
26
- }
27
-
28
- for (const invalid of invalidAddrArr) {
29
- await it(`should return 0 for "${invalid}"`, async () => {
30
- expect(isIP(invalid)).toBe(0);
31
- });
32
- }
33
-
34
- });
35
-
36
- await describe('net.isIPv4', async () => {
37
- await it('should be a function', async () => {
38
- expect(typeof isIPv4).toBe("function");
39
- });
40
-
41
- for (const v6 of v6AddrArr) {
42
- await it(`should return false for "${v6}"`, async () => {
43
- expect(isIPv4(v6)).toBeFalsy();
44
- });
45
- }
46
-
47
- for (const v4 of v4AddrArr) {
48
- await it(`should return true for "${v4}"`, async () => {
49
- expect(isIPv4(v4)).toBeTruthy();
50
- });
51
- }
52
-
53
- for (const invalid of invalidAddrArr) {
54
- await it(`should return false for "${invalid}"`, async () => {
55
- expect(isIPv4(invalid)).toBeFalsy();
56
- });
57
- }
58
- });
59
-
60
- await describe('net.isIPv6', async () => {
61
- await it('should be a function', async () => {
62
- expect(typeof isIPv6).toBe("function");
63
- });
64
-
65
- for (const v6 of v6AddrArr) {
66
- await it(`should return true for "${v6}"`, async () => {
67
- expect(isIPv6(v6)).toBeTruthy();
68
- });
69
- }
70
-
71
- for (const v4 of v4AddrArr) {
72
- await it(`should return false for "${v4}"`, async () => {
73
- expect(isIPv6(v4)).toBeFalsy();
74
- });
75
- }
76
-
77
- for (const invalid of invalidAddrArr) {
78
- await it(`should return false for "${invalid}"`, async () => {
79
- expect(isIPv6(invalid)).toBeFalsy();
80
- });
81
- }
82
- });
83
-
84
- }
12
+ // ==================== isIP comprehensive tests ====================
13
+ // Ported from refs/node-test/parallel/test-net-isip.js
14
+ await describe('isIP', async () => {
15
+ await it('should return 4 for valid IPv4 addresses', async () => {
16
+ expect(isIP('127.0.0.1')).toBe(4);
17
+ expect(isIP('192.168.1.1')).toBe(4);
18
+ expect(isIP('0.0.0.0')).toBe(4);
19
+ expect(isIP('255.255.255.255')).toBe(4);
20
+ expect(isIP('10.0.0.1')).toBe(4);
21
+ expect(isIP('1.2.3.4')).toBe(4);
22
+ });
23
+
24
+ await it('should return 6 for valid IPv6 addresses', async () => {
25
+ expect(isIP('::1')).toBe(6);
26
+ expect(isIP('fe80::1')).toBe(6);
27
+ expect(isIP('::ffff:127.0.0.1')).toBe(6);
28
+ expect(isIP('2001:db8::1')).toBe(6);
29
+ expect(isIP('::')).toBe(6);
30
+ expect(isIP('fe80::1%eth0')).toBe(6);
31
+ expect(isIP('::ffff:192.168.1.1')).toBe(6);
32
+ });
33
+
34
+ await it('should return 6 for full and compressed IPv6', async () => {
35
+ expect(isIP('0000:0000:0000:0000:0000:0000:0000:0000')).toBe(6);
36
+ expect(isIP('1050:0:0:0:5:600:300c:326b')).toBe(6);
37
+ expect(isIP('2001:252:0:1::2008:6')).toBe(6);
38
+ expect(isIP('2001:dead:beef:1::2008:6')).toBe(6);
39
+ expect(isIP('2001::')).toBe(6);
40
+ expect(isIP('2001:dead::')).toBe(6);
41
+ expect(isIP('2001:dead:beef::')).toBe(6);
42
+ expect(isIP('2001:dead:beef:1::')).toBe(6);
43
+ expect(isIP('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')).toBe(6);
44
+ });
45
+
46
+ await it('should return 6 for IPv4-mapped and mixed notation', async () => {
47
+ expect(isIP('::2001:252:1:2008:6')).toBe(6);
48
+ expect(isIP('::2001:252:1:1.1.1.1')).toBe(6);
49
+ expect(isIP('::2001:252:1:255.255.255.255')).toBe(6);
50
+ });
51
+
52
+ await it('should return 6 for zone ID addresses', async () => {
53
+ expect(isIP('fe80::2008%eth0')).toBe(6);
54
+ expect(isIP('fe80::2008%eth0.0')).toBe(6);
55
+ });
56
+
57
+ await it('should return 0 for invalid addresses', async () => {
58
+ expect(isIP('')).toBe(0);
59
+ expect(isIP('hello')).toBe(0);
60
+ expect(isIP('not an ip')).toBe(0);
61
+ expect(isIP('999.999.999.999')).toBe(0);
62
+ expect(isIP('1.2.3')).toBe(0);
63
+ expect(isIP('1.2.3.4.5')).toBe(0);
64
+ expect(isIP('::banana')).toBe(0);
65
+ expect(isIP('0')).toBe(0);
66
+ expect(isIP('x127.0.0.1')).toBe(0);
67
+ expect(isIP('example.com')).toBe(0);
68
+ });
69
+
70
+ await it('should return 0 for malformed IPv6', async () => {
71
+ expect(isIP('0000:0000:0000:0000:0000:0000:0000:0000::0000')).toBe(0);
72
+ expect(isIP(':2001:252:0:1::2008:6:')).toBe(0);
73
+ expect(isIP(':2001:252:0:1::2008:6')).toBe(0);
74
+ expect(isIP('2001:252:0:1::2008:6:')).toBe(0);
75
+ expect(isIP('2001:252::1::2008:6')).toBe(0);
76
+ expect(isIP('::2001:252:1:255.255.255.255.76')).toBe(0);
77
+ expect(isIP('0000:0000:0000:0000:0000:0000:12345:0000')).toBe(0);
78
+ expect(isIP('::anything')).toBe(0);
79
+ });
80
+
81
+ await it('should return 0 for non-string input', async () => {
82
+ expect(isIP(undefined as any)).toBe(0);
83
+ expect(isIP(null as any)).toBe(0);
84
+ expect(isIP(123 as any)).toBe(0);
85
+ expect(isIP(true as any)).toBe(0);
86
+ expect(isIP({} as any)).toBe(0);
87
+ });
88
+ });
89
+
90
+ await describe('isIPv4', async () => {
91
+ await it('should return true for valid IPv4', async () => {
92
+ expect(isIPv4('127.0.0.1')).toBe(true);
93
+ expect(isIPv4('0.0.0.0')).toBe(true);
94
+ expect(isIPv4('255.255.255.255')).toBe(true);
95
+ });
96
+
97
+ await it('should return false for IPv6 and invalid', async () => {
98
+ expect(isIPv4('::1')).toBe(false);
99
+ expect(isIPv4('')).toBe(false);
100
+ expect(isIPv4('hello')).toBe(false);
101
+ expect(isIPv4('example.com')).toBe(false);
102
+ expect(isIPv4('2001:252:0:1::2008:6')).toBe(false);
103
+ });
104
+
105
+ await it('should return false for non-string input', async () => {
106
+ expect(isIPv4(undefined as any)).toBe(false);
107
+ expect(isIPv4(null as any)).toBe(false);
108
+ expect(isIPv4(123 as any)).toBe(false);
109
+ expect(isIPv4(true as any)).toBe(false);
110
+ expect(isIPv4({} as any)).toBe(false);
111
+ });
112
+ });
113
+
114
+ await describe('isIPv6', async () => {
115
+ await it('should return true for valid IPv6', async () => {
116
+ expect(isIPv6('::1')).toBe(true);
117
+ expect(isIPv6('fe80::1')).toBe(true);
118
+ expect(isIPv6('::')).toBe(true);
119
+ expect(isIPv6('2001:252:0:1::2008:6')).toBe(true);
120
+ });
121
+
122
+ await it('should return false for IPv4 and invalid', async () => {
123
+ expect(isIPv6('127.0.0.1')).toBe(false);
124
+ expect(isIPv6('')).toBe(false);
125
+ expect(isIPv6('hello')).toBe(false);
126
+ expect(isIPv6('example.com')).toBe(false);
127
+ });
128
+
129
+ await it('should return false for non-string input', async () => {
130
+ expect(isIPv6(undefined as any)).toBe(false);
131
+ expect(isIPv6(null as any)).toBe(false);
132
+ expect(isIPv6(123 as any)).toBe(false);
133
+ expect(isIPv6(true as any)).toBe(false);
134
+ expect(isIPv6({} as any)).toBe(false);
135
+ });
136
+ });
137
+
138
+ // ==================== Module exports ====================
139
+ await describe('exports', async () => {
140
+ await it('should export isIP, isIPv4, isIPv6', async () => {
141
+ expect(typeof isIP).toBe('function');
142
+ expect(typeof isIPv4).toBe('function');
143
+ expect(typeof isIPv6).toBe('function');
144
+ });
145
+
146
+ await it('should export createServer and createConnection', async () => {
147
+ expect(typeof createServer).toBe('function');
148
+ expect(typeof createConnection).toBe('function');
149
+ });
150
+
151
+ await it('should export connect as alias for createConnection', async () => {
152
+ expect(typeof connect).toBe('function');
153
+ });
154
+
155
+ await it('should export Socket and Server constructors', async () => {
156
+ expect(typeof Socket).toBe('function');
157
+ expect(typeof Server).toBe('function');
158
+ });
159
+
160
+ await it('should have all exports on the default export', async () => {
161
+ expect(typeof net.isIP).toBe('function');
162
+ expect(typeof net.isIPv4).toBe('function');
163
+ expect(typeof net.isIPv6).toBe('function');
164
+ expect(typeof net.createServer).toBe('function');
165
+ expect(typeof net.createConnection).toBe('function');
166
+ expect(typeof net.connect).toBe('function');
167
+ expect(typeof net.Socket).toBe('function');
168
+ expect(typeof net.Server).toBe('function');
169
+ });
170
+ });
171
+
172
+ // ==================== Socket (unit tests) ====================
173
+ await describe('Socket', async () => {
174
+ await it('should be constructable', async () => {
175
+ const socket = new Socket();
176
+ expect(socket).toBeDefined();
177
+ });
178
+
179
+ await it('should have connecting property initially false', async () => {
180
+ const socket = new Socket();
181
+ expect(socket.connecting).toBe(false);
182
+ });
183
+
184
+ await it('should have bytesRead and bytesWritten at 0', async () => {
185
+ const socket = new Socket();
186
+ expect(socket.bytesRead).toBe(0);
187
+ expect(socket.bytesWritten).toBe(0);
188
+ });
189
+
190
+ await it('should have pending=true before connection', async () => {
191
+ const socket = new Socket();
192
+ expect(socket.pending).toBe(true);
193
+ });
194
+
195
+ await it('should have setTimeout method that returns this', async () => {
196
+ const socket = new Socket();
197
+ expect(typeof socket.setTimeout).toBe('function');
198
+ });
199
+
200
+ await it('should have setKeepAlive method', async () => {
201
+ const socket = new Socket();
202
+ expect(typeof socket.setKeepAlive).toBe('function');
203
+ });
204
+
205
+ await it('should have setNoDelay method', async () => {
206
+ const socket = new Socket();
207
+ expect(typeof socket.setNoDelay).toBe('function');
208
+ });
209
+
210
+ await it('should have address method', async () => {
211
+ const socket = new Socket();
212
+ expect(typeof socket.address).toBe('function');
213
+ });
214
+
215
+ await it('should have ref/unref methods', async () => {
216
+ const socket = new Socket();
217
+ expect(typeof socket.ref).toBe('function');
218
+ expect(typeof socket.unref).toBe('function');
219
+ });
220
+
221
+ await it('should have connect method', async () => {
222
+ const socket = new Socket();
223
+ expect(typeof socket.connect).toBe('function');
224
+ });
225
+
226
+ await it('should have write and end methods (Duplex)', async () => {
227
+ const socket = new Socket();
228
+ expect(typeof socket.write).toBe('function');
229
+ expect(typeof socket.end).toBe('function');
230
+ });
231
+
232
+ await it('should have destroy method', async () => {
233
+ const socket = new Socket();
234
+ expect(typeof socket.destroy).toBe('function');
235
+ });
236
+
237
+ await it('should return empty object from address() when not connected', async () => {
238
+ const socket = new Socket();
239
+ const addr = socket.address();
240
+ expect(addr).toBeDefined();
241
+ });
242
+ });
243
+
244
+ // ==================== Server (unit tests) ====================
245
+ await describe('Server', async () => {
246
+ await it('should be constructable', async () => {
247
+ const server = new Server();
248
+ expect(server).toBeDefined();
249
+ });
250
+
251
+ await it('should have listening property initially false', async () => {
252
+ const server = new Server();
253
+ expect(server.listening).toBe(false);
254
+ });
255
+
256
+ await it('should have listen method', async () => {
257
+ const server = new Server();
258
+ expect(typeof server.listen).toBe('function');
259
+ });
260
+
261
+ await it('should have close method', async () => {
262
+ const server = new Server();
263
+ expect(typeof server.close).toBe('function');
264
+ });
265
+
266
+ await it('should have address method', async () => {
267
+ const server = new Server();
268
+ expect(typeof server.address).toBe('function');
269
+ });
270
+
271
+ await it('should return null from address() before listening', async () => {
272
+ const server = new Server();
273
+ expect(server.address()).toBeNull();
274
+ });
275
+
276
+ await it('should have getConnections method', async () => {
277
+ const server = new Server();
278
+ expect(typeof server.getConnections).toBe('function');
279
+ });
280
+
281
+ await it('should have ref/unref methods', async () => {
282
+ const server = new Server();
283
+ expect(typeof server.ref).toBe('function');
284
+ expect(typeof server.unref).toBe('function');
285
+ });
286
+
287
+ await it('should accept connectionListener in constructor', async () => {
288
+ const server = createServer(() => { /* listener */ });
289
+ expect(server).toBeDefined();
290
+ expect(server.listening).toBe(false);
291
+ });
292
+
293
+ await it('should have maxConnections property', async () => {
294
+ const server = new Server();
295
+ expect(server.maxConnections).toBeUndefined();
296
+ server.maxConnections = 10;
297
+ expect(server.maxConnections).toBe(10);
298
+ });
299
+ });
300
+
301
+ // ==================== TCP connection tests ====================
302
+ await describe('TCP connection', async () => {
303
+ await it('should listen and connect', async () => {
304
+ const server = createServer((socket) => {
305
+ socket.write('hello');
306
+ socket.end();
307
+ });
308
+
309
+ await new Promise<void>((resolve, reject) => {
310
+ server.listen(0, () => {
311
+ const addr = server.address();
312
+ if (!addr || !('port' in addr)) {
313
+ reject(new Error('Server has no address'));
314
+ return;
315
+ }
316
+
317
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
318
+ const chunks: Buffer[] = [];
319
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
320
+ client.on('end', () => {
321
+ const data = Buffer.concat(chunks).toString();
322
+ expect(data).toBe('hello');
323
+ server.close(() => resolve());
324
+ });
325
+ });
326
+
327
+ client.on('error', reject);
328
+ });
329
+
330
+ server.on('error', reject);
331
+ });
332
+ });
333
+
334
+ await it('should listen on port 0 and assign a random port', async () => {
335
+ const server = createServer();
336
+ await new Promise<void>((resolve, reject) => {
337
+ server.listen(0, () => {
338
+ const addr = server.address();
339
+ expect(addr).toBeDefined();
340
+ expect(typeof (addr as any).port).toBe('number');
341
+ expect((addr as any).port).toBeGreaterThan(0);
342
+ expect(server.listening).toBe(true);
343
+ server.close(() => resolve());
344
+ });
345
+ server.on('error', reject);
346
+ });
347
+ });
348
+
349
+ await it('should emit close event on server.close', async () => {
350
+ const server = createServer();
351
+ await new Promise<void>((resolve, reject) => {
352
+ server.listen(0, () => {
353
+ server.close(() => {
354
+ expect(server.listening).toBe(false);
355
+ resolve();
356
+ });
357
+ });
358
+ server.on('error', reject);
359
+ });
360
+ });
361
+
362
+ await it('should echo data back', async () => {
363
+ const server = createServer((socket) => {
364
+ socket.on('data', (data) => {
365
+ socket.write(data);
366
+ });
367
+ socket.on('end', () => socket.end());
368
+ });
369
+
370
+ await new Promise<void>((resolve, reject) => {
371
+ server.listen(0, () => {
372
+ const addr = server.address() as { port: number };
373
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
374
+ client.write('echo test');
375
+ client.end();
376
+ });
377
+
378
+ const chunks: Buffer[] = [];
379
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
380
+ client.on('end', () => {
381
+ const data = Buffer.concat(chunks).toString();
382
+ expect(data).toBe('echo test');
383
+ server.close(() => resolve());
384
+ });
385
+ client.on('error', reject);
386
+ });
387
+ server.on('error', reject);
388
+ });
389
+ });
390
+
391
+ await it('should handle multiple sequential connections', async () => {
392
+ let connectionCount = 0;
393
+ const server = createServer((socket) => {
394
+ connectionCount++;
395
+ socket.write(`conn${connectionCount}`);
396
+ socket.end();
397
+ });
398
+
399
+ await new Promise<void>((resolve, reject) => {
400
+ server.listen(0, async () => {
401
+ const addr = server.address() as { port: number };
402
+
403
+ const connectAndRead = () => new Promise<string>((res, rej) => {
404
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
405
+ const chunks: Buffer[] = [];
406
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
407
+ client.on('end', () => res(Buffer.concat(chunks).toString()));
408
+ client.on('error', rej);
409
+ });
410
+ });
411
+
412
+ try {
413
+ const data1 = await connectAndRead();
414
+ expect(data1).toBe('conn1');
415
+ const data2 = await connectAndRead();
416
+ expect(data2).toBe('conn2');
417
+ server.close(() => resolve());
418
+ } catch (e) {
419
+ reject(e);
420
+ }
421
+ });
422
+ server.on('error', reject);
423
+ });
424
+ });
425
+
426
+ await it('should set remoteAddress and remotePort on connection', async () => {
427
+ const server = createServer((socket) => {
428
+ socket.end();
429
+ });
430
+
431
+ await new Promise<void>((resolve, reject) => {
432
+ server.listen(0, () => {
433
+ const addr = server.address() as { port: number };
434
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
435
+ expect(client.remoteAddress).toBe('127.0.0.1');
436
+ expect(client.remotePort).toBe(addr.port);
437
+ client.on('end', () => {
438
+ server.close(() => resolve());
439
+ });
440
+ client.resume();
441
+ });
442
+ client.on('error', reject);
443
+ });
444
+ server.on('error', reject);
445
+ });
446
+ });
447
+
448
+ // Ported from refs/node-test/parallel/test-net-connect-buffer.js
449
+ await it('should set socket state during connect lifecycle', async () => {
450
+ const server = createServer((socket) => {
451
+ socket.end();
452
+ });
453
+
454
+ await new Promise<void>((resolve, reject) => {
455
+ server.listen(0, () => {
456
+ const addr = server.address() as { port: number };
457
+ const socket = new Socket();
458
+
459
+ expect(socket.pending).toBe(true);
460
+ expect(socket.connecting).toBe(false);
461
+
462
+ socket.connect(addr.port, '127.0.0.1', () => {
463
+ expect(socket.connecting).toBe(false);
464
+ expect(socket.pending).toBe(false);
465
+ socket.on('end', () => {
466
+ server.close(() => resolve());
467
+ });
468
+ socket.resume();
469
+ });
470
+
471
+ // After connect() is called but before connected
472
+ expect(socket.connecting).toBe(true);
473
+
474
+ socket.on('error', reject);
475
+ });
476
+ server.on('error', reject);
477
+ });
478
+ });
479
+
480
+ await it('should set localAddress and localPort after connect', async () => {
481
+ const server = createServer((socket) => {
482
+ socket.end();
483
+ });
484
+
485
+ await new Promise<void>((resolve, reject) => {
486
+ server.listen(0, () => {
487
+ const addr = server.address() as { port: number };
488
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
489
+ expect(client.localAddress).toBeDefined();
490
+ expect(typeof client.localPort).toBe('number');
491
+ expect(client.localPort).toBeGreaterThan(0);
492
+ client.on('end', () => {
493
+ server.close(() => resolve());
494
+ });
495
+ client.resume();
496
+ });
497
+ client.on('error', reject);
498
+ });
499
+ server.on('error', reject);
500
+ });
501
+ });
502
+
503
+ // Ported from refs/node-test/parallel/test-net-bytes-read.js
504
+ await it('should track bytesRead on the receiving socket', async () => {
505
+ const payload = 'hello world bytes test';
506
+ const server = createServer((socket) => {
507
+ socket.end(payload);
508
+ });
509
+
510
+ await new Promise<void>((resolve, reject) => {
511
+ server.listen(0, () => {
512
+ const addr = server.address() as { port: number };
513
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
514
+ client.on('data', () => {
515
+ // bytesRead should increase
516
+ expect(client.bytesRead).toBeGreaterThan(0);
517
+ });
518
+ client.on('end', () => {
519
+ expect(client.bytesRead).toBe(Buffer.byteLength(payload));
520
+ server.close(() => resolve());
521
+ });
522
+ });
523
+ client.on('error', reject);
524
+ });
525
+ server.on('error', reject);
526
+ });
527
+ });
528
+
529
+ await it('should track bytesWritten on the sending socket', async () => {
530
+ const payload = 'hello bytes written';
531
+ const server = createServer((socket) => {
532
+ const chunks: Buffer[] = [];
533
+ socket.on('data', (chunk) => chunks.push(chunk as Buffer));
534
+ socket.on('end', () => {
535
+ const received = Buffer.concat(chunks).toString();
536
+ expect(received).toBe(payload);
537
+ socket.end();
538
+ });
539
+ });
540
+
541
+ await new Promise<void>((resolve, reject) => {
542
+ server.listen(0, () => {
543
+ const addr = server.address() as { port: number };
544
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
545
+ client.end(payload, () => {
546
+ // bytesWritten should match the payload
547
+ expect(client.bytesWritten).toBe(Buffer.byteLength(payload));
548
+ });
549
+ client.on('end', () => {
550
+ server.close(() => resolve());
551
+ });
552
+ client.resume();
553
+ });
554
+ client.on('error', reject);
555
+ });
556
+ server.on('error', reject);
557
+ });
558
+ });
559
+
560
+ await it('should support setEncoding on socket', async () => {
561
+ const server = createServer((socket) => {
562
+ socket.write('hello encoding');
563
+ socket.end();
564
+ });
565
+
566
+ await new Promise<void>((resolve, reject) => {
567
+ server.listen(0, () => {
568
+ const addr = server.address() as { port: number };
569
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
570
+ client.setEncoding('utf8');
571
+ const chunks: string[] = [];
572
+ client.on('data', (chunk) => {
573
+ expect(typeof chunk).toBe('string');
574
+ chunks.push(chunk as string);
575
+ });
576
+ client.on('end', () => {
577
+ expect(chunks.join('')).toBe('hello encoding');
578
+ server.close(() => resolve());
579
+ });
580
+ });
581
+ client.on('error', reject);
582
+ });
583
+ server.on('error', reject);
584
+ });
585
+ });
586
+
587
+ // Ported from refs/node-test/parallel/test-net-settimeout.js
588
+ await it('should support setTimeout and cancel it', async () => {
589
+ const server = createServer((socket) => {
590
+ socket.write('hello');
591
+ // Keep connection open briefly
592
+ setTimeout(() => socket.end(), 200);
593
+ });
594
+
595
+ await new Promise<void>((resolve, reject) => {
596
+ server.listen(0, () => {
597
+ const addr = server.address() as { port: number };
598
+ const socket = createConnection(addr.port, '127.0.0.1');
599
+
600
+ // Set then immediately disable timeout
601
+ const s = socket.setTimeout(100);
602
+ expect(s).toBe(socket); // should return this
603
+ socket.setTimeout(0); // cancel
604
+
605
+ socket.on('data', () => {
606
+ // Timeout should not have fired
607
+ });
608
+ socket.on('end', () => {
609
+ socket.destroy();
610
+ server.close(() => resolve());
611
+ });
612
+ socket.on('error', reject);
613
+ });
614
+ server.on('error', reject);
615
+ });
616
+ });
617
+
618
+ await it('should emit timeout event', async () => {
619
+ const server = createServer((socket) => {
620
+ // Don't send anything — let client time out
621
+ });
622
+
623
+ await new Promise<void>((resolve, reject) => {
624
+ server.listen(0, () => {
625
+ const addr = server.address() as { port: number };
626
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
627
+ client.setTimeout(100);
628
+ client.on('timeout', () => {
629
+ client.destroy();
630
+ server.close(() => resolve());
631
+ });
632
+ });
633
+ client.on('error', () => {
634
+ // Expected — we destroyed the socket
635
+ });
636
+ });
637
+ server.on('error', reject);
638
+ });
639
+ });
640
+
641
+ await it('should report getConnections correctly', async () => {
642
+ const server = createServer((socket) => {
643
+ // Hold connection open
644
+ });
645
+
646
+ await new Promise<void>((resolve, reject) => {
647
+ server.listen(0, () => {
648
+ const addr = server.address() as { port: number };
649
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
650
+ server.getConnections((err, count) => {
651
+ expect(err).toBeNull();
652
+ expect(count).toBe(1);
653
+ client.destroy();
654
+ server.close(() => resolve());
655
+ });
656
+ });
657
+ client.on('error', () => {});
658
+ });
659
+ server.on('error', reject);
660
+ });
661
+ });
662
+
663
+ await it('should set remoteFamily to IPv4', async () => {
664
+ const server = createServer((socket) => {
665
+ socket.end();
666
+ });
667
+
668
+ await new Promise<void>((resolve, reject) => {
669
+ server.listen(0, () => {
670
+ const addr = server.address() as { port: number };
671
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
672
+ expect(client.remoteFamily).toBe('IPv4');
673
+ client.on('end', () => {
674
+ server.close(() => resolve());
675
+ });
676
+ client.resume();
677
+ });
678
+ client.on('error', reject);
679
+ });
680
+ server.on('error', reject);
681
+ });
682
+ });
683
+
684
+ await it('should emit connection event on server', async () => {
685
+ let connectionEmitted = false;
686
+ const server = createServer();
687
+ server.on('connection', (socket) => {
688
+ connectionEmitted = true;
689
+ socket.end();
690
+ });
691
+
692
+ await new Promise<void>((resolve, reject) => {
693
+ server.listen(0, () => {
694
+ const addr = server.address() as { port: number };
695
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' });
696
+ client.on('end', () => {
697
+ expect(connectionEmitted).toBe(true);
698
+ server.close(() => resolve());
699
+ });
700
+ client.on('error', reject);
701
+ client.resume();
702
+ });
703
+ server.on('error', reject);
704
+ });
705
+ });
706
+
707
+ await it('should pass multi-byte UTF-8 data correctly', async () => {
708
+ const message = "L'État, c'est moi — 日本語テスト";
709
+ const server = createServer((socket) => {
710
+ socket.setEncoding('utf8');
711
+ let buf = '';
712
+ socket.on('data', (d) => { buf += d; });
713
+ socket.on('end', () => {
714
+ socket.write(buf);
715
+ socket.end();
716
+ });
717
+ });
718
+
719
+ await new Promise<void>((resolve, reject) => {
720
+ server.listen(0, () => {
721
+ const addr = server.address() as { port: number };
722
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
723
+ client.end(message);
724
+ });
725
+ client.setEncoding('utf8');
726
+ let received = '';
727
+ client.on('data', (d) => { received += d; });
728
+ client.on('end', () => {
729
+ expect(received).toBe(message);
730
+ server.close(() => resolve());
731
+ });
732
+ client.on('error', reject);
733
+ });
734
+ server.on('error', reject);
735
+ });
736
+ });
737
+
738
+ await it('should handle socket.destroy() during connection', async () => {
739
+ const server = createServer((socket) => {
740
+ socket.end();
741
+ });
742
+
743
+ await new Promise<void>((resolve, reject) => {
744
+ server.listen(0, () => {
745
+ const addr = server.address() as { port: number };
746
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
747
+ client.destroy();
748
+ expect(client.destroyed).toBe(true);
749
+ server.close(() => resolve());
750
+ });
751
+ client.on('error', () => {}); // Ignore errors from destroyed socket
752
+ });
753
+ server.on('error', reject);
754
+ });
755
+ });
756
+
757
+ await it('should emit close event on socket after destroy', async () => {
758
+ const server = createServer((socket) => {
759
+ socket.end();
760
+ });
761
+
762
+ await new Promise<void>((resolve, reject) => {
763
+ server.listen(0, () => {
764
+ const addr = server.address() as { port: number };
765
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
766
+ client.on('close', () => {
767
+ server.close(() => resolve());
768
+ });
769
+ client.destroy();
770
+ });
771
+ client.on('error', () => {}); // Ignore
772
+ });
773
+ server.on('error', reject);
774
+ });
775
+ });
776
+
777
+ await it('should support connect with port number shorthand', async () => {
778
+ const server = createServer((socket) => {
779
+ socket.write('ok');
780
+ socket.end();
781
+ });
782
+
783
+ await new Promise<void>((resolve, reject) => {
784
+ server.listen(0, () => {
785
+ const addr = server.address() as { port: number };
786
+ // Use the simpler connect(port, host, cb) form
787
+ const client = net.connect(addr.port, '127.0.0.1', () => {
788
+ const chunks: Buffer[] = [];
789
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
790
+ client.on('end', () => {
791
+ expect(Buffer.concat(chunks).toString()).toBe('ok');
792
+ server.close(() => resolve());
793
+ });
794
+ });
795
+ client.on('error', reject);
796
+ });
797
+ server.on('error', reject);
798
+ });
799
+ });
800
+
801
+ await it('should handle large data transfer', async () => {
802
+ const size = 64 * 1024; // 64 KB
803
+ const payload = Buffer.alloc(size, 0x41); // 'A' repeated
804
+
805
+ const server = createServer((socket) => {
806
+ socket.end(payload);
807
+ });
808
+
809
+ await new Promise<void>((resolve, reject) => {
810
+ server.listen(0, () => {
811
+ const addr = server.address() as { port: number };
812
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
813
+ const chunks: Buffer[] = [];
814
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
815
+ client.on('end', () => {
816
+ const received = Buffer.concat(chunks);
817
+ expect(received.length).toBe(size);
818
+ expect(received.every(b => b === 0x41)).toBe(true);
819
+ server.close(() => resolve());
820
+ });
821
+ });
822
+ client.on('error', reject);
823
+ });
824
+ server.on('error', reject);
825
+ });
826
+ });
827
+
828
+ await it('should report server address family', async () => {
829
+ const server = createServer();
830
+ await new Promise<void>((resolve, reject) => {
831
+ server.listen(0, '127.0.0.1', () => {
832
+ const addr = server.address()!;
833
+ expect(addr.family).toBe('IPv4');
834
+ expect(addr.address).toBe('127.0.0.1');
835
+ expect(typeof addr.port).toBe('number');
836
+ server.close(() => resolve());
837
+ });
838
+ server.on('error', reject);
839
+ });
840
+ });
841
+
842
+ // ==================== TCP error handling ====================
843
+ // Ported from refs/node-test/parallel/test-net-connect-error.js
844
+ // Original: MIT license, Node.js contributors
845
+
846
+ await it('should emit error when connecting to refused port', async () => {
847
+ const client = createConnection({ port: 1, host: '127.0.0.1' });
848
+ const err = await new Promise<Error>((resolve) => {
849
+ client.on('error', (e) => resolve(e));
850
+ });
851
+ expect(err).toBeDefined();
852
+ expect((err as NodeJS.ErrnoException).code).toBeDefined();
853
+ client.destroy();
854
+ });
855
+
856
+ await it('should support socket.setNoDelay', async () => {
857
+ const server = createServer((socket) => {
858
+ socket.end('ok');
859
+ });
860
+
861
+ await new Promise<void>((resolve, reject) => {
862
+ server.listen(0, () => {
863
+ const addr = server.address() as { port: number };
864
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
865
+ // setNoDelay should not throw
866
+ client.setNoDelay(true);
867
+ client.setNoDelay(false);
868
+ client.on('end', () => {
869
+ server.close(() => resolve());
870
+ });
871
+ client.resume();
872
+ });
873
+ client.on('error', reject);
874
+ });
875
+ server.on('error', reject);
876
+ });
877
+ });
878
+
879
+ await it('should support socket.setKeepAlive', async () => {
880
+ const server = createServer((socket) => {
881
+ socket.end('ok');
882
+ });
883
+
884
+ await new Promise<void>((resolve, reject) => {
885
+ server.listen(0, () => {
886
+ const addr = server.address() as { port: number };
887
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
888
+ // setKeepAlive should not throw
889
+ client.setKeepAlive(true);
890
+ client.setKeepAlive(false, 1000);
891
+ client.on('end', () => {
892
+ server.close(() => resolve());
893
+ });
894
+ client.resume();
895
+ });
896
+ client.on('error', reject);
897
+ });
898
+ server.on('error', reject);
899
+ });
900
+ });
901
+
902
+ await it('should support socket.ref and unref', async () => {
903
+ const server = createServer((socket) => {
904
+ socket.end('ok');
905
+ });
906
+
907
+ await new Promise<void>((resolve, reject) => {
908
+ server.listen(0, () => {
909
+ const addr = server.address() as { port: number };
910
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
911
+ const result = client.ref();
912
+ expect(result).toBe(client); // should return this
913
+ const result2 = client.unref();
914
+ expect(result2).toBe(client);
915
+ client.on('end', () => {
916
+ server.close(() => resolve());
917
+ });
918
+ client.resume();
919
+ });
920
+ client.on('error', reject);
921
+ });
922
+ server.on('error', reject);
923
+ });
924
+ });
925
+
926
+ await it('server.ref/unref should return this', async () => {
927
+ const server = createServer();
928
+ await new Promise<void>((resolve, reject) => {
929
+ server.listen(0, () => {
930
+ const r1 = server.ref();
931
+ expect(r1).toBe(server);
932
+ const r2 = server.unref();
933
+ expect(r2).toBe(server);
934
+ server.close(() => resolve());
935
+ });
936
+ server.on('error', reject);
937
+ });
938
+ });
939
+
940
+ await it('should handle write after end gracefully', async () => {
941
+ const server = createServer((socket) => {
942
+ socket.on('error', () => {}); // Ignore ECONNRESET from client closing
943
+ socket.end('done');
944
+ });
945
+
946
+ await new Promise<void>((resolve, reject) => {
947
+ server.listen(0, () => {
948
+ const addr = server.address() as { port: number };
949
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
950
+ client.end();
951
+ // Write after end should not crash
952
+ const result = client.write('after end');
953
+ expect(result).toBe(false);
954
+ client.on('error', () => {}); // Ignore write-after-end error
955
+ client.on('close', () => {
956
+ server.close(() => resolve());
957
+ });
958
+ });
959
+ client.on('error', () => {});
960
+ });
961
+ server.on('error', reject);
962
+ });
963
+ });
964
+
965
+ await it('should handle simultaneous connections', async () => {
966
+ let connCount = 0;
967
+ const server = createServer((socket) => {
968
+ connCount++;
969
+ socket.write(`client${connCount}`);
970
+ socket.end();
971
+ });
972
+
973
+ await new Promise<void>((resolve, reject) => {
974
+ server.listen(0, () => {
975
+ const addr = server.address() as { port: number };
976
+ let done = 0;
977
+ const results: string[] = [];
978
+
979
+ for (let i = 0; i < 3; i++) {
980
+ const client = createConnection({ port: addr.port, host: '127.0.0.1' }, () => {
981
+ const chunks: Buffer[] = [];
982
+ client.on('data', (chunk) => chunks.push(chunk as Buffer));
983
+ client.on('end', () => {
984
+ results.push(Buffer.concat(chunks).toString());
985
+ done++;
986
+ if (done === 3) {
987
+ expect(results.length).toBe(3);
988
+ server.close(() => resolve());
989
+ }
990
+ });
991
+ });
992
+ client.on('error', reject);
993
+ }
994
+ });
995
+ server.on('error', reject);
996
+ });
997
+ });
998
+ });
999
+
1000
+ // ==================== Socket additional properties (cross-platform) ====================
1001
+
1002
+ await describe('Socket additional properties', async () => {
1003
+ await it('should have ref/unref methods', async () => {
1004
+ const socket = new Socket();
1005
+ expect(typeof socket.ref).toBe('function');
1006
+ expect(typeof socket.unref).toBe('function');
1007
+ });
1008
+
1009
+ await it('ref/unref should return this', async () => {
1010
+ const socket = new Socket();
1011
+ expect(socket.ref()).toBe(socket);
1012
+ expect(socket.unref()).toBe(socket);
1013
+ });
1014
+
1015
+ await it('should have setNoDelay method', async () => {
1016
+ const socket = new Socket();
1017
+ expect(typeof socket.setNoDelay).toBe('function');
1018
+ });
1019
+
1020
+ await it('should have setKeepAlive method', async () => {
1021
+ const socket = new Socket();
1022
+ expect(typeof socket.setKeepAlive).toBe('function');
1023
+ });
1024
+
1025
+ await it('should have address method', async () => {
1026
+ const socket = new Socket();
1027
+ expect(typeof socket.address).toBe('function');
1028
+ });
1029
+
1030
+ await it('should have destroyed=false initially', async () => {
1031
+ const socket = new Socket();
1032
+ expect(socket.destroyed).toBe(false);
1033
+ });
1034
+
1035
+ await it('should have readyState property', async () => {
1036
+ const socket = new Socket();
1037
+ expect(socket.readyState).toBeDefined();
1038
+ });
1039
+ });
1040
+
1041
+ // ==================== Server additional properties (cross-platform) ====================
1042
+
1043
+ await describe('Server additional properties', async () => {
1044
+ await it('should have ref/unref methods', async () => {
1045
+ const server = new Server();
1046
+ expect(typeof server.ref).toBe('function');
1047
+ expect(typeof server.unref).toBe('function');
1048
+ });
1049
+
1050
+ await it('should have listening=false before listen', async () => {
1051
+ const server = createServer();
1052
+ expect(server.listening).toBe(false);
1053
+ });
1054
+
1055
+ await it('should have address method', async () => {
1056
+ const server = createServer();
1057
+ expect(typeof server.address).toBe('function');
1058
+ });
1059
+
1060
+ await it('address() should return null before listening', async () => {
1061
+ const server = createServer();
1062
+ expect(server.address()).toBeNull();
1063
+ });
1064
+
1065
+ await it('should have getConnections method', async () => {
1066
+ const server = createServer();
1067
+ expect(typeof server.getConnections).toBe('function');
1068
+ });
1069
+
1070
+ await it('should have close method', async () => {
1071
+ const server = createServer();
1072
+ expect(typeof server.close).toBe('function');
1073
+ });
1074
+ });
1075
+ });
1076
+ };