/*
* Copyright (C) 2015 SoftIndex LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datakernel.codegen;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.*;
import static io.datakernel.codegen.ExpressionComparator.leftField;
import static io.datakernel.codegen.ExpressionComparator.rightField;
import static io.datakernel.codegen.Expressions.*;
import static java.util.Arrays.asList;
import static org.junit.Assert.*;
public class ExpressionTest {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
public static class TestPojo {
public int field1;
public int field2;
public TestPojo(int field1, int field2) {
this.field1 = field1;
this.field2 = field2;
}
public TestPojo(int field1) {
this.field1 = field1;
}
public void setField1(int field1) {
this.field1 = field1;
}
public int getField1() {
return field1;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestPojo testPojo = (TestPojo) o;
return (field1 == testPojo.field1) && (field2 == testPojo.field2);
}
@Override
public int hashCode() {
int result = field1;
result = 31 * result + field2;
return result;
}
@Override
public String toString() {
return "TestPojo{field1=" + field1 + ", field2=" + field2 + '}';
}
}
public static class TestPojo2 {
public String field1;
public int field2;
public long field3;
public float field4;
public int field5;
public double field6;
public String field7;
public TestPojo2(String field1, int field2, long field3, float field4, int field5, double field6, String field7) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
this.field4 = field4;
this.field5 = field5;
this.field6 = field6;
this.field7 = field7;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestPojo2 testPojo2 = (TestPojo2) o;
if (field2 != testPojo2.field2) return false;
if (field3 != testPojo2.field3) return false;
if (Float.compare(testPojo2.field4, field4) != 0) return false;
if (field5 != testPojo2.field5) return false;
if (Double.compare(testPojo2.field6, field6) != 0) return false;
if (field1 != null ? !field1.equals(testPojo2.field1) : testPojo2.field1 != null) return false;
return !(field7 != null ? !field7.equals(testPojo2.field7) : testPojo2.field7 != null);
}
@Override
public int hashCode() {
int result;
long temp;
result = field1 != null ? field1.hashCode() : 0;
result = 31 * result + field2;
result = 31 * result + (int) (field3 ^ (field3 >>> 32));
result = 31 * result + (field4 != +0.0f ? Float.floatToIntBits(field4) : 0);
result = 31 * result + field5;
temp = Double.doubleToLongBits(field6);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (field7 != null ? field7.hashCode() : 0);
return result;
}
}
public interface Test2 {
int hash(TestPojo2 pojo);
}
public interface Test extends Comparator<TestPojo>, Comparable<Test> {
Integer test(Integer argument);
int hash(TestPojo pojo);
int field1(TestPojo pojo);
TestPojo setter(TestPojo pojo);
TestPojo ctor();
void setXY(int valueX, byte valueY);
Integer getX();
short getY();
boolean allEqual(int var, int var1, int var2);
boolean anyEqual(int var, int var1, int var2);
void setPojoField1(TestPojo testPojo, int value);
int getPojoField1(TestPojo testPojo);
@Override
int compare(TestPojo o1, TestPojo o2);
@Override
boolean equals(Object obj);
@Override
int compareTo(Test o);
@Override
String toString();
void loop();
}
@org.junit.Test
public void test() throws IllegalAccessException, InstantiationException {
Expression local = let(constructor(TestPojo.class, value(1)));
Class<Test> testClass = ClassBuilder.create(DefiningClassLoader.create(), Test.class)
.withField("x", int.class)
.withField("y", Long.class)
.withMethod("compare", int.class, asList(TestPojo.class, TestPojo.class),
compare(TestPojo.class, "field1", "field2"))
.withMethod("int compareTo(io.datakernel.codegen.ExpressionTest$Test)",
compareTo("x"))
.withMethod("equals",
asEquals("x"))
.withMethod("setXY", sequence(
set(self(), "x", arg(0)),
set(self(), "y", arg(1))))
.withMethod("test",
add(arg(0), value(1L)))
.withMethod("hash",
hashCodeOfArgs(field(arg(0), "field1"), field(arg(0), "field2")))
.withMethod("field1",
field(arg(0), "field1"))
.withMethod("setter", sequence(
set(arg(0), "field1", value(10)),
set(arg(0), "field2", value(20)),
arg(0)))
.withMethod("ctor", sequence(
local,
set(local, "field2", value(2)),
local))
.withMethod("getX",
field(self(), "x"))
.withMethod("getY",
field(self(), "y"))
.withMethod("allEqual",
and(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("anyEqual",
or(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("setPojoField1",
call(arg(0), "setField1", arg(1)))
.withMethod("getPojoField1",
call(arg(0), "getField1"))
.withMethod("toString",
asString()
.withQuotes("{", "}", ", ")
.withArgument(field(self(), "x"))
.withArgument("labelY: ", field(self(), "y")))
.build();
Test test = testClass.newInstance();
assertEquals(11, (int) test.test(10));
assertEquals(33, test.hash(new TestPojo(1, 2)));
assertEquals(1, test.field1(new TestPojo(1, 2)));
assertEquals(new TestPojo(10, 20), test.setter(new TestPojo(1, 2)));
assertEquals(new TestPojo(1, 2), test.ctor());
test.setXY(1, (byte) 10);
assertEquals(1, (int) test.getX());
assertEquals(10, test.getY());
assertTrue(test.compare(new TestPojo(1, 10), new TestPojo(1, 10)) == 0);
assertTrue(test.compare(new TestPojo(2, 10), new TestPojo(1, 10)) > 0);
assertTrue(test.compare(new TestPojo(0, 10), new TestPojo(1, 10)) < 0);
assertTrue(test.compare(new TestPojo(1, 0), new TestPojo(1, 10)) < 0);
assertTrue(test.compareTo(test) == 0);
Test test1 = testClass.newInstance();
Test test2 = testClass.newInstance();
test1.setXY(1, (byte) 10);
test2.setXY(1, (byte) 10);
assertTrue(test1.compareTo(test2) == 0);
assertTrue(test1.equals(test2));
test2.setXY(2, (byte) 10);
assertTrue(test1.compareTo(test2) < 0);
assertFalse(test1.equals(test2));
test2.setXY(0, (byte) 10);
assertTrue(test1.compareTo(test2) > 0);
assertFalse(test1.equals(test2));
assertTrue(test1.allEqual(1, 1, 1));
assertFalse(test1.allEqual(1, 2, 1));
assertFalse(test1.allEqual(1, 1, 2));
assertFalse(test1.anyEqual(1, 2, 3));
assertTrue(test1.anyEqual(1, 2, 1));
assertTrue(test1.anyEqual(1, 1, 2));
TestPojo testPojo = new TestPojo(1, 10);
assertEquals(1, test1.getPojoField1(testPojo));
test1.setPojoField1(testPojo, 2);
assertEquals(2, test1.getPojoField1(testPojo));
assertEquals("{1, labelY: 10}", test1.toString());
}
@org.junit.Test
public void test2() throws IllegalAccessException, InstantiationException {
Class<Test2> testClass = ClassBuilder.create(DefiningClassLoader.create(), Test2.class)
.withMethod("hash",
hashCodeOfArgs(field(arg(0), "field1"), field(arg(0), "field2"), field(arg(0), "field3"),
field(arg(0), "field4"), field(arg(0), "field5"), field(arg(0), "field6"),
field(arg(0), "field7"))).build();
Test2 test = testClass.newInstance();
TestPojo2 testPojo2 = new TestPojo2("randomString", 42, 666666, 43258.42342f, 54359878, 43252353278423.423468, "fhsduighrwqruqsd");
assertEquals(testPojo2.hashCode(), test.hash(testPojo2));
}
@SuppressWarnings("unchecked")
@org.junit.Test
public void testComparator() {
Comparator<TestPojo> comparator = ClassBuilder.create(DefiningClassLoader.create(), Comparator.class)
.withMethod("compare",
compare(TestPojo.class, "field1", "field2"))
.buildClassAndCreateNewInstance();
assertTrue(comparator.compare(new TestPojo(1, 10), new TestPojo(1, 10)) == 0);
}
public interface TestNeg {
boolean negBoolean();
int negByte();
int negShort();
int negChar();
int negInt();
long negLong();
float negFloat();
double negDouble();
}
@org.junit.Test
public void testNeg() {
boolean z = true;
byte b = Byte.MAX_VALUE;
short s = Short.MAX_VALUE;
char c = Character.MAX_VALUE;
int i = Integer.MAX_VALUE;
long l = Long.MAX_VALUE;
float f = Float.MAX_VALUE;
double d = Double.MAX_VALUE;
TestNeg testClass = ClassBuilder.create(DefiningClassLoader.create(), TestNeg.class)
.withMethod("negBoolean", neg(value(z)))
.withMethod("negShort", neg(value(s)))
.withMethod("negByte", neg(value(b)))
.withMethod("negChar", neg(value(c)))
.withMethod("negInt", neg(value(i)))
.withMethod("negLong", neg(value(l)))
.withMethod("negFloat", neg(value(f)))
.withMethod("negDouble", neg(value(d)))
.buildClassAndCreateNewInstance();
assertTrue(testClass.negBoolean() == !z);
assertTrue(testClass.negShort() == -s);
assertTrue(testClass.negByte() == -b);
assertTrue(testClass.negChar() == -c);
assertTrue(testClass.negInt() == -i);
assertTrue(testClass.negLong() == -l);
assertTrue(testClass.negFloat() == -f);
assertTrue(testClass.negDouble() == -d);
}
public interface TestOperation {
int remB();
int remS();
int remC();
int remI();
long remL();
float remF();
double remD();
}
@org.junit.Test
public void testOperation() {
byte b = Byte.MAX_VALUE;
short s = Short.MAX_VALUE;
char c = Character.MAX_VALUE;
int i = Integer.MAX_VALUE;
long l = Long.MAX_VALUE;
float f = Float.MAX_VALUE;
double d = Double.MAX_VALUE;
TestOperation testClass = ClassBuilder.create(DefiningClassLoader.create(), TestOperation.class)
.withMethod("remB", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(b), value(20)))
.withMethod("remS", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(s), value(20)))
.withMethod("remC", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(c), value(20)))
.withMethod("remI", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(i), value(20)))
.withMethod("remL", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(l), value(20)))
.withMethod("remF", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(f), value(20)))
.withMethod("remD", arithmeticOp(ExpressionArithmeticOp.Operation.REM, value(d), value(20)))
.buildClassAndCreateNewInstance();
assertTrue(testClass.remB() == (b % (20)));
assertTrue(testClass.remS() == (s % (20)));
assertTrue(testClass.remC() == (c % (20)));
assertTrue(testClass.remI() == (i % (20)));
assertTrue(testClass.remL() == (l % (20)));
assertTrue(testClass.remF() == (f % (20)));
assertTrue(testClass.remD() == (d % (20)));
}
public interface TestSH {
int shlInt();
long shlLong();
int shrInt();
long shrLong();
int ushrInt();
}
@org.junit.Test
public void testSH() {
byte b = 8;
int i = 2;
long l = 4;
TestSH testClass = ClassBuilder.create(DefiningClassLoader.create(), TestSH.class)
.withMethod("shlInt", bitOp(ExpressionBitOp.Operation.SHL, value(b), value(i)))
.withMethod("shlLong", bitOp(ExpressionBitOp.Operation.SHL, value(l), value(b)))
.withMethod("shrInt", bitOp(ExpressionBitOp.Operation.SHR, value(b), value(i)))
.withMethod("shrLong", bitOp(ExpressionBitOp.Operation.SHR, value(l), value(i)))
.withMethod("ushrInt", bitOp(ExpressionBitOp.Operation.USHR, value(b), value(i)))
.buildClassAndCreateNewInstance();
assertTrue(testClass.shlInt() == (b << i));
assertTrue(testClass.shlLong() == (l << b));
assertTrue(testClass.shrInt() == (b >> i));
assertTrue(testClass.shrLong() == (l >> i));
assertTrue(testClass.ushrInt() == (b >>> i));
}
public interface TestBitMask {
int andInt();
int orInt();
int xorInt();
long andLong();
long orLong();
long xorLong();
}
@org.junit.Test
public void testBitMask() {
TestBitMask testClass = ClassBuilder.create(DefiningClassLoader.create(), TestBitMask.class)
.withMethod("andInt", bitOp(ExpressionBitOp.Operation.AND, value(2), value(4)))
.withMethod("orInt", bitOp(ExpressionBitOp.Operation.OR, value(2), value(4)))
.withMethod("xorInt", bitOp(ExpressionBitOp.Operation.XOR, value(2), value(4)))
.withMethod("andLong", bitOp(ExpressionBitOp.Operation.AND, value(2), value(4L)))
.withMethod("orLong", bitOp(ExpressionBitOp.Operation.OR, value((byte) 2), value(4L)))
.withMethod("xorLong", bitOp(ExpressionBitOp.Operation.XOR, value(2L), value(4L)))
.buildClassAndCreateNewInstance();
assertTrue(testClass.andInt() == (2 & 4));
assertTrue(testClass.orInt() == (2 | 4));
assertTrue(testClass.xorInt() == (2 ^ 4));
assertTrue(testClass.andLong() == (2L & 4L));
assertTrue(testClass.orLong() == (2L | 4L));
assertTrue(testClass.xorLong() == (2L ^ 4L));
}
public interface TestCall {
int callOther1(int i);
long callOther2();
int callStatic1(int i1, int i2);
long callStatic2(long l);
}
@org.junit.Test
public void testCall() {
TestCall testClass = ClassBuilder.create(DefiningClassLoader.create(), TestCall.class)
.withMethod("callOther1", call(self(), "method", arg(0)))
.withMethod("callOther2", call(self(), "method"))
.withMethod("method", int.class, asList(int.class), arg(0))
.withMethod("method", long.class, Collections.<Class<?>>emptyList(), value(-1L))
.withMethod("callStatic1", int.class, asList(int.class, int.class), callStaticSelf("method", arg(0), arg(1)))
.withMethod("callStatic2", long.class, asList(long.class), callStaticSelf("method", arg(0)))
.withStaticMethod("method", int.class, asList(int.class, int.class), arg(1))
.withStaticMethod("method", long.class, asList(long.class), arg(0))
.buildClassAndCreateNewInstance();
assert (testClass.callOther1(100) == 100);
assert (testClass.callOther2() == -1);
assert (testClass.callStatic1(1, 2) == 2);
assert (testClass.callStatic2(3L) == 3L);
}
public interface TestArgument {
Object array(WriteFirstElement w, Object[] arr);
Object write(WriteFirstElement w, Object o);
}
public static class WriteFirstElement {
public Object writeFirst(Object[] i) {
return i[0];
}
public Object write(Object o) {
return o;
}
}
@org.junit.Test
public void testArgument() {
TestArgument testClass = ClassBuilder.create(DefiningClassLoader.create(), TestArgument.class)
.withMethod("array", call(arg(0), "writeFirst", arg(1)))
.withMethod("write", call(arg(0), "write", arg(1)))
.buildClassAndCreateNewInstance();
assertTrue(testClass.array(new WriteFirstElement(), new Object[]{1000, 2, 3, 4}).equals(1000));
assertTrue(testClass.write(new WriteFirstElement(), 1000).equals(1000));
}
public interface WriteAllListElement {
void write(List listFrom, List listTo);
void writeIter(Iterator iteratorFrom, List listTo);
}
@org.junit.Test
public void testIterator() {
List<Integer> listFrom = asList(1, 1, 2, 3, 5, 8);
List<Integer> listTo1 = new ArrayList<>();
List<Integer> listTo2 = new ArrayList<>();
WriteAllListElement testClass = ClassBuilder.create(DefiningClassLoader.create(), WriteAllListElement.class)
.withMethod("write", forEach(arg(0), new ForVar() {
@Override
public Expression forVar(Expression it) {
return sequence(addListItem(arg(1), it), voidExp());
}
}))
.withMethod("writeIter", forEach(arg(0), new ForVar() {
@Override
public Expression forVar(Expression it) {
return sequence(addListItem(arg(1), it), voidExp());
}
}))
.buildClassAndCreateNewInstance();
testClass.write(listFrom, listTo1);
testClass.writeIter(listFrom.iterator(), listTo2);
assertEquals(listFrom.size(), listTo1.size());
for (int i = 0; i < listFrom.size(); i++) {
assertEquals(listFrom.get(i), (listTo1.get(i)));
}
assertEquals(listFrom.size(), listTo2.size());
for (int i = 0; i < listFrom.size(); i++) {
assertEquals(listFrom.get(i), (listTo2.get(i)));
}
}
public interface WriteArrayElements {
void write(Long[] a, List<Long> b);
}
@org.junit.Test
public void testIteratorForArray() {
Long[] intsFrom = new Long[]{1L, 1L, 2L, 3L, 5L, 8L};
List<Long> list = new ArrayList<>();
WriteArrayElements testClass = ClassBuilder.create(DefiningClassLoader.create(), WriteArrayElements.class)
.withMethod("write", forEach(arg(0), new ForVar() {
@Override
public Expression forVar(Expression it) {
return sequence(addListItem(arg(1), cast(it, Object.class)), voidExp());
}
}))
.buildClassAndCreateNewInstance();
testClass.write(intsFrom, list);
for (int i = 0; i < intsFrom.length; i++) {
assertEquals(intsFrom[i], list.get(i));
}
}
public interface CastPrimitive {
Object a();
}
@org.junit.Test
public void testCastPrimitive() {
CastPrimitive testClass = ClassBuilder.create(DefiningClassLoader.create(), CastPrimitive.class)
.withMethod("a", value(1))
.buildClassAndCreateNewInstance();
assertEquals(testClass.a(), 1);
}
public interface Initializable {
void init();
}
public interface Getter {
Object get(Object obj);
}
@org.junit.Test
public void testGetter() throws Exception {
DefiningClassLoader classLoader = DefiningClassLoader.create();
Initializable intHolder = ClassBuilder.create(classLoader, Initializable.class)
.withField("x", int.class)
.withMethod("init", set(field(self(), "x"), value(42)))
.buildClassAndCreateNewInstance();
intHolder.init();
Getter getter = ClassBuilder.create(classLoader, Getter.class)
.withMethod("get", field(cast(arg(0), intHolder.getClass()), "x"))
.buildClassAndCreateNewInstance();
assertEquals(42, getter.get(intHolder));
}
@org.junit.Test
public void testBuildedInstance() throws IllegalAccessException, InstantiationException {
DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
Expression local = let(constructor(TestPojo.class, value(1)));
Class<Test> testClass1 = ClassBuilder.create(definingClassLoader, Test.class)
.withField("x", int.class)
.withField("y", Long.class)
.withMethod("compare", int.class, asList(TestPojo.class, TestPojo.class),
compare(TestPojo.class, "field1", "field2"))
.withMethod("int compareTo(io.datakernel.codegen.ExpressionTest$Test)",
compareTo("x"))
.withMethod("equals",
asEquals("x"))
.withMethod("setXY", sequence(
set(field(self(), "x"), arg(0)),
set(field(self(), "y"), arg(1))))
.withMethod("test",
add(arg(0), value(1L)))
.withMethod("hash",
hashCodeOfArgs(field(arg(0), "field1"), field(arg(0), "field2")))
.withMethod("field1",
field(arg(0), "field1"))
.withMethod("setter", sequence(
set(field(arg(0), "field1"), value(10)),
set(field(arg(0), "field2"), value(20)),
arg(0)))
.withMethod("ctor", sequence(
local,
set(field(local, "field2"), value(2)),
local))
.withMethod("getX",
field(self(), "x"))
.withMethod("getY",
field(self(), "y"))
.withMethod("allEqual",
and(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("anyEqual",
or(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("setPojoField1",
call(arg(0), "setField1", arg(1)))
.withMethod("getPojoField1",
call(arg(0), "getField1"))
.withMethod("toString",
asString()
.withQuotes("{", "}", ", ")
.withArgument(field(self(), "x"))
.withArgument("labelY: ", field(self(), "y")))
.build();
Class<Test> testClass2 = ClassBuilder.create(definingClassLoader, Test.class)
.withField("x", int.class)
.withField("y", Long.class)
.withMethod("compare", int.class, asList(TestPojo.class, TestPojo.class),
compare(TestPojo.class, "field1", "field2"))
.withMethod("int compareTo(io.datakernel.codegen.ExpressionTest$Test)",
compareTo("x"))
.withMethod("equals",
asEquals("x"))
.withMethod("setXY", sequence(
set(field(self(), "x"), arg(0)),
set(field(self(), "y"), arg(1))))
.withMethod("test",
add(arg(0), value(1L)))
.withMethod("hash",
hashCodeOfArgs(field(arg(0), "field1"), field(arg(0), "field2")))
.withMethod("field1",
field(arg(0), "field1"))
.withMethod("setter", sequence(
set(field(arg(0), "field1"), value(10)),
set(field(arg(0), "field2"), value(20)),
arg(0)))
.withMethod("ctor", sequence(
local,
set(field(local, "field2"), value(2)),
local))
.withMethod("getX",
field(self(), "x"))
.withMethod("getY",
field(self(), "y"))
.withMethod("allEqual",
and(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("anyEqual",
or(cmpEq(arg(0), arg(1)), cmpEq(arg(0), arg(2))))
.withMethod("setPojoField1",
call(arg(0), "setField1", arg(1)))
.withMethod("getPojoField1",
call(arg(0), "getField1"))
.withMethod("toString",
asString()
.withQuotes("{", "}", ", ")
.withArgument(field(self(), "x"))
.withArgument("labelY: ", field(self(), "y")))
.build();
assertEquals(testClass1, testClass2);
}
public interface TestCompare {
boolean compareObjectLE(Integer i1, Integer i2);
boolean comparePrimitiveLE(int i1, int i2);
boolean compareObjectEQ(Integer i1, Integer i2);
boolean compareObjectNE(Integer i1, Integer i2);
}
@org.junit.Test
public void testCompare() throws IllegalAccessException, InstantiationException {
DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
Class<TestCompare> test1 = ClassBuilder.create(definingClassLoader, TestCompare.class)
.withMethod("compareObjectLE", cmp(PredicateDefCmp.Operation.LE, arg(0), arg(1)))
.withMethod("comparePrimitiveLE", cmp(PredicateDefCmp.Operation.LE, arg(0), arg(1)))
.withMethod("compareObjectEQ", cmp(PredicateDefCmp.Operation.EQ, arg(0), arg(1)))
.withMethod("compareObjectNE", cmp(PredicateDefCmp.Operation.NE, arg(0), arg(1)))
.build();
TestCompare testCompare = test1.newInstance();
assertTrue(testCompare.compareObjectLE(5, 5));
assertTrue(testCompare.comparePrimitiveLE(5, 6));
assertTrue(testCompare.compareObjectEQ(5, 5));
assertTrue(testCompare.compareObjectNE(5, -5));
}
public static class StringHolder {
public String string1;
public String string2;
public StringHolder(String string1, String string2) {
this.string1 = string1;
this.string2 = string2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StringHolder that = (StringHolder) o;
return Objects.equals(string1, that.string1) &&
Objects.equals(string2, that.string2);
}
@Override
public int hashCode() {
return Objects.hash(string1, string2);
}
@Override
public String toString() {
return "StringHolder{" +
"string1='" + string1 + '\'' +
", string2='" + string2 + '\'' +
'}';
}
}
public class StringHolderComparator implements Comparator<StringHolder> {
public int compare(StringHolder var1, StringHolder var2) {
String var1String1 = var1.string1;
String var2String1 = var2.string1;
int compare;
if (var1String1 == null) {
if (var2String1 != null) {
return -1;
}
} else {
if (var2String1 == null) {
return 1;
}
compare = var1String1.compareTo(var2String1);
if (compare != 0) {
return compare;
}
}
String var1String2 = var1.string2;
String var2String2 = var2.string2;
if (var1String2 == null) {
if (var2String2 != null) {
return -1;
}
} else {
if (var2String2 == null) {
return 1;
}
compare = var1String2.compareTo(var2String2);
if (compare != 0) {
return compare;
}
}
compare = 0;
return compare;
}
}
@org.junit.Test
public void testComparatorNullable() {
DefiningClassLoader classLoader = DefiningClassLoader.create();
Comparator generatedComparator = ClassBuilder.create(classLoader, Comparator.class)
.withMethod("compare", ExpressionComparator.create()
.with(leftField(StringHolder.class, "string1"), rightField(StringHolder.class, "string1"), true)
.with(leftField(StringHolder.class, "string2"), rightField(StringHolder.class, "string2"), true))
.buildClassAndCreateNewInstance();
List<StringHolder> strings = Arrays.asList(new StringHolder(null, "b"), new StringHolder(null, "a"),
new StringHolder("b", null), new StringHolder("c", "e"),
new StringHolder("c", "d"), new StringHolder(null, null), new StringHolder("d", "z"),
new StringHolder(null, null));
List<StringHolder> strings2 = new ArrayList<>(strings);
Collections.sort(strings, generatedComparator);
Collections.sort(strings2, new StringHolderComparator());
assertEquals(strings, strings2);
}
public interface TestInterface {
double returnDouble();
}
public static abstract class TestAbstract implements TestInterface {
protected abstract int returnInt();
}
@org.junit.Test
public void testAbstractClassWithInterface() throws Exception {
DefiningClassLoader classLoader = DefiningClassLoader.create();
TestAbstract testObj = ClassBuilder.create(classLoader, TestAbstract.class)
.withMethod("returnInt", value(42))
.withMethod("returnDouble", value(-1.0))
.buildClassAndCreateNewInstance();
assertEquals(42, testObj.returnInt());
assertEquals(-1.0, testObj.returnDouble(), 1E-5);
}
public static abstract class A {
public int t() {
return 40;
}
public abstract int a();
}
public interface B {
Integer b();
}
public interface C {
String c();
}
@org.junit.Test
public void testMultipleInterfacesWithAbstract() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final A instance = ClassBuilder.create(definingClassLoader, A.class, asList(B.class, C.class))
.withMethod("a", value(42))
.withMethod("b", value(43))
.withMethod("c", value("44"))
.buildClassAndCreateNewInstance();
assertEquals(instance.t(), 40);
assertEquals(instance.a(), 42);
assertEquals(((B) instance).b(), Integer.valueOf(43));
assertEquals(((C) instance).c(), "44");
}
@org.junit.Test
public void testMultipleInterfaces() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final B instance = ClassBuilder.create(definingClassLoader, B.class, Collections.<Class<?>>singletonList(C.class))
.withMethod("b", value(43))
.withMethod("c", value("44"))
.buildClassAndCreateNewInstance();
assertEquals(instance.b(), Integer.valueOf(43));
assertEquals(((C) instance).c(), "44");
}
@org.junit.Test
public void testNullableToString() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final B instance = ClassBuilder.create(definingClassLoader, B.class)
.withMethod("b", nullRef(Integer.class))
.withMethod("toString",
asString()
.withQuotes("{", "}", ", ")
.withArgument(call(self(), "b")))
.buildClassAndCreateNewInstance();
assertEquals(instance.b(), null);
assertEquals(instance.toString(), "{null}");
}
@org.junit.Test
public void testSetSaveBytecode() throws IOException {
final File folder = tempFolder.newFolder();
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final B instance = ClassBuilder.create(definingClassLoader, B.class)
.withBytecodeSaveDir(folder.toPath())
.withMethod("b", nullRef(Integer.class))
.withMethod("toString",
asString()
.withQuotes("{", "}", ", ")
.withArgument(call(self(), "b")))
.buildClassAndCreateNewInstance();
assertEquals(folder.list().length, 1);
assertEquals(instance.b(), null);
assertEquals(instance.toString(), "{null}");
}
public interface TestArraySet {
Integer[] ints(Integer[] ints);
}
@org.junit.Test
public void testArraySet() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final TestArraySet instance = ClassBuilder.create(definingClassLoader, TestArraySet.class)
.withMethod("ints", sequence(setArrayItem(arg(0), value(0), cast(value(42), Integer.class)), arg(0)))
.buildClassAndCreateNewInstance();
Integer[] ints = new Integer[]{1, 2, 3, 4};
assertArrayEquals(instance.ints(ints), new Integer[]{42, 2, 3, 4});
}
public interface TestCallStatic {
int method(int a, int b);
}
@org.junit.Test
public void testCallStatic() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final TestCallStatic instance = ClassBuilder.create(definingClassLoader, TestCallStatic.class)
.withMethod("method", callStatic(Math.class, "min", arg(0), arg(1)))
.buildClassAndCreateNewInstance();
assertEquals(instance.method(5, 0), 0);
assertEquals(instance.method(5, 10), 5);
}
public interface TestIsNull {
boolean method(String a);
}
@org.junit.Test
public void testIsNull() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final TestIsNull instance = ClassBuilder.create(definingClassLoader, TestIsNull.class)
.withMethod("method", isNull(arg(0)))
.buildClassAndCreateNewInstance();
assertEquals(instance.method("42"), false);
assertEquals(instance.method(null), true);
}
public interface TestIsNotNull {
boolean method(Object a);
}
@org.junit.Test
public void testIsNotNull() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final TestIsNotNull instance = ClassBuilder.create(definingClassLoader, TestIsNotNull.class)
.withMethod("method", isNotNull(arg(0)))
.buildClassAndCreateNewInstance();
assertEquals(instance.method("42"), true);
assertEquals(instance.method(42), true);
assertEquals(instance.method(null), false);
}
public interface TestNewArray {
int[] ints(int size);
String[] integers(int size);
}
@org.junit.Test
public void testNewArray() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
final TestNewArray instance = ClassBuilder.create(definingClassLoader, TestNewArray.class)
.withMethod("ints", newArray(int[].class, arg(0)))
.withMethod("integers", newArray(String[].class, arg(0)))
.buildClassAndCreateNewInstance();
assertEquals(instance.ints(1).length, 1);
assertEquals(instance.integers(2).length, 2);
}
@org.junit.Test
public void testStaticConstants() {
final DefiningClassLoader definingClassLoader = DefiningClassLoader.create();
Object testObject = new Object();
final Getter instance = ClassBuilder.create(definingClassLoader, Getter.class)
.withMethod("get", value(testObject))
.buildClassAndCreateNewInstance();
assertTrue(testObject == instance.get(null));
}
}