Skip to content

Commit b472068

Browse files
add tests
1 parent fb58588 commit b472068

2 files changed

Lines changed: 191 additions & 1 deletion

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
"main": "index.js",
99
"scripts": {
1010
"format": "prettier . --write",
11-
"test": "prettier . --check"
11+
"test": "prettier . --check && node test.js"
1212
},
1313
"dependencies": {
1414
"bare-encoding": "^1.0.3"
1515
},
1616
"devDependencies": {
17+
"brittle": "^4.0.0",
1718
"prettier": "^3.8.3",
1819
"prettier-config-holepunch": "^2.0.0"
1920
}

test.js

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
const test = require('brittle')
2+
const {
3+
CAPABILITY_LEN,
4+
HEADER_LEN,
5+
MODE_TUNNEL,
6+
MODE_PROBE,
7+
encodeHeader,
8+
decodeHeader,
9+
encodeProbeResponse,
10+
decodeProbeResponse
11+
} = require('./index.js')
12+
13+
test('constants', function (t) {
14+
t.is(CAPABILITY_LEN, 32)
15+
t.is(HEADER_LEN, 33)
16+
t.is(MODE_TUNNEL, 0)
17+
t.is(MODE_PROBE, 1)
18+
})
19+
20+
test('encodeHeader - tunnel mode', function (t) {
21+
const cap = Buffer.alloc(32, 0xab)
22+
const header = encodeHeader(cap, MODE_TUNNEL)
23+
24+
t.is(header.length, HEADER_LEN)
25+
t.alike(Buffer.from(header.subarray(0, 32)), cap)
26+
t.is(header[32], MODE_TUNNEL)
27+
})
28+
29+
test('encodeHeader - probe mode', function (t) {
30+
const cap = Buffer.alloc(32, 0xff)
31+
const header = encodeHeader(cap, MODE_PROBE)
32+
33+
t.is(header[32], MODE_PROBE)
34+
})
35+
36+
test('encodeHeader - rejects wrong capability length', function (t) {
37+
t.exception(() => encodeHeader(Buffer.alloc(16), 0), /capability must be 32 bytes/)
38+
t.exception(() => encodeHeader(Buffer.alloc(0), 0), /capability must be 32 bytes/)
39+
t.exception(() => encodeHeader(Buffer.alloc(64), 0), /capability must be 32 bytes/)
40+
})
41+
42+
test('encodeHeader - rejects invalid mode', function (t) {
43+
const cap = Buffer.alloc(32)
44+
t.exception(() => encodeHeader(cap, -1), /mode must be a byte/)
45+
t.exception(() => encodeHeader(cap, 256), /mode must be a byte/)
46+
t.exception(() => encodeHeader(cap, 1.5), /mode must be a byte/)
47+
t.exception(() => encodeHeader(cap, NaN), /mode must be a byte/)
48+
})
49+
50+
test('decodeHeader - round trip', function (t) {
51+
const cap = Buffer.alloc(32)
52+
for (let i = 0; i < 32; i++) cap[i] = i
53+
54+
const encoded = encodeHeader(cap, MODE_PROBE)
55+
const decoded = decodeHeader(encoded)
56+
57+
t.alike(Buffer.from(decoded.capability), cap)
58+
t.is(decoded.mode, MODE_PROBE)
59+
t.is(decoded.leftover.length, 0)
60+
})
61+
62+
test('decodeHeader - with leftover bytes', function (t) {
63+
const cap = Buffer.alloc(32, 0x01)
64+
const header = encodeHeader(cap, MODE_TUNNEL)
65+
const extra = Buffer.from([0xde, 0xad])
66+
const combined = Buffer.concat([header, extra])
67+
68+
const decoded = decodeHeader(combined)
69+
t.alike(decoded.leftover, extra)
70+
})
71+
72+
test('decodeHeader - returns null on short input', function (t) {
73+
t.is(decodeHeader(Buffer.alloc(0)), null)
74+
t.is(decodeHeader(Buffer.alloc(32)), null)
75+
})
76+
77+
test('encodeProbeResponse - defaults', function (t) {
78+
const probe = encodeProbeResponse()
79+
80+
t.is(probe[0], 0)
81+
t.is(probe[1], 0)
82+
t.is(probe[2], 0)
83+
t.is(probe[3], 0)
84+
t.is(probe.length, 4)
85+
})
86+
87+
test('encodeProbeResponse - with host and port', function (t) {
88+
const probe = encodeProbeResponse({ port: 8080, host: '127.0.0.1' })
89+
90+
t.is((probe[0] << 8) | probe[1], 8080)
91+
t.is(probe[2], 0)
92+
t.is(probe[3], 9)
93+
t.is(probe.length, 4 + 9)
94+
})
95+
96+
test('encodeProbeResponse - udp flag', function (t) {
97+
const probe = encodeProbeResponse({ udp: true })
98+
t.is(probe[2], 1)
99+
100+
const probe2 = encodeProbeResponse({ udp: false })
101+
t.is(probe2[2], 0)
102+
})
103+
104+
test('encodeProbeResponse - rejects host over 255 bytes', function (t) {
105+
const longHost = 'a'.repeat(256)
106+
t.exception(() => encodeProbeResponse({ host: longHost }), /host exceeds 255 bytes/)
107+
})
108+
109+
test('encodeProbeResponse - rejects invalid port', function (t) {
110+
t.exception(() => encodeProbeResponse({ port: -1 }), /port must fit in uint16/)
111+
t.exception(() => encodeProbeResponse({ port: 0x10000 }), /port must fit in uint16/)
112+
})
113+
114+
test('decodeProbeResponse - round trip', function (t) {
115+
const original = { port: 443, host: 'example.com', udp: false }
116+
const encoded = encodeProbeResponse(original)
117+
const decoded = decodeProbeResponse(encoded)
118+
119+
t.is(decoded.port, 443)
120+
t.is(decoded.host, 'example.com')
121+
t.is(decoded.udp, false)
122+
t.is(decoded.leftover.length, 0)
123+
})
124+
125+
test('decodeProbeResponse - udp round trip', function (t) {
126+
const encoded = encodeProbeResponse({ port: 53, host: '8.8.8.8', udp: true })
127+
const decoded = decodeProbeResponse(encoded)
128+
129+
t.is(decoded.port, 53)
130+
t.is(decoded.host, '8.8.8.8')
131+
t.is(decoded.udp, true)
132+
})
133+
134+
test('decodeProbeResponse - with leftover bytes', function (t) {
135+
const encoded = encodeProbeResponse({ port: 80, host: 'localhost' })
136+
const extra = Buffer.from([0x01, 0x02, 0x03])
137+
const combined = Buffer.concat([encoded, extra])
138+
139+
const decoded = decodeProbeResponse(combined)
140+
t.alike(decoded.leftover, extra)
141+
})
142+
143+
test('decodeProbeResponse - returns null on short input', function (t) {
144+
t.is(decodeProbeResponse(Buffer.alloc(0)), null)
145+
t.is(decodeProbeResponse(Buffer.alloc(3)), null)
146+
})
147+
148+
test('decodeProbeResponse - returns null when host is truncated', function (t) {
149+
const buf = Buffer.from([0x00, 0x50, 0x00, 0x05, 0x61])
150+
t.is(decodeProbeResponse(buf), null)
151+
})
152+
153+
test('full header + probe round trip', function (t) {
154+
const cap = Buffer.alloc(32, 0xcc)
155+
const header = encodeHeader(cap, MODE_PROBE)
156+
const probe = encodeProbeResponse({ port: 9999, host: '10.0.0.1', udp: true })
157+
const wire = Buffer.concat([header, probe])
158+
159+
const h = decodeHeader(wire)
160+
t.is(h.mode, MODE_PROBE)
161+
t.alike(h.capability, cap)
162+
163+
const p = decodeProbeResponse(h.leftover)
164+
t.is(p.port, 9999)
165+
t.is(p.host, '10.0.0.1')
166+
t.is(p.udp, true)
167+
t.is(p.leftover.length, 0)
168+
})
169+
170+
test('encodeProbeResponse - empty host', function (t) {
171+
const encoded = encodeProbeResponse({ port: 1234, host: '' })
172+
const decoded = decodeProbeResponse(encoded)
173+
174+
t.is(decoded.port, 1234)
175+
t.is(decoded.host, '')
176+
})
177+
178+
test('encodeProbeResponse - max valid port', function (t) {
179+
const encoded = encodeProbeResponse({ port: 65535 })
180+
const decoded = decodeProbeResponse(encoded)
181+
182+
t.is(decoded.port, 65535)
183+
})
184+
185+
test('encodeHeader - max valid mode byte', function (t) {
186+
const cap = Buffer.alloc(32)
187+
const header = encodeHeader(cap, 255)
188+
t.is(header[32], 255)
189+
})

0 commit comments

Comments
 (0)