mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-12 16:37:38 +00:00
test: characterize method symbol info
This commit is contained in:
1 parent
257d0e4a04
commit
9859aa8a08
4 files changed
+254
No files matched your search
Vendored
+14
@@ -405,3 +405,17 @@ Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the untouche
|
||||
| --- | --- |
|
||||
| `ReferenceScalaMethodSymbolDescriptor` | `47731de0986ab2701a3d5acae0b0a93b24c979495c288383fcab4a925370c192` |
|
||||
| `ReferenceScalaMethodSymbolDescriptor$$anon$1` | `9fbfb463190e14a9be53a27add9d460d2e8e45bedb0054059806798aa098d2e1` |
|
||||
|
||||
### `ReferenceScalaMethodSymbolInfo`
|
||||
|
||||
`scala/codechicken/multipart/compat/ReferenceScalaMethodSymbolInfo.scala` freezes a Scala caller of
|
||||
`MethodSymbol.info`. Tests preserve the path-dependent return descriptor, virtual info-ID evaluation and failures.
|
||||
|
||||
Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the untouched dev jar at `257d0e4`
|
||||
(SHA-256 `1d671a402ec0fe06fcf44c0edbcca350372c05886ad2a7b3cb5fb8688ab95267`). Source SHA-256 is
|
||||
`53c16080dcd7fe271a9c89b2c869bcb8410baad88e72641d73668aea1cbfd8b8`. The frozen class file is under
|
||||
`src/test/resources/compat/`; do not regenerate it against the port.
|
||||
|
||||
| Class | SHA-256 |
|
||||
| --- | --- |
|
||||
| `ReferenceScalaMethodSymbolInfo` | `0d89ef63187efc9f7959e292ba8e6cee1f4b68794891b913c53c3e96032c869e` |
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package codechicken.multipart.compat
|
||||
|
||||
import codechicken.multipart.asm.ScalaSignature
|
||||
|
||||
class ReferenceScalaMethodSymbolInfo {
|
||||
def info(ref: ScalaSignature#MethodSymbol): ScalaSignature#TMethodType = ref.info
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package codechicken.multipart.asm;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import codechicken.multipart.asm.ScalaSignature.Bytes;
|
||||
import codechicken.multipart.asm.ScalaSignature.MethodSymbol;
|
||||
import codechicken.multipart.asm.ScalaSignature.SymbolRef;
|
||||
import codechicken.multipart.asm.ScalaSignature.TMethodType;
|
||||
|
||||
class ScalaSignatureMethodSymbolInfoTest {
|
||||
|
||||
private static final Fixture FIXTURE = new Fixture();
|
||||
|
||||
@Test
|
||||
void returnsEvaluatedMethodTypeAndNullLiterally() throws Throwable {
|
||||
TMethodType expected = method();
|
||||
ProbeSignature sig = signature(index -> index == 37 ? expected : null, new ArrayList<>());
|
||||
assertSame(expected, info(sig.new MethodSymbol(null, null, 0, 37)));
|
||||
assertNull(info(sig.new MethodSymbol(null, null, 0, -1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void readsInfoIdThenEvalOnEveryQuery() throws Throwable {
|
||||
List<String> calls = new ArrayList<>();
|
||||
TMethodType expected = method();
|
||||
ProbeSignature sig = signature(index -> expected, calls);
|
||||
MethodSymbol ref = sig.new MethodSymbol(null, null, 0, 0) {
|
||||
|
||||
@Override
|
||||
public int infoId() {
|
||||
calls.add("infoId");
|
||||
return 19;
|
||||
}
|
||||
};
|
||||
assertSame(expected, info(ref));
|
||||
assertSame(expected, info(ref));
|
||||
assertEquals(Arrays.asList("infoId", "eval:19", "infoId", "eval:19"), calls);
|
||||
}
|
||||
|
||||
@Test
|
||||
void changingInfoIdsAndResultsAreNotCached() throws Throwable {
|
||||
TMethodType first = method();
|
||||
TMethodType second = method();
|
||||
int[] query = { 0 };
|
||||
ProbeSignature sig = signature(index -> index == 4 ? first : second, new ArrayList<>());
|
||||
MethodSymbol ref = sig.new MethodSymbol(null, null, 0, 0) {
|
||||
|
||||
@Override
|
||||
public int infoId() {
|
||||
return query[0]++ == 0 ? 4 : 9;
|
||||
}
|
||||
};
|
||||
assertSame(first, info(ref));
|
||||
assertSame(second, info(ref));
|
||||
assertEquals(2, query[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAnEvaluatedNonMethodType() {
|
||||
ProbeSignature sig = signature(index -> "not a method type", new ArrayList<>());
|
||||
assertThrows(ClassCastException.class, () -> info(sig.new MethodSymbol(null, null, 0, 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failuresStopAtInfoIdOrEval() {
|
||||
RuntimeException failure = new IllegalStateException("method info lookup");
|
||||
List<String> calls = new ArrayList<>();
|
||||
ProbeSignature sig = signature(index -> {
|
||||
calls.add("value");
|
||||
throw failure;
|
||||
}, calls);
|
||||
|
||||
MethodSymbol idFailure = sig.new MethodSymbol(null, null, 0, 0) {
|
||||
|
||||
@Override
|
||||
public int infoId() {
|
||||
calls.add("infoId");
|
||||
throw failure;
|
||||
}
|
||||
};
|
||||
assertSame(failure, assertThrows(RuntimeException.class, () -> info(idFailure)));
|
||||
assertEquals(Arrays.asList("infoId"), calls);
|
||||
|
||||
calls.clear();
|
||||
MethodSymbol evalFailure = sig.new MethodSymbol(null, null, 0, 8) {
|
||||
|
||||
@Override
|
||||
public int infoId() {
|
||||
calls.add("infoId");
|
||||
return 8;
|
||||
}
|
||||
};
|
||||
assertSame(failure, assertThrows(RuntimeException.class, () -> info(evalFailure)));
|
||||
assertEquals(Arrays.asList("infoId", "eval:8", "value"), calls);
|
||||
}
|
||||
|
||||
@Test
|
||||
void infoDoesNotReadOtherSymbolOrMethodTypeMembers() throws Throwable {
|
||||
TMethodType expected = method();
|
||||
ProbeSignature sig = signature(index -> expected, new ArrayList<>());
|
||||
MethodSymbol ref = sig.new MethodSymbol(null, null, 0, 3) {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
throw new AssertionError("name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolRef owner() {
|
||||
throw new AssertionError("owner");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flags() {
|
||||
throw new AssertionError("flags");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String full() {
|
||||
throw new AssertionError("full");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jDesc() {
|
||||
throw new AssertionError("jDesc");
|
||||
}
|
||||
};
|
||||
assertSame(expected, info(ref));
|
||||
}
|
||||
|
||||
@Test
|
||||
void frozenScalaCallerKeepsItsReturnDescriptorAndNullReceiverFailure() throws Throwable {
|
||||
assertEquals(TMethodType.class, FIXTURE.returnType);
|
||||
assertThrows(NullPointerException.class, () -> info(null));
|
||||
}
|
||||
|
||||
private static TMethodType method() {
|
||||
return (TMethodType) java.lang.reflect.Proxy.newProxyInstance(
|
||||
TMethodType.class.getClassLoader(),
|
||||
new Class<?>[] { TMethodType.class },
|
||||
(proxy, method, args) -> { throw new AssertionError(method.getName()); });
|
||||
}
|
||||
|
||||
private static TMethodType info(MethodSymbol ref) throws Throwable {
|
||||
return (TMethodType) FIXTURE.info.invoke(ref);
|
||||
}
|
||||
|
||||
private static ProbeSignature signature(IntFunction<Object> values, List<String> calls) {
|
||||
return new ProbeSignature(values, calls);
|
||||
}
|
||||
|
||||
private static final class ProbeSignature extends ScalaSignature {
|
||||
|
||||
private final IntFunction<Object> values;
|
||||
private final List<String> calls;
|
||||
|
||||
ProbeSignature(IntFunction<Object> values, List<String> calls) {
|
||||
super(new Bytes(new byte[] { 5, 0, 0 }, 0, 3));
|
||||
this.values = values;
|
||||
this.calls = calls;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T evalT(int index) {
|
||||
calls.add("eval:" + index);
|
||||
return (T) values.apply(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Fixture extends ClassLoader {
|
||||
|
||||
final MethodHandle info;
|
||||
final Class<?> returnType;
|
||||
|
||||
Fixture() {
|
||||
super(ScalaSignatureMethodSymbolInfoTest.class.getClassLoader());
|
||||
try {
|
||||
String base = "ReferenceScalaMethodSymbolInfo";
|
||||
byte[] bytes;
|
||||
try (InputStream stream = Objects.requireNonNull(getResourceAsStream("compat/" + base + ".class.b64"));
|
||||
Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
|
||||
bytes = Base64.getMimeDecoder().decode(scanner.next());
|
||||
}
|
||||
Class<?> type = defineClass(null, bytes, 0, bytes.length);
|
||||
Object instance = type.getConstructor().newInstance();
|
||||
java.lang.reflect.Method method = type.getMethod("info", MethodSymbol.class);
|
||||
returnType = method.getReturnType();
|
||||
info = MethodHandles.publicLookup().unreflect(method).bindTo(instance);
|
||||
} catch (ReflectiveOperationException | java.io.IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
yv66vgAAADQAJQEAO2NvZGVjaGlja2VuL211bHRpcGFydC9jb21wYXQvUmVmZXJlbmNlU2NhbGFN
|
||||
ZXRob2RTeW1ib2xJbmZvBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAJFJlZmVyZW5jZVNjYWxh
|
||||
TWV0aG9kU3ltYm9sSW5mby5zY2FsYQEAHkxzY2FsYS9yZWZsZWN0L1NjYWxhU2lnbmF0dXJlOwEA
|
||||
BWJ5dGVzAQEgBgEZMkEhAQIBEwlxIisaNGZlFnQ3LVoqZEMyDFcqGjtpXxIcFjAcMnBZJnNnbRwG
|
||||
AwcRCWFhWThuYQYkKEJBAwcDJWlXDxw7amEGFEhPQwEIAy0Zdw5aM2RRJhw3Lho4BAFNEQFBAwkD
|
||||
FzlpEQEEBgIbBSkxb1kxbUMmEXECBAIHAzpMKCsaNAkLRQFBEQEKAg1xSmcuGzs/KQUZAkMBCwEb
|
||||
BREBIgIMAQkDORIBQjVvTT4kIgFHEREFZXkCQwEOHhsFWSJCAQ8FAw0JNy9cBQM9bRFhYlUyYlkG
|
||||
HBZuGjhiaVYUWC0DAiE7CVlBK1QzdVE+JEcrHzlmERURUwMxASQDDRFYTRoJAzMRSiEhSg8DGTUr
|
||||
Rw9bOGUnZmwnbRw3AQAEaW5mbwEAbyhMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L2FzbS9TY2FsYVNp
|
||||
Z25hdHVyZSRNZXRob2RTeW1ib2w7KUxjb2RlY2hpY2tlbi9tdWx0aXBhcnQvYXNtL1NjYWxhU2ln
|
||||
bmF0dXJlJFRNZXRob2RUeXBlOwEANWNvZGVjaGlja2VuL211bHRpcGFydC9hc20vU2NhbGFTaWdu
|
||||
YXR1cmUkTWV0aG9kU3ltYm9sBwALAQA4KClMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L2FzbS9TY2Fs
|
||||
YVNpZ25hdHVyZSRUTWV0aG9kVHlwZTsMAAkADQoADAAOAQAEdGhpcwEAPUxjb2RlY2hpY2tlbi9t
|
||||
dWx0aXBhcnQvY29tcGF0L1JlZmVyZW5jZVNjYWxhTWV0aG9kU3ltYm9sSW5mbzsBAANyZWYBADdM
|
||||
Y29kZWNoaWNrZW4vbXVsdGlwYXJ0L2FzbS9TY2FsYVNpZ25hdHVyZSRNZXRob2RTeW1ib2w7AQAG
|
||||
PGluaXQ+AQADKClWDAAUABUKAAQAFgEANGNvZGVjaGlja2VuL211bHRpcGFydC9hc20vU2NhbGFT
|
||||
aWduYXR1cmUkVE1ldGhvZFR5cGUHABgBAChjb2RlY2hpY2tlbi9tdWx0aXBhcnQvYXNtL1NjYWxh
|
||||
U2lnbmF0dXJlBwAaAQALVE1ldGhvZFR5cGUBAAxNZXRob2RTeW1ib2wBAARDb2RlAQASTG9jYWxW
|
||||
YXJpYWJsZVRhYmxlAQAPTGluZU51bWJlclRhYmxlAQAKU291cmNlRmlsZQEADElubmVyQ2xhc3Nl
|
||||
cwEAGVJ1bnRpbWVWaXNpYmxlQW5ub3RhdGlvbnMBAAhTY2FsYVNpZwAhAAIABAAAAAAAAgABAAkA
|
||||
CgABAB4AAAA5AAEAAgAAAAUrtgAPsAAAAAIAHwAAABYAAgAAAAUAEAARAAAAAAAFABIAEwABACAA
|
||||
AAAGAAEAAAAGAAEAFAAVAAEAHgAAAC8AAQABAAAABSq3ABexAAAAAgAfAAAADAABAAAABQAQABEA
|
||||
AAAgAAAABgABAAAABwAEACEAAAACAAUAIgAAABIAAgAZABsAHAYBAAwAGwAdAAEAIwAAAAsAAQAG
|
||||
AAEAB3MACAAkAAAAAwUAAA==
|
||||
Reference in new issue
Block a user