Skip to content

Commit bec273d

Browse files
feat(core): add IP and username mock generators (#16)
* feat(core): add IP and username mock generators - Add IP generator supporting both IPv4 and IPv6 - Add username generator with customizable options - Include comprehensive test coverage for new generators * feat(core): add documentation for IP generator in smart-mock
1 parent 0366abf commit bec273d

File tree

4 files changed

+230
-2
lines changed

4 files changed

+230
-2
lines changed

package-lock.json

Lines changed: 38 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
"vite": "npm:rolldown-vite@7.2.5"
7777
},
7878
"dependencies": {
79-
"axios": "^1.13.2"
79+
"@faker-js/faker": "^10.1.0",
80+
"axios": "^1.13.2",
81+
"unique-username-generator": "^1.5.1"
8082
}
8183
}

src/core/engine/smart-mock.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import type { MockGenerator } from '../types'
2+
import { generateUsername } from 'unique-username-generator';
3+
import { faker } from '@faker-js/faker';
4+
25

36
const generators: Record<string, MockGenerator> = {
47

@@ -16,6 +19,44 @@ const generators: Record<string, MockGenerator> = {
1619
const max = parseInt(maxStr, 10);
1720
return Math.floor(Math.random() * (max - min + 1)) + min;
1821
},
22+
// Username generator using unique-username-generator
23+
// Arguments: separator, randomDigits, maxLength, dictType
24+
// Example: @username("-", 2, 20) or @username() for defaults
25+
username: (args?: string) => {
26+
if (!args) {
27+
return generateUsername();
28+
}
29+
30+
const params = args.split(',').map(s => s.trim().replace(/^["']|["']$/g, ''));
31+
const separator = params[0] || '';
32+
const randomDigits = params[1] ? parseInt(params[1], 10) : 0;
33+
const maxLength = params[2] ? parseInt(params[2], 10) : undefined;
34+
const dictType = params[3] || undefined;
35+
36+
if (dictType) {
37+
return generateUsername(separator, randomDigits, maxLength, dictType);
38+
} else if (maxLength) {
39+
return generateUsername(separator, randomDigits, maxLength);
40+
} else if (randomDigits) {
41+
return generateUsername(separator, randomDigits);
42+
} else if (separator) {
43+
return generateUsername(separator);
44+
} else {
45+
return generateUsername();
46+
}
47+
},
48+
49+
// IP generator for v4 and v6
50+
// Arguments: version
51+
// Example: @ip(v6) or @ip(IPv6) for IPv6, defaults to IPv4
52+
ip:(args?:string)=>{
53+
if(args == "6" || args =="IPv6" || args == "ipv6" || args == "v6"){
54+
return faker.internet.ipv6();
55+
}else{
56+
// Default to IPv4
57+
return faker.internet.ipv4();
58+
}
59+
},
1960

2061
string: (args?: string) => {
2162
const length = args ? parseInt(args, 10) : 10;

test/core/engine/smart-mock.test.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,152 @@ describe('generateMockData', () => {
216216
const longTextWords = result.longText.split(' ');
217217
expect(longTextWords.length).toBeGreaterThanOrEqual(20);
218218
});
219+
220+
it('should generate username with default settings', () => {
221+
const template = {
222+
username: '@username'
223+
};
224+
const result = generateMockData(template);
225+
226+
expect(result.username).toBeDefined();
227+
expect(typeof result.username).toBe('string');
228+
expect(result.username.length).toBeGreaterThan(0);
229+
});
230+
231+
it('should generate username with custom separator', () => {
232+
const template = {
233+
username: '@username(_)'
234+
};
235+
const result = generateMockData(template);
236+
237+
expect(result.username).toBeDefined();
238+
expect(typeof result.username).toBe('string');
239+
// Username with underscore separator should contain underscores
240+
expect(result.username).toMatch(/[_]/);
241+
});
242+
243+
it('should generate username with separator and random digits', () => {
244+
const template = {
245+
username: '@username(-,3)'
246+
};
247+
const result = generateMockData(template);
248+
249+
expect(result.username).toBeDefined();
250+
expect(typeof result.username).toBe('string');
251+
// Should contain dash separator and digits
252+
expect(result.username).toMatch(/[-]/);
253+
expect(result.username).toMatch(/\d+/);
254+
});
255+
256+
it('should generate username with separator, random digits, and max length', () => {
257+
const template = {
258+
username: '@username(_,2,15)'
259+
};
260+
const result = generateMockData(template);
261+
262+
expect(result.username).toBeDefined();
263+
expect(typeof result.username).toBe('string');
264+
expect(result.username.length).toBeLessThanOrEqual(15);
265+
});
266+
267+
it('should generate username with all parameters including dictType', () => {
268+
const template = {
269+
username: '@username(-,3,20,adjectives)'
270+
};
271+
const result = generateMockData(template);
272+
273+
expect(result.username).toBeDefined();
274+
expect(typeof result.username).toBe('string');
275+
expect(result.username.length).toBeLessThanOrEqual(20);
276+
});
277+
278+
it('should generate IPv4 address by default', () => {
279+
const template = {
280+
ip: '@ip'
281+
};
282+
const result = generateMockData(template);
283+
284+
expect(result.ip).toBeDefined();
285+
expect(typeof result.ip).toBe('string');
286+
// IPv4 format: xxx.xxx.xxx.xxx
287+
expect(result.ip).toMatch(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
288+
});
289+
290+
it('should generate IPv6 address with "6" argument', () => {
291+
const template = {
292+
ip: '@ip(6)'
293+
};
294+
const result = generateMockData(template);
295+
296+
expect(result.ip).toBeDefined();
297+
expect(typeof result.ip).toBe('string');
298+
// IPv6 format contains colons
299+
expect(result.ip).toMatch(/:/);
300+
});
301+
302+
it('should generate IPv6 address with "IPv6" argument', () => {
303+
const template = {
304+
ip: '@ip(IPv6)'
305+
};
306+
const result = generateMockData(template);
307+
308+
expect(result.ip).toBeDefined();
309+
expect(typeof result.ip).toBe('string');
310+
expect(result.ip).toMatch(/:/);
311+
});
312+
313+
it('should generate IPv6 address with "ipv6" argument', () => {
314+
const template = {
315+
ip: '@ip(ipv6)'
316+
};
317+
const result = generateMockData(template);
318+
319+
expect(result.ip).toBeDefined();
320+
expect(typeof result.ip).toBe('string');
321+
expect(result.ip).toMatch(/:/);
322+
});
323+
324+
it('should generate IPv6 address with "v6" argument', () => {
325+
const template = {
326+
ip: '@ip(v6)'
327+
};
328+
const result = generateMockData(template);
329+
330+
expect(result.ip).toBeDefined();
331+
expect(typeof result.ip).toBe('string');
332+
expect(result.ip).toMatch(/:/);
333+
});
334+
335+
it('should generate multiple usernames with different configurations', () => {
336+
const template = {
337+
user1: '@username',
338+
user2: '@username(-)',
339+
user3: '@username(_,4)'
340+
};
341+
const result = generateMockData(template);
342+
343+
expect(result.user1).toBeDefined();
344+
expect(result.user2).toBeDefined();
345+
expect(result.user3).toBeDefined();
346+
expect(result.user1).not.toBe(result.user2);
347+
});
348+
349+
it('should handle IP addresses in nested structures', () => {
350+
const template = {
351+
server: {
352+
ipv4: '@ip',
353+
ipv6: '@ip(6)'
354+
},
355+
'clients|2': {
356+
address: '@ip'
357+
}
358+
};
359+
const result = generateMockData(template);
360+
361+
expect(result.server.ipv4).toMatch(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
362+
expect(result.server.ipv6).toMatch(/:/);
363+
expect(result.clients).toHaveLength(2);
364+
expect(result.clients[0].address).toMatch(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
365+
expect(result.clients[1].address).toMatch(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
366+
});
219367
});

0 commit comments

Comments
 (0)