package edu.stanford.nlp.util;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.*;
import static org.junit.Assert.*;
import org.junit.*;
public class MetaClassTest {
private static final String CLASS = MetaClassTest.class.getName();
//Interface
public static interface ISomething{
public String display();
}
public static class IInstSomething implements ISomething{
public String display(){ return "Isomething"; }
}
//Abstract
public static abstract class ASomething{
public abstract String display();
}
public static class AInstSomething extends ASomething{
public String display(){ return "Asomething"; }
}
//Superclass
public static class SSomething{
public String display(){ return "FAIL"; }
}
public static class SInstSomething extends SSomething{
public String display(){ return "Ssomething"; }
}
//Simpleclass
public static class Something{
public String display(){ return "something"; }
}
public static class SomethingWrapper{
private ISomething isomething;
private ASomething asomething;
private SSomething ssomething;
private Something something;
public SomethingWrapper(ISomething something){
this.isomething = something;
}
public SomethingWrapper(ASomething something){
this.asomething = something;
}
public SomethingWrapper(SSomething something){
this.ssomething = something;
}
public SomethingWrapper(Something something){
this.something = something;
}
public String display(){ return something.display(); }
public String displayI(){ return isomething.display(); }
public String displayA(){ return asomething.display(); }
public String displayS(){ return ssomething.display(); }
}
public static class SubSSomething extends SSomething{
public String display(){ return "subssomething"; }
}
public static class ManyConstructors {
private int constructorInvoked = -1;
public ManyConstructors(Object a){
constructorInvoked = 0;
}
public ManyConstructors(Something a){
constructorInvoked = 1;
}
public ManyConstructors(SSomething a){
constructorInvoked = 2;
}
public ManyConstructors(SubSSomething a){
constructorInvoked = 3;
}
public ManyConstructors(Object a, Object b){
this.constructorInvoked = 4;
}
public ManyConstructors(Object a, Something b){
this.constructorInvoked = 5;
}
public ManyConstructors(Object a, SSomething b){
this.constructorInvoked = 6;
}
public ManyConstructors(Object a, SubSSomething b){
this.constructorInvoked = 7;
}
public ManyConstructors(Something a, Object b){
this.constructorInvoked = 8;
}
public ManyConstructors(Something a, Something b){
this.constructorInvoked = 9;
}
public ManyConstructors(Something a, SSomething b){
this.constructorInvoked = 10;
}
public ManyConstructors(Something a, SubSSomething b){
this.constructorInvoked = 11;
}
public ManyConstructors(SSomething a, Object b){
this.constructorInvoked = 12;
}
public ManyConstructors(SSomething a, Something b){
this.constructorInvoked = 13;
}
public ManyConstructors(SSomething a, SSomething b){
this.constructorInvoked = 14;
}
public ManyConstructors(SSomething a, SubSSomething b){
this.constructorInvoked = 15;
}
public ManyConstructors(SubSSomething a, Object b){
this.constructorInvoked = 16;
}
public ManyConstructors(SubSSomething a, Something b){
this.constructorInvoked = 17;
}
public ManyConstructors(SubSSomething a, SSomething b){
this.constructorInvoked = 18;
}
public ManyConstructors(SubSSomething a, SubSSomething b){
this.constructorInvoked = 19;
}
public ManyConstructors(Something a, Something b, Something c){
this.constructorInvoked = 20;
}
public int constructorInvoked(){ return constructorInvoked; }
public boolean equals(Object o){
if(o instanceof ManyConstructors){
return this.constructorInvoked == ((ManyConstructors) o).constructorInvoked;
}
return false;
}
public String toString(){
return "" + constructorInvoked;
}
}
public static class Primitive{
public Primitive(int i){}
public Primitive(double d){}
}
public static class VarArgs{
public int a[];
public VarArgs(int ...args){
a = args;
}
}
@Test
public void testBasic(){
//--Basics
//(succeed)
MetaClass.create("java.lang.String");
assertEquals(MetaClass.create("java.lang.String").createInstance("hello"), "hello");
//(fail)
try{
MetaClass.create(CLASS+"$SomethingWrapper").createInstance("hello");
} catch(MetaClass.ClassCreationException e){
assertTrue("Should not instantiate Super with String", true);
}
//--Argument Length
MetaClass.create(CLASS+"$ManyConstructors").createInstance(new Something(), new Something(), new Something());
assertEquals(
((ManyConstructors) MetaClass.create(CLASS+"$ManyConstructors").createInstance(
new Something()
)).constructorInvoked(),
new ManyConstructors(
new Something()
).constructorInvoked()
);
assertEquals(
((ManyConstructors) MetaClass.create(CLASS+"$ManyConstructors").createInstance(
new Something(), new Something()
)).constructorInvoked(),
new ManyConstructors(
new Something(), new Something()
).constructorInvoked()
);
assertEquals(
((ManyConstructors) MetaClass.create(CLASS+"$ManyConstructors").createInstance(
new Something(), new Something(), new Something()
)).constructorInvoked(),
new ManyConstructors(
new Something(), new Something(), new Something()
).constructorInvoked()
);
assertEquals(new ManyConstructors(new String("hi")), MetaClass.create(CLASS+"$ManyConstructors").createInstance(new String("hi")));
assertEquals(new ManyConstructors(new Something()), MetaClass.create(CLASS+"$ManyConstructors").createInstance(new Something()));
assertEquals(new ManyConstructors(new SSomething()), MetaClass.create(CLASS+"$ManyConstructors").createInstance(new SSomething()));
assertEquals(new ManyConstructors(new SubSSomething()), MetaClass.create(CLASS+"$ManyConstructors").createInstance(new SubSSomething()));
}
@Test
public void testInheritance(){
//--Implementing Class
try{
Object o = MetaClass.create(CLASS+"$SomethingWrapper").createInstance(new Something());
assertTrue("Returned class should be a SomethingWrapper", o instanceof SomethingWrapper );
assertEquals(((SomethingWrapper) o).display(), "something");
} catch(MetaClass.ClassCreationException e){
e.printStackTrace();
assertFalse("Should not exception on this call", true);
}
//--Implementing super class
try{
Object o = MetaClass.create(CLASS+"$SomethingWrapper").createInstance(new SInstSomething());
assertTrue("Returned class should be a SomethingWrapper", o instanceof SomethingWrapper );
assertEquals(((SomethingWrapper) o).displayS(), "Ssomething");
} catch(MetaClass.ClassCreationException e){
e.printStackTrace();
assertFalse("Should not exception on this call", true);
}
//--Implementing abstract classes
try{
Object o = MetaClass.create(CLASS+"$SomethingWrapper").createInstance(new AInstSomething());
assertTrue("Returned class should be a SomethingWrapper", o instanceof SomethingWrapper );
assertEquals(((SomethingWrapper) o).displayA(), "Asomething");
} catch(MetaClass.ClassCreationException e){
e.printStackTrace();
assertFalse("Should not exception on this call", true);
}
//--Implementing interfaces
try{
Object o = MetaClass.create(CLASS+"$SomethingWrapper").createInstance(new IInstSomething());
assertTrue("Returned class should be a SomethingWrapper", o instanceof SomethingWrapper );
assertEquals(((SomethingWrapper) o).displayI(), "Isomething");
} catch(MetaClass.ClassCreationException e){
e.printStackTrace();
assertFalse("Should not exception on this call", true);
}
}
private ManyConstructors makeRef(int i, int j){
switch(i){
case 0:
switch(j){
case 0:
return new ManyConstructors(new String("hi"), new String("hi"));
case 1:
return new ManyConstructors(new String("hi"), new Something());
case 2:
return new ManyConstructors(new String("hi"), new SSomething());
case 3:
return new ManyConstructors(new String("hi"), new SubSSomething());
}
return null;
case 1:
switch(j){
case 0:
return new ManyConstructors(new Something(), new String("hi"));
case 1:
return new ManyConstructors(new Something(), new Something());
case 2:
return new ManyConstructors(new Something(), new SSomething());
case 3:
return new ManyConstructors(new Something(), new SubSSomething());
}
return null;
case 2:
switch(j){
case 0:
return new ManyConstructors(new SSomething(), new String("hi"));
case 1:
return new ManyConstructors(new SSomething(), new Something());
case 2:
return new ManyConstructors(new SSomething(), new SSomething());
case 3:
return new ManyConstructors(new SSomething(), new SubSSomething());
}
return null;
case 3:
switch(j){
case 0:
return new ManyConstructors(new SubSSomething(), new String("hi"));
case 1:
return new ManyConstructors(new SubSSomething(), new Something());
case 2:
return new ManyConstructors(new SubSSomething(), new SSomething());
case 3:
return new ManyConstructors(new SubSSomething(), new SubSSomething());
}
return null;
}
return null;
}
private static ManyConstructors makeRef(int i){
switch(i){
case 0:
return new ManyConstructors(new String("hi"));
case 1:
return new ManyConstructors(new Something());
case 2:
return new ManyConstructors(new SSomething());
case 3:
return new ManyConstructors(new SubSSomething());
}
return null;
}
@Test
public void testConsistencyWithJava(){
Object[] options = new Object[]{ new String("hi"), new Something(), new SSomething(), new SubSSomething() };
/*
* Single Term
*/
//--Cast everything as an object
for (Object option : options) {
ManyConstructors ref = new ManyConstructors(option);
ManyConstructors test = (ManyConstructors)
MetaClass.create(CLASS + "$ManyConstructors")
.createFactory(Object.class)
.createInstance(option);
assertEquals(ref.constructorInvoked(), test.constructorInvoked());
}
//--Use native types
for(int i=0; i<options.length; i++){
ManyConstructors ref = makeRef(i);
ManyConstructors test = (ManyConstructors)
MetaClass.create(CLASS+"$ManyConstructors")
.createInstance(options[i]);
assertEquals(ref, test);
}
/*
* Multi Term
*/
//--Use native types
for(int i=0; i<options.length; i++){
for(int j=0; j<options.length; j++){
ManyConstructors ref = makeRef(i,j);
ManyConstructors test = (ManyConstructors)
MetaClass.create(CLASS+"$ManyConstructors")
.createInstance(options[i], options[j]);
assertEquals(ref, test);
}
}
}
@Test
public void testPrimitives(){
// pass a value as a class
MetaClass.create(CLASS+"$Primitive").createInstance(new Integer(7));
MetaClass.create(CLASS+"$Primitive").createInstance(new Double(7));
// pass a value as a primitive
MetaClass.create(CLASS+"$Primitive").createInstance(7);
MetaClass.create(CLASS+"$Primitive").createInstance(2.8);
//(fail)
try{
MetaClass.create(CLASS+"$Primitive").createInstance(7L);
} catch(MetaClass.ClassCreationException e){
assertTrue("Should not be able to case Long int Primitive()", true);
}
}
@Test
public void testCastSimple() {
assertEquals(new Double(1.0), MetaClass.cast("1.0", Double.class));
assertEquals(new Integer(1), MetaClass.cast("1", Integer.class));
assertEquals(new Integer(1), MetaClass.cast("1.0", Integer.class));
assertEquals(new Long(1L), MetaClass.cast("1.0", Long.class));
assertEquals(new Short((short) 1), MetaClass.cast("1.0", Short.class));
assertEquals(new Byte((byte) 1), MetaClass.cast("1.0", Byte.class));
assertEquals("Hello", MetaClass.cast("Hello", String.class));
assertEquals(true, MetaClass.cast("true", Boolean.class));
assertEquals(true, MetaClass.cast("1", Boolean.class));
assertEquals(false, MetaClass.cast("False", Boolean.class));
assertEquals(new File("/path/to/file"), MetaClass.cast("/path/to/file", File.class));
}
@Test
public void testCastArray() {
Integer[] ints1 = MetaClass.cast("[1,2,3]", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints1);
Integer[] ints2 = MetaClass.cast("(1,2,3)", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints2);
Integer[] ints3 = MetaClass.cast("1, 2, 3", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints3);
Integer[] ints4 = MetaClass.cast("1 2 3", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints4);
Integer[] ints5 = MetaClass.cast("1 2 3", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints5);
Integer[] ints6 = MetaClass.cast("\n1 \n\n 2 3", Integer[].class);
assertArrayEquals(new Integer[]{1,2,3}, ints6);
Integer[] intsEmpty = MetaClass.cast("", Integer[].class);
assertArrayEquals(new Integer[]{}, intsEmpty);
}
@Test
public void testCastStringArray() throws IOException {
String[] strings1 = MetaClass.cast("[a,b,c]", String[].class);
assertArrayEquals(new String[]{"a", "b", "c"}, strings1);
String string1 = Files.createTempFile("TestCastString", "tmp").toString();
String string2 = Files.createTempFile("TestCastString", "tmp").toString();
String[] strings2 = MetaClass.cast("['" + string1 + "','" + string2 + "']", String[].class);
assertArrayEquals(new String[]{string1, string2}, strings2);
String[] strings3 = MetaClass.cast("['a','b','c']", String[].class);
assertArrayEquals(new String[]{"a", "b", "c"}, strings3);
}
private static enum Fruits {
APPLE,
Orange,
grape
}
@Test
public void testCastEnum() {
assertEquals(Fruits.APPLE, MetaClass.cast("APPLE", Fruits.class));
assertEquals(Fruits.APPLE, MetaClass.cast("apple", Fruits.class));
assertEquals(Fruits.APPLE, MetaClass.cast("Apple", Fruits.class));
assertEquals(Fruits.APPLE, MetaClass.cast("aPPlE", Fruits.class));
assertEquals(Fruits.Orange, MetaClass.cast("orange", Fruits.class));
assertEquals(Fruits.grape, MetaClass.cast("grape", Fruits.class));
assertEquals(Fruits.grape, MetaClass.cast("Grape", Fruits.class));
assertEquals(Fruits.grape, MetaClass.cast("GRAPE", Fruits.class));
}
@Test
public void testCastCollection() {
Set<String> set = new HashSet<String>();
set.add("apple");
set.add("banana");
Set<String> castedSet = MetaClass.cast("[apple, banana]", Set.class);
Set<String> castedSet2 = MetaClass.cast("[apple , banana ]", Set.class);
Set<String> castedSet3 = MetaClass.cast("{apple , banana }", Set.class);
assertEquals(set, castedSet);
assertEquals(set, castedSet2);
assertEquals(set, castedSet3);
List<String> list = new LinkedList<String>();
list.add("apple");
list.add("banana");
List<String> castedList = MetaClass.cast("[apple, banana]", List.class);
assertEquals(list, castedList);
}
private static class Pointer<E> {
public E value;
public Pointer(E value) {
this.value = value;
}
@SuppressWarnings("UnusedDeclaration") // used via reflection
public static <E> Pointer<E> fromString(String value) {
E v = MetaClass.castWithoutKnowingType(value);
return new Pointer<E>(v);
}
}
@Test
public void testCastMap() {
Map<String, String> a = MetaClass.cast("{ a -> 1, b -> 2 }", Map.class);
assertEquals(2, a.size());
assertEquals("1", a.get("a"));
assertEquals("2", a.get("b"));
Map<String, String> b = MetaClass.cast("a => 1, b -> 2", Map.class);
assertEquals(2, b.size());
assertEquals("1", b.get("a"));
assertEquals("2", b.get("b"));
Map<String, String> c = MetaClass.cast("[a->1;b->2]", Map.class);
assertEquals(2, c.size());
assertEquals("1", c.get("a"));
assertEquals("2", c.get("b"));
Map<String, String> d = MetaClass.cast("\n\na->\n1\n\n\nb->2", Map.class);
assertEquals(2, d.size());
assertEquals("1", d.get("a"));
assertEquals("2", d.get("b"));
}
@Test
public void testCastRegression() {
// Generics ordering (integer should go relatively early)
Pointer<Integer> x1 = MetaClass.cast("1", Pointer.class);
assertEquals(1, x1.value.intValue());
}
private static class FromStringable {
public final String myContents;
private FromStringable(String contents) { myContents = contents; }
public static FromStringable fromString(String str) {
return new FromStringable(str);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FromStringable)) return false;
FromStringable that = (FromStringable) o;
if (myContents != null ? !myContents.equals(that.myContents) : that.myContents != null) return false;
return true;
}
@Override
public int hashCode() {
return myContents != null ? myContents.hashCode() : 0;
}
}
@Test
public void testCastFromString() {
assertEquals(new FromStringable("foo"), MetaClass.cast("foo", FromStringable.class));
assertEquals(new FromStringable("bar"), MetaClass.cast("bar", FromStringable.class));
}
@Test
public void testCastStream() {
assertEquals(System.out, MetaClass.cast("stdout", OutputStream.class));
assertEquals(System.out, MetaClass.cast("out", OutputStream.class));
assertEquals(System.err, MetaClass.cast("stderr", OutputStream.class));
assertEquals(System.err, MetaClass.cast("err", OutputStream.class));
assertEquals(ObjectOutputStream.class, MetaClass.cast("err", ObjectOutputStream.class).getClass());
}
// TODO(gabor) this would be kind of cool to implement
/*
@Test
@Ignore
public void testVariableArgConstructor(){
VarArgs a = MetaClass.create(CLASS+"$VarArgs").createInstance(1,2,3);
assertEquals(3, a.a.length);
assertTrue(a.a[0] == 1);
assertTrue(a.a[1] == 2);
assertTrue(a.a[2] == 3);
}
*/
}