Skip to content

Commit 10f22e9

Browse files
committed
test: added test for generate-otp.ts
1 parent fe35192 commit 10f22e9

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

test/security/generate-otp.test.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { expect, test, describe } from 'bun:test'
2+
import { generateOTP } from '../../src/func/security'
3+
4+
describe('generateOTP', () => {
5+
// Test default behavior
6+
describe('Default Parameters', () => {
7+
test('should generate 4-digit OTP by default', () => {
8+
const otp = generateOTP()
9+
expect(otp).toHaveLength(4)
10+
expect(otp).toMatch(/^\d{4}$/)
11+
})
12+
})
13+
14+
// Test all valid lengths
15+
describe('Valid Lengths', () => {
16+
test('should generate 4-digit OTP when length is 4', () => {
17+
const otp = generateOTP(4)
18+
expect(otp).toHaveLength(4)
19+
expect(otp).toMatch(/^\d{4}$/)
20+
})
21+
22+
test('should generate 6-digit OTP when length is 6', () => {
23+
const otp = generateOTP(6)
24+
expect(otp).toHaveLength(6)
25+
expect(otp).toMatch(/^\d{6}$/)
26+
})
27+
28+
test('should generate 8-digit OTP when length is 8', () => {
29+
const otp = generateOTP(8)
30+
expect(otp).toHaveLength(8)
31+
expect(otp).toMatch(/^\d{8}$/)
32+
})
33+
})
34+
35+
// Test randomness
36+
describe('Randomness', () => {
37+
test('should generate different OTPs on subsequent calls', () => {
38+
const otps = new Set()
39+
for (let i = 0; i < 100; i++) {
40+
otps.add(generateOTP(4))
41+
}
42+
// With true randomness, it's highly unlikely to get the same OTP in 100 tries
43+
expect(otps.size).toBeGreaterThan(90)
44+
})
45+
46+
test('should include all possible digits (0-9)', () => {
47+
const otps: string[] = []
48+
for (let i = 0; i < 100; i++) {
49+
otps.push(generateOTP(8))
50+
}
51+
const allDigits = otps.join('').split('')
52+
const uniqueDigits = new Set(allDigits)
53+
expect(uniqueDigits.size).toBe(10) // Should have all digits 0-9
54+
})
55+
})
56+
57+
// Test distribution
58+
describe('Distribution', () => {
59+
test('should generate roughly uniform distribution of digits', () => {
60+
const digitCounts: { [key: string]: number } = {}
61+
const iterations = 1000
62+
63+
// Generate many OTPs and count digit occurrences
64+
for (let i = 0; i < iterations; i++) {
65+
const otp = generateOTP(8)
66+
for (const digit of otp) {
67+
digitCounts[digit] = (digitCounts[digit] || 0) + 1
68+
}
69+
}
70+
71+
// Each digit should appear roughly the same number of times
72+
// Allow for some variation (±20% from expected)
73+
const expectedCount = (iterations * 8) / 10 // Total digits / 10 (for each possible digit)
74+
const margin = expectedCount * 0.2
75+
76+
for (let i = 0; i < 10; i++) {
77+
const count = digitCounts[i] || 0
78+
expect(count).toBeGreaterThan(expectedCount - margin)
79+
expect(count).toBeLessThan(expectedCount + margin)
80+
}
81+
})
82+
})
83+
84+
// Test leading zeros
85+
describe('Leading Zeros', () => {
86+
test('should preserve leading zeros', () => {
87+
let foundLeadingZero = false
88+
for (let i = 0; i < 100; i++) {
89+
const otp = generateOTP(4)
90+
if (otp.startsWith('0')) {
91+
foundLeadingZero = true
92+
break
93+
}
94+
}
95+
expect(foundLeadingZero).toBe(true)
96+
})
97+
})
98+
99+
// Test type safety
100+
describe('Type Safety', () => {
101+
test('should not accept invalid lengths', () => {
102+
// @ts-expect-error - Testing invalid input
103+
expect(() => generateOTP(5)).toThrow()
104+
// @ts-expect-error - Testing invalid input
105+
expect(() => generateOTP(7)).toThrow()
106+
// @ts-expect-error - Testing invalid input
107+
expect(() => generateOTP(0)).toThrow()
108+
})
109+
})
110+
111+
// Performance test
112+
describe('Performance', () => {
113+
test('should generate OTP quickly', () => {
114+
const start = performance.now()
115+
for (let i = 0; i < 1000; i++) {
116+
generateOTP(8)
117+
}
118+
const end = performance.now()
119+
const duration = end - start
120+
121+
// Should generate 1000 OTPs in less than 100ms
122+
expect(duration).toBeLessThan(100)
123+
})
124+
})
125+
})

0 commit comments

Comments
 (0)