Skip to content

Commit 306e160

Browse files
committed
Améliorer la documentation du schéma InitInfoPart : ajouter des commentaires explicatifs pour les propriétés sentDate et initDate.
1 parent 9d82239 commit 306e160

File tree

3 files changed

+214
-0
lines changed

3 files changed

+214
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import { isIPv4 } from '~/_common/functions/is-ipv4';
2+
3+
describe('isIPv4', () => {
4+
describe('Valid IPv4 addresses', () => {
5+
it('should accept standard IPv4 addresses', () => {
6+
const validAddresses = [
7+
'192.168.1.1',
8+
'10.0.0.1',
9+
'172.16.254.1',
10+
'127.0.0.1',
11+
'8.8.8.8',
12+
'1.1.1.1'
13+
];
14+
15+
validAddresses.forEach(address => {
16+
expect(isIPv4(address)).toBe(true);
17+
});
18+
});
19+
20+
it('should accept edge case valid addresses', () => {
21+
const edgeCases = [
22+
'0.0.0.0', // Network address
23+
'255.255.255.255', // Broadcast address
24+
'255.0.0.0', // Class A network mask
25+
'255.255.0.0', // Class B network mask
26+
'255.255.255.0', // Class C network mask
27+
'192.168.0.1', // Private network
28+
'10.255.255.254', // Private network edge
29+
'172.31.255.255' // Private network edge
30+
];
31+
32+
edgeCases.forEach(address => {
33+
expect(isIPv4(address)).toBe(true);
34+
});
35+
});
36+
37+
it('should accept addresses with leading zeros (current regex behavior)', () => {
38+
const leadingZeroAddresses = [
39+
'192.168.001.001',
40+
'010.000.000.001',
41+
'001.002.003.004',
42+
'000.000.000.000'
43+
];
44+
45+
leadingZeroAddresses.forEach(address => {
46+
expect(isIPv4(address)).toBe(true);
47+
});
48+
});
49+
});
50+
51+
describe('Invalid IPv4 addresses', () => {
52+
it('should reject addresses with octets > 255', () => {
53+
const invalidAddresses = [
54+
'256.1.1.1',
55+
'192.256.1.1',
56+
'192.168.256.1',
57+
'192.168.1.256',
58+
'300.168.1.1',
59+
'192.300.1.1',
60+
'999.999.999.999'
61+
];
62+
63+
invalidAddresses.forEach(address => {
64+
expect(isIPv4(address)).toBe(false);
65+
});
66+
});
67+
68+
it('should reject addresses with wrong number of octets', () => {
69+
const wrongOctetCount = [
70+
'192.168.1', // Too few
71+
'192.168', // Too few
72+
'192', // Too few
73+
'192.168.1.1.1', // Too many
74+
'192.168.1.1.1.1', // Too many
75+
'1.2.3.4.5.6.7.8' // Way too many
76+
];
77+
78+
wrongOctetCount.forEach(address => {
79+
expect(isIPv4(address)).toBe(false);
80+
});
81+
});
82+
83+
it('should reject addresses with negative numbers', () => {
84+
const negativeNumbers = [
85+
'-1.168.1.1',
86+
'192.-1.1.1',
87+
'192.168.-1.1',
88+
'192.168.1.-1',
89+
'-192.168.1.1'
90+
];
91+
92+
negativeNumbers.forEach(address => {
93+
expect(isIPv4(address)).toBe(false);
94+
});
95+
});
96+
97+
it('should reject addresses with non-numeric characters', () => {
98+
const nonNumeric = [
99+
'a.b.c.d',
100+
'192.168.a.1',
101+
'192.168.1.a',
102+
'192.168.1.1a',
103+
'localhost',
104+
'192.168.1.1/24',
105+
'192.168.1.1:80',
106+
'192.168.1.1 ',
107+
' 192.168.1.1'
108+
];
109+
110+
nonNumeric.forEach(address => {
111+
expect(isIPv4(address)).toBe(false);
112+
});
113+
});
114+
115+
it('should reject empty and malformed strings', () => {
116+
const malformed = [
117+
'',
118+
' ',
119+
'...',
120+
'192..1.1',
121+
'192.168..1',
122+
'192.168.1.',
123+
'.192.168.1.1',
124+
'192.168.1.1.',
125+
'192,168,1,1',
126+
'192 168 1 1'
127+
];
128+
129+
malformed.forEach(address => {
130+
expect(isIPv4(address)).toBe(false);
131+
});
132+
});
133+
134+
it('should reject IPv6 addresses', () => {
135+
const ipv6Addresses = [
136+
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
137+
'2001:db8:85a3::8a2e:370:7334',
138+
'::1',
139+
'::',
140+
'fe80::1'
141+
];
142+
143+
ipv6Addresses.forEach(address => {
144+
expect(isIPv4(address)).toBe(false);
145+
});
146+
});
147+
});
148+
149+
describe('RFC compliance edge cases', () => {
150+
it('should handle boundary values correctly', () => {
151+
// Test exact boundary values
152+
expect(isIPv4('0.0.0.0')).toBe(true);
153+
expect(isIPv4('255.255.255.255')).toBe(true);
154+
155+
// Test just over boundary
156+
expect(isIPv4('256.0.0.0')).toBe(false);
157+
expect(isIPv4('0.256.0.0')).toBe(false);
158+
expect(isIPv4('0.0.256.0')).toBe(false);
159+
expect(isIPv4('0.0.0.256')).toBe(false);
160+
});
161+
162+
it('should handle various number formats', () => {
163+
// Single digits
164+
expect(isIPv4('1.2.3.4')).toBe(true);
165+
166+
// Double digits
167+
expect(isIPv4('12.34.56.78')).toBe(true);
168+
169+
// Triple digits
170+
expect(isIPv4('123.234.200.199')).toBe(true);
171+
172+
// Mixed lengths
173+
expect(isIPv4('1.22.333.4')).toBe(false); // 333 > 255
174+
expect(isIPv4('1.22.200.4')).toBe(true);
175+
});
176+
});
177+
178+
describe('Performance and edge case testing', () => {
179+
it('should handle very long strings efficiently', () => {
180+
const longString = '1'.repeat(1000) + '.1.1.1';
181+
expect(isIPv4(longString)).toBe(false);
182+
});
183+
184+
it('should handle special characters', () => {
185+
const specialChars = [
186+
'192.168.1.1\n',
187+
'192.168.1.1\t',
188+
'192.168.1.1\r',
189+
'192.168.1.1\0'
190+
];
191+
192+
specialChars.forEach(address => {
193+
expect(isIPv4(address)).toBe(false);
194+
});
195+
});
196+
});
197+
});

src/_common/functions/is-ipv4.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function isIPv4(address: string): boolean {
2+
return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address);
3+
}

src/management/identities/_schemas/_parts/init-info.part.schema.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
22
import { Document } from 'mongoose';
33

4+
/**
5+
* Information related to the account/identity initialization process.
6+
*
7+
* This schema is stored as a subdocument (no own _id) and
8+
* keeps track of the initialization timestamps.
9+
*/
410
@Schema({ _id: false })
511
export class InitInfoPart extends Document {
12+
/**
13+
* Date when the initialization request/link was sent (email, SMS, etc.).
14+
* Undefined if no request has been sent yet.
15+
*/
616
@Prop({ type: Date })
717
public sentDate?: Date;
818

19+
/**
20+
* Date when the user actually completed the initialization.
21+
* Undefined if the initialization has not been completed yet.
22+
*/
923
@Prop({ type: Date })
1024
public initDate?: Date;
1125
}

0 commit comments

Comments
 (0)