mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
[tests] migrates bytecode analysis tests to light test case
... and moves test data out of source code
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ExpectContract {
|
||||
String value() default "";
|
||||
boolean pure() default false;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectLeaking { }
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectNoPsiKey { }
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectNotNull { }
|
||||
@@ -0,0 +1,287 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@SuppressWarnings({"unused", "IOResourceOpenedButNotSafelyClosed"})
|
||||
public class Test01 {
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public static MySupplier methodReference(@ExpectNotNull String s) {
|
||||
return s::trim;
|
||||
}
|
||||
|
||||
boolean plainFlag;
|
||||
volatile boolean volatileFlag;
|
||||
|
||||
static void f(@ExpectNotNull Object o1, @ExpectNotNull Object o2) {
|
||||
if (o1 == null) throw new NullPointerException();
|
||||
else s(o2, o2);
|
||||
}
|
||||
|
||||
static void g(@ExpectNotNull Object o, boolean b) {
|
||||
if (b) f(o, o);
|
||||
else s(o, o);
|
||||
}
|
||||
|
||||
static void s(@ExpectNotNull Object o1, Object o2) {
|
||||
t(o1);
|
||||
v(o2);
|
||||
}
|
||||
|
||||
static void t(@ExpectNotNull Object o) {
|
||||
use(o);
|
||||
}
|
||||
|
||||
private static String use(@ExpectNotNull Object o) {
|
||||
System.out.println(o);
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
static void v(Object o) { }
|
||||
|
||||
@ExpectContract("null->null")
|
||||
static String toString1(Object o) {
|
||||
return o == null ? null : use(o);
|
||||
}
|
||||
|
||||
@ExpectContract("null->!null")
|
||||
static String toString2(Object o) {
|
||||
return o == null ? "null" : use(o);
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
static String constantString() {
|
||||
return "s";
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->param1", pure = true)
|
||||
static String idString(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->this", pure = true)
|
||||
@ExpectNotNull
|
||||
public Test01 getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->new", pure = true)
|
||||
@ExpectNotNull
|
||||
protected Test01 createRoot() {
|
||||
return new Test01();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->false;null->true", pure = true)
|
||||
static boolean isNull(Object o) {
|
||||
return o == null;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->true;null->false", pure = true)
|
||||
static boolean isNotNull(Object o) {
|
||||
return !isNull(o);
|
||||
}
|
||||
|
||||
interface MySupplier {
|
||||
String get();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public static MySupplier lambda(@ExpectNotNull String s) {
|
||||
return () -> s.trim();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public MySupplier lambdaNonStatic(@ExpectNotNull String s) {
|
||||
return () -> getThis().hashCode() + s.trim();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
public MySupplier lambdaBranching(@ExpectNotNull String s, String t, boolean b) {
|
||||
if (b) {
|
||||
System.out.println(s);
|
||||
}
|
||||
else {
|
||||
System.out.println(t);
|
||||
}
|
||||
return () -> s.trim();
|
||||
}
|
||||
|
||||
@ExpectContract(value="null,_->fail", pure = true)
|
||||
public static void assertNotNull(@ExpectNotNull Object obj, String message) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract(value="false,_,_->fail;true,_,_->true", pure = true)
|
||||
public static boolean assertTrue(boolean val, String message, int data) {
|
||||
if (!val) {
|
||||
throw new IllegalArgumentException(message+":"+data);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@ExpectContract(value="true,_->fail;_,_->false", pure = true)
|
||||
public static boolean assertFalse(boolean val, String message) {
|
||||
if (val) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(value = "_,_,_->new", pure = true)
|
||||
public static long[] copyOfRange(@ExpectNotNull long[] arr, int from, int to) {
|
||||
int diff = to - from;
|
||||
if (diff < 0) {
|
||||
throw new IllegalArgumentException("Invalid arguments: " + from + '>' + to);
|
||||
}
|
||||
long[] copy = new long[diff];
|
||||
System.arraycopy(arr, from, copy, 0, Math.min(arr.length - from, diff));
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(value="_->new", pure = true)
|
||||
public static long[] copyAndModify(@ExpectNotNull long[] input) {
|
||||
long[] copy = copyOfRange(input, 0, input.length);
|
||||
copy[0] = 1;
|
||||
set(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static void set(@ExpectNotNull long[] copy) {
|
||||
copy[1] = 2;
|
||||
}
|
||||
|
||||
@ExpectContract(value="_,_,_,_->new", pure = true)
|
||||
public static <I, O> O[] copyOfRangeObject(@ExpectNotNull I[] arr, int from, int to, @ExpectNotNull Class<? extends O[]> newType) {
|
||||
int diff = to - from;
|
||||
if (diff < 0) {
|
||||
throw new IllegalArgumentException("Invalid arguments: " + from + '>' + to);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
O[] copy = (O[]) Array.newInstance(newType.getComponentType(), diff);
|
||||
//noinspection SuspiciousSystemArraycopy
|
||||
System.arraycopy(arr, from, copy, 0, Math.min(arr.length - from, diff));
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->fail", pure = true)
|
||||
public static void callAlwaysFail(int x) {
|
||||
alwaysFail();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->fail", pure = true)
|
||||
public static void callAlwaysFailRef(String x) {
|
||||
callAlwaysFailTwoRefs(x, null);
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_,_->fail", pure = true)
|
||||
public static void callAlwaysFailTwoRefs(String x, String y) {
|
||||
alwaysFail();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->fail", pure = true)
|
||||
private static void alwaysFail() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->null;null->!null", pure = true)
|
||||
static String invert(String x) {
|
||||
return x == null ? "empty" : null;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "false->true;true->false", pure = true)
|
||||
static boolean invertBool(boolean x) {
|
||||
return !x;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_,true->true;null,_->true", pure=true)
|
||||
boolean checkTrueFail(Object a, boolean b) {
|
||||
if (a == null) return true;
|
||||
if (b) throw new RuntimeException();
|
||||
return b;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
String getStringNoTry(@ExpectNotNull String s) throws IOException {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
|
||||
String getStringTry(String s) {
|
||||
try {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract("null->null")
|
||||
String getStringTryNPECatched(String s) {
|
||||
try {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
void testThrow(@ExpectNotNull String s) {
|
||||
if (s.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract("_->param1")
|
||||
String testCatchReturn(String s) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
System.out.println("exception!");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
boolean testCatchBool(File file) {
|
||||
try {
|
||||
Files.createDirectories(file.toPath());
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignored) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectContract("null->false")
|
||||
boolean testCatchBool2(File file) {
|
||||
try {
|
||||
Files.createDirectories(file.toPath());
|
||||
return true;
|
||||
}
|
||||
catch (Throwable ignored) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->new", pure = true)
|
||||
String[] replaceFirstWithNull(@ExpectNotNull String[] arr) {
|
||||
String[] res = arr.clone();
|
||||
res[0] = null;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public final class Test02 {
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String notNullString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String notNullStringDelegate() {
|
||||
return notNullString();
|
||||
}
|
||||
|
||||
public boolean getFlagVolatile(@ExpectNotNull Test01 test01) {
|
||||
return test01.volatileFlag;
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public boolean getFlagPlain(@ExpectNotNull Test01 test01) {
|
||||
return test01.plainFlag;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TestAnnotation { }
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectContract;
|
||||
|
||||
// A class to test the clash of the same class in different source paths
|
||||
// See also ../../conflict/TestConflict.java
|
||||
public class TestConflict {
|
||||
static int throwInDataNativeInConflict() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
static native int nativeInDataThrowInConflict();
|
||||
|
||||
@ExpectContract(value = "->fail", pure = true)
|
||||
static int throwBoth() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
void pureInDataSideEffectInConflict() { }
|
||||
|
||||
void sideEffectInDataPureInConflict() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
void pureBoth() { }
|
||||
|
||||
void sideEffectBoth() {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectNoPsiKey;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestConverterData {
|
||||
public static class StaticNestedClass {
|
||||
public StaticNestedClass(Object o) { }
|
||||
|
||||
public StaticNestedClass[] test01(StaticNestedClass[] ns, StaticNestedClass... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
|
||||
public class InnerClass {
|
||||
// a reference to outer class should be inserted when translating PSI -> ASM
|
||||
public InnerClass(Object o) { }
|
||||
|
||||
public InnerClass[] Inner2test01(InnerClass[] tests, InnerClass... ellipsis) {
|
||||
return tests;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericStaticNestedClass<A> {
|
||||
public GenericStaticNestedClass(A a) { }
|
||||
|
||||
public GenericStaticNestedClass[] test01(GenericStaticNestedClass[] ns, GenericStaticNestedClass... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
public GenericStaticNestedClass<A>[] test02(GenericStaticNestedClass<A>[] ns, GenericStaticNestedClass<A>... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
public class GenericInnerClass<B> {
|
||||
public GenericInnerClass(B b) { }
|
||||
|
||||
public <C> GenericStaticNestedClass<A> test01(GenericInnerClass<C> c) {
|
||||
return GenericStaticNestedClass.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TestConverterData(int x) { }
|
||||
|
||||
// ExtConverterClass class is not in the class roots, so translation from PSI is impossible
|
||||
@ExpectNoPsiKey
|
||||
public ExtTestConverterData test01(ExtTestConverterData converter) {
|
||||
return converter;
|
||||
}
|
||||
|
||||
@TestAnnotation
|
||||
public TestConverterData[] test02(@TestAnnotation TestConverterData[] tests) {
|
||||
return tests;
|
||||
}
|
||||
|
||||
public boolean[] test03(boolean[] b) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
class ExtTestConverterData { }
|
||||
@@ -0,0 +1,22 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectContract;
|
||||
|
||||
public enum TestEnum {
|
||||
A, B, C;
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public int getValue() {
|
||||
return ordinal()+1;
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public boolean isA() {
|
||||
switch (this) {
|
||||
case A:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
public final class TestHashCollision {
|
||||
// signature hashes for these two methods collide: MD5("()V"+"test11044") and MD5("()V"+"test20917") have the same prefix: 3d802c48
|
||||
void test11044() {
|
||||
// Though purity can be inferred for this method, due to collision we erase inference result
|
||||
}
|
||||
|
||||
void test20917() {
|
||||
System.out.println("non-pure");
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectLeaking;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestLeakingParametersData {
|
||||
int z;
|
||||
|
||||
void test01(@ExpectLeaking Object o1, @ExpectLeaking Object o2, @ExpectLeaking Object o3) {
|
||||
o1.toString();
|
||||
o2.toString();
|
||||
o3.toString();
|
||||
}
|
||||
|
||||
void test02(@ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
|
||||
void test03(int i, @ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
|
||||
void test04(long i, @ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestNonStable {
|
||||
public String asString1() {
|
||||
return asString();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String asString() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package bytecodeAnalysis.java9;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
// Test that indified string concatenation is properly recognized
|
||||
// This file is precompiled via Java 9 compiler and class file is placed in the same directory
|
||||
public class TestStringConcat {
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
String concat(String foo, String bar) {
|
||||
return foo+"!"+bar;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user