Skip to content

Commit 3aaba51

Browse files
committed
feat: Add more generators for more realistic data in payloads
1 parent b136536 commit 3aaba51

40 files changed

Lines changed: 2316 additions & 0 deletions
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.util.List;
12+
13+
/**
14+
* A generator class implementing interfaces for generating valid and invalid API key data formats.
15+
* It also implements the OpenAPIFormat interface.
16+
*/
17+
@Singleton
18+
public class APIKeyGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
19+
20+
private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
21+
22+
@Override
23+
public Object generate(Schema<?> schema) {
24+
// Generate API key in common formats
25+
int format = CommonUtils.random().nextInt(3);
26+
27+
return switch (format) {
28+
case 0 -> generateSimpleKey(32); // Simple alphanumeric
29+
case 1 -> "sk_live_" + generateSimpleKey(24); // Stripe-style
30+
default -> "AIza" + generateSimpleKey(35); // Google-style
31+
};
32+
}
33+
34+
private String generateSimpleKey(int length) {
35+
StringBuilder key = new StringBuilder();
36+
for (int i = 0; i < length; i++) {
37+
key.append(CHARS.charAt(CommonUtils.random().nextInt(CHARS.length())));
38+
}
39+
return key.toString();
40+
}
41+
42+
@Override
43+
public boolean appliesTo(String format, String propertyName) {
44+
String sanitized = PropertySanitizer.sanitize(propertyName);
45+
return "apikey".equalsIgnoreCase(format) ||
46+
sanitized.contains("apikey") ||
47+
(sanitized.contains("api") && sanitized.contains("key"));
48+
}
49+
50+
@Override
51+
public String getAlmostValidValue() {
52+
// Too short to be valid
53+
return "sk_live_abc123";
54+
}
55+
56+
@Override
57+
public String getTotallyWrongValue() {
58+
return "invalid-key";
59+
}
60+
61+
@Override
62+
public List<String> matchingFormats() {
63+
return List.of("apikey", "api-key", "api_key");
64+
}
65+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.util.Base64;
12+
import java.util.List;
13+
14+
/**
15+
* A generator class implementing interfaces for generating valid and invalid Base64 encoded data formats.
16+
* It also implements the OpenAPIFormat interface.
17+
*/
18+
@Singleton
19+
public class Base64Generator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
20+
21+
@Override
22+
public Object generate(Schema<?> schema) {
23+
// Generate random bytes and encode to Base64
24+
int length = 16 + CommonUtils.random().nextInt(32); // 16-48 bytes
25+
byte[] randomBytes = new byte[length];
26+
CommonUtils.random().nextBytes(randomBytes);
27+
28+
return Base64.getEncoder().encodeToString(randomBytes);
29+
}
30+
31+
@Override
32+
public boolean appliesTo(String format, String propertyName) {
33+
String sanitized = PropertySanitizer.sanitize(propertyName);
34+
return "base64".equalsIgnoreCase(format) ||
35+
"byte".equalsIgnoreCase(format) || // OpenAPI uses 'byte' for base64
36+
sanitized.contains("base64") ||
37+
sanitized.endsWith("encoded");
38+
}
39+
40+
@Override
41+
public String getAlmostValidValue() {
42+
// Invalid Base64 character '@'
43+
return "SGVsbG8gV29ybGQ@";
44+
}
45+
46+
@Override
47+
public String getTotallyWrongValue() {
48+
return "not base64!@#$%";
49+
}
50+
51+
@Override
52+
public List<String> matchingFormats() {
53+
return List.of("base64", "byte");
54+
}
55+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.util.List;
12+
13+
/**
14+
* A generator class implementing interfaces for generating valid and invalid cron expression data formats.
15+
* It also implements the OpenAPIFormat interface.
16+
*/
17+
@Singleton
18+
public class CronExpressionGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
19+
20+
private static final List<String> COMMON_CRON_EXPRESSIONS = List.of(
21+
"0 0 * * *", // Daily at midnight
22+
"0 */6 * * *", // Every 6 hours
23+
"*/15 * * * *", // Every 15 minutes
24+
"0 9 * * 1", // Every Monday at 9 AM
25+
"0 0 1 * *", // First day of month at midnight
26+
"0 12 * * 1-5", // Weekdays at noon
27+
"0 0 * * 0", // Every Sunday at midnight
28+
"30 2 * * *", // Daily at 2:30 AM
29+
"0 */4 * * *", // Every 4 hours
30+
"0 0 1 1 *" // January 1st at midnight
31+
);
32+
33+
@Override
34+
public Object generate(Schema<?> schema) {
35+
return CommonUtils.selectRandom(COMMON_CRON_EXPRESSIONS);
36+
}
37+
38+
@Override
39+
public boolean appliesTo(String format, String propertyName) {
40+
String sanitized = PropertySanitizer.sanitize(propertyName);
41+
return "cron".equalsIgnoreCase(format) ||
42+
sanitized.contains("cron") ||
43+
(sanitized.contains("schedule") && sanitized.contains("expression"));
44+
}
45+
46+
@Override
47+
public String getAlmostValidValue() {
48+
// Invalid minute value (60)
49+
return "60 0 * * *";
50+
}
51+
52+
@Override
53+
public String getTotallyWrongValue() {
54+
return "not a cron";
55+
}
56+
57+
@Override
58+
public List<String> matchingFormats() {
59+
return List.of("cron", "cron-expression");
60+
}
61+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.util.List;
12+
13+
/**
14+
* A generator class implementing interfaces for generating valid and invalid hex color code data formats.
15+
* It also implements the OpenAPIFormat interface.
16+
*/
17+
@Singleton
18+
public class HexColorGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
19+
20+
@Override
21+
public Object generate(Schema<?> schema) {
22+
// Generate random hex color
23+
int r = CommonUtils.random().nextInt(256);
24+
int g = CommonUtils.random().nextInt(256);
25+
int b = CommonUtils.random().nextInt(256);
26+
27+
return String.format("#%02X%02X%02X", r, g, b);
28+
}
29+
30+
@Override
31+
public boolean appliesTo(String format, String propertyName) {
32+
String sanitized = PropertySanitizer.sanitize(propertyName);
33+
return "hexcolor".equalsIgnoreCase(format) ||
34+
"color".equalsIgnoreCase(format) ||
35+
sanitized.contains("hexcolor") ||
36+
sanitized.contains("colorhex") ||
37+
(sanitized.endsWith("color") && !sanitized.contains("multicolor"));
38+
}
39+
40+
@Override
41+
public String getAlmostValidValue() {
42+
// Missing one hex digit
43+
return "#FF00F";
44+
}
45+
46+
@Override
47+
public String getTotallyWrongValue() {
48+
return "red";
49+
}
50+
51+
@Override
52+
public List<String> matchingFormats() {
53+
return List.of("hexcolor", "hex-color", "color");
54+
}
55+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.time.LocalDate;
12+
import java.time.ZoneId;
13+
import java.util.List;
14+
15+
/**
16+
* A generator class implementing interfaces for generating valid and invalid invoice number data formats.
17+
* It also implements the OpenAPIFormat interface.
18+
*/
19+
@Singleton
20+
public class InvoiceNumberGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
21+
22+
@Override
23+
public Object generate(Schema<?> schema) {
24+
// Generate invoice number in common formats
25+
int format = CommonUtils.random().nextInt(4);
26+
int year = LocalDate.now(ZoneId.systemDefault()).getYear();
27+
int sequence = 1000 + CommonUtils.random().nextInt(9000);
28+
29+
return switch (format) {
30+
case 0 -> "INV-" + year + "-" + sequence; // INV-2024-1234
31+
case 1 -> "INV" + String.format("%06d", sequence); // INV001234
32+
case 2 -> year + "/" + sequence; // 2024/1234
33+
default -> String.format("%04d-%04d", year, sequence); // 2024-1234
34+
};
35+
}
36+
37+
@Override
38+
public boolean appliesTo(String format, String propertyName) {
39+
String sanitized = PropertySanitizer.sanitize(propertyName);
40+
return "invoice".equalsIgnoreCase(format) ||
41+
"invoicenumber".equalsIgnoreCase(format) ||
42+
(sanitized.contains("invoice") && (sanitized.contains("number") || sanitized.contains("id")));
43+
}
44+
45+
@Override
46+
public String getAlmostValidValue() {
47+
// Missing year
48+
return "INV-1234";
49+
}
50+
51+
@Override
52+
public String getTotallyWrongValue() {
53+
return "invoice";
54+
}
55+
56+
@Override
57+
public List<String> matchingFormats() {
58+
return List.of("invoice", "invoice-number", "invoicenumber");
59+
}
60+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package dev.dochia.cli.core.generator.format.impl;
2+
3+
import dev.dochia.cli.core.generator.format.api.InvalidDataFormatGenerator;
4+
import dev.dochia.cli.core.generator.format.api.OpenAPIFormat;
5+
import dev.dochia.cli.core.generator.format.api.PropertySanitizer;
6+
import dev.dochia.cli.core.generator.format.api.ValidDataFormatGenerator;
7+
import dev.dochia.cli.core.util.CommonUtils;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import jakarta.inject.Singleton;
10+
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.Base64;
13+
import java.util.List;
14+
15+
/**
16+
* A generator class implementing interfaces for generating valid and invalid JWT (JSON Web Token) data formats.
17+
* It also implements the OpenAPIFormat interface.
18+
*/
19+
@Singleton
20+
public class JWTGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator, OpenAPIFormat {
21+
22+
@Override
23+
public Object generate(Schema<?> schema) {
24+
// Generate a fake JWT structure: header.payload.signature
25+
String header = Base64.getUrlEncoder().withoutPadding()
26+
.encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes(StandardCharsets.UTF_8));
27+
28+
String payload = Base64.getUrlEncoder().withoutPadding()
29+
.encodeToString(("{\"sub\":\"" + CommonUtils.faker().internet().uuid() +
30+
"\",\"name\":\"" + CommonUtils.faker().name().fullName() +
31+
"\",\"iat\":" + (System.currentTimeMillis() / 1000) + "}").getBytes(StandardCharsets.UTF_8));
32+
33+
// Generate a fake signature (random bytes)
34+
byte[] signatureBytes = new byte[32];
35+
CommonUtils.random().nextBytes(signatureBytes);
36+
String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes);
37+
38+
return header + "." + payload + "." + signature;
39+
}
40+
41+
@Override
42+
public boolean appliesTo(String format, String propertyName) {
43+
String sanitized = PropertySanitizer.sanitize(propertyName);
44+
return "jwt".equalsIgnoreCase(format) ||
45+
sanitized.contains("jwt") ||
46+
sanitized.contains("jsonwebtoken") ||
47+
(sanitized.endsWith("token") && (sanitized.contains("auth") || sanitized.contains("bearer")));
48+
}
49+
50+
@Override
51+
public String getAlmostValidValue() {
52+
// Missing signature part
53+
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";
54+
}
55+
56+
@Override
57+
public String getTotallyWrongValue() {
58+
return "not.a.valid.jwt.token";
59+
}
60+
61+
@Override
62+
public List<String> matchingFormats() {
63+
return List.of("jwt", "jsonwebtoken", "bearer-token");
64+
}
65+
}

0 commit comments

Comments
 (0)