mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
feat(domain): add SlugValidator with comprehensive validation rules
This commit is contained in:
parent
95c8c31561
commit
351829e1a9
3 changed files with 98 additions and 0 deletions
|
|
@ -15,5 +15,10 @@
|
|||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.iflytek.skillhub.domain.namespace;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SlugValidator {
|
||||
|
||||
private static final int MIN_LENGTH = 2;
|
||||
private static final int MAX_LENGTH = 64;
|
||||
private static final Pattern SLUG_PATTERN = Pattern.compile("^[a-z0-9]([a-z0-9-]*[a-z0-9])?$");
|
||||
private static final Set<String> RESERVED_SLUGS = Set.of(
|
||||
"admin", "api", "dashboard", "search", "auth",
|
||||
"me", "global", "system", "static", "assets", "health"
|
||||
);
|
||||
|
||||
public static void validate(String slug) {
|
||||
if (slug == null || slug.isBlank()) {
|
||||
throw new IllegalArgumentException("Slug cannot be null or blank");
|
||||
}
|
||||
if (slug.length() < MIN_LENGTH || slug.length() > MAX_LENGTH) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Slug length must be between %d and %d characters", MIN_LENGTH, MAX_LENGTH));
|
||||
}
|
||||
if (!SLUG_PATTERN.matcher(slug).matches()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Slug must contain only lowercase alphanumeric characters and hyphens, " +
|
||||
"and must start and end with an alphanumeric character");
|
||||
}
|
||||
if (slug.contains("--")) {
|
||||
throw new IllegalArgumentException("Slug cannot contain consecutive hyphens");
|
||||
}
|
||||
if (RESERVED_SLUGS.contains(slug)) {
|
||||
throw new IllegalArgumentException("Slug '" + slug + "' is reserved and cannot be used");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.iflytek.skillhub.domain.namespace;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SlugValidatorTest {
|
||||
@Test
|
||||
void shouldAcceptValidSlug() {
|
||||
assertDoesNotThrow(() -> SlugValidator.validate("my-namespace"));
|
||||
assertDoesNotThrow(() -> SlugValidator.validate("ab"));
|
||||
assertDoesNotThrow(() -> SlugValidator.validate("test123"));
|
||||
assertDoesNotThrow(() -> SlugValidator.validate("my-team-2024"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectTooShort() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("a"));
|
||||
assertTrue(ex.getMessage().contains("length"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectTooLong() {
|
||||
String longSlug = "a".repeat(65);
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate(longSlug));
|
||||
assertTrue(ex.getMessage().contains("length"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectUpperCase() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("MyNamespace"));
|
||||
assertTrue(ex.getMessage().contains("lowercase"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectStartingWithHyphen() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("-namespace"));
|
||||
assertTrue(ex.getMessage().contains("alphanumeric"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectEndingWithHyphen() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("namespace-"));
|
||||
assertTrue(ex.getMessage().contains("alphanumeric"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectDoubleHyphen() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("my--namespace"));
|
||||
assertTrue(ex.getMessage().contains("consecutive"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectReservedWords() {
|
||||
assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("admin"));
|
||||
assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("api"));
|
||||
assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("global"));
|
||||
assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("system"));
|
||||
}
|
||||
@Test
|
||||
void shouldRejectSpecialCharacters() {
|
||||
Exception ex = assertThrows(IllegalArgumentException.class, () -> SlugValidator.validate("my_namespace"));
|
||||
assertTrue(ex.getMessage().contains("lowercase") || ex.getMessage().contains("alphanumeric"));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue