Validity checks on NamespaceIDs

This commit is contained in:
jglrxavpok 2020-10-18 18:27:57 +02:00
parent 19ab2cbd50
commit 26ce63763a
2 changed files with 87 additions and 2 deletions

View File

@ -1,17 +1,18 @@
package net.minestom.server.utils; package net.minestom.server.utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern;
/** /**
* Represents a namespaced ID * Represents a namespaced ID
* https://minecraft.gamepedia.com/Namespaced_ID * https://minecraft.gamepedia.com/Namespaced_ID
* <p>
* TODO: Implement validity conditions
*/ */
public class NamespaceID implements CharSequence { public class NamespaceID implements CharSequence {
private static final Int2ObjectOpenHashMap<NamespaceID> cache = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectOpenHashMap<NamespaceID> cache = new Int2ObjectOpenHashMap<>();
private static final String legalLetters = "[0123456789abcdefghijklmnopqrstuvwxyz_-]+";
private final String domain; private final String domain;
private final String path; private final String path;
@ -28,6 +29,7 @@ public class NamespaceID implements CharSequence {
final int index = namespaceID.indexOf(':'); final int index = namespaceID.indexOf(':');
if (index < 0) if (index < 0)
return "minecraft"; return "minecraft";
assert namespaceID.indexOf(':', index+1) == -1: "Namespace ID can only have at most one colon ':' ("+namespaceID+")";
return namespaceID.substring(0, index); return namespaceID.substring(0, index);
} }
@ -42,6 +44,7 @@ public class NamespaceID implements CharSequence {
final int index = namespaceID.indexOf(':'); final int index = namespaceID.indexOf(':');
if (index < 0) if (index < 0)
return namespaceID; return namespaceID;
assert namespaceID.indexOf(':', index+1) == -1: "Namespace ID can only have at most one colon ':' ("+namespaceID+")";
return namespaceID.substring(index + 1); return namespaceID.substring(index + 1);
} }
@ -68,12 +71,20 @@ public class NamespaceID implements CharSequence {
this.path = path.substring(index + 1); this.path = path.substring(index + 1);
} }
this.full = toString(); this.full = toString();
validate();
} }
private NamespaceID(String domain, String path) { private NamespaceID(String domain, String path) {
this.domain = domain; this.domain = domain;
this.path = path; this.path = path;
this.full = toString(); this.full = toString();
validate();
}
private void validate() {
assert !domain.contains(".") && !domain.contains("/") : "Domain cannot contain a dot nor a slash character (" + full+ ")";
assert domain.matches(legalLetters) : "Illegal character in domain ("+full+"). Must match "+legalLetters;
assert path.matches(legalLetters) : "Illegal character in path ("+full+"). Must match "+legalLetters;
} }
public String getDomain() { public String getDomain() {
@ -113,6 +124,7 @@ public class NamespaceID implements CharSequence {
return full.subSequence(start, end); return full.subSequence(start, end);
} }
@NotNull
@Override @Override
public String toString() { public String toString() {
return domain + ":" + path; return domain + ":" + path;

View File

@ -0,0 +1,73 @@
package misc;
import net.minestom.server.utils.NamespaceID;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class TestNamespaceIDValidity {
@Test
public void noErrorWithCorrectFormat() {
NamespaceID.from("minecraft:any");
}
@Test
public void atMostOneColon() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft:block:wool");
});
}
@Test
public void noSlashInDomain() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft/java_edition:any");
});
}
@Test
public void noDotInDomain() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft.java:game");
});
}
@Test
public void noUppercase() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("Minecraft:any");
});
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft:Any");
});
}
@Test
public void noSpace() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft:a n y");
});
}
@Test
public void onlyLatinLowercase() {
assertThrows(AssertionError.class, () -> {
NamespaceID.from("Minecraft:voilà");
});
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft:où_ça");
});
assertThrows(AssertionError.class, () -> {
NamespaceID.from("minecraft:schrödingers_var");
});
}
@Test
public void numbersAllowed() {
NamespaceID.from("0xc1:468786471");
}
}