blob: 576fea710e9cfa9a8ff30ef6d1ff24cb3f0fafb6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.openjpa.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.openjpa.kernel.FillStrategy;
import org.apache.openjpa.kernel.ResultShape;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestResultShape {
@Test
public void testPrimitiveShapeIsImmutable() {
ResultShape<Object> shape = new ResultShape<>(Object.class, true);
assertCategory(shape, true, false, false);
assertEquals(FillStrategy.Assign.class, shape.getStrategy().getClass());
try {
shape.add(int.class);
fail(shape + " should not allow adding other shapes");
} catch (UnsupportedOperationException e) {
}
try {
shape.nest(Object[].class, new FillStrategy.Array(Object[].class), int.class, double.class);
fail(shape + " should not allow nesting other shapes");
} catch (UnsupportedOperationException e) {
}
}
@Test
public void testArrayIsMutable() {
ResultShape<Object[]> shape = new ResultShape<>(Object[].class);
assertCategory(shape, false, true, false);
assertEquals(FillStrategy.Array.class, shape.getStrategy().getClass());
shape.add(int.class, double.class); // will add primitive shapes
assertCategory(shape, false, true, false);
ResultShape<Object> primitiveShape = new ResultShape<>(Object.class, true);
shape.nest(primitiveShape);
assertCategory(shape, false, true, false);
ResultShape<Object[]> nonPrimitiveShape = new ResultShape<>(Object[].class);
nonPrimitiveShape.add(int.class, double.class);
assertCategory(nonPrimitiveShape, false, true, false);
shape.nest(nonPrimitiveShape);
assertCategory(shape, false, true, true);
}
@Test
public void testMethodImpliesMapStrategy() {
FillStrategy<Map> strategy = new FillStrategy.Map<>(method(Map.class, "put", Object.class, Object.class));
ResultShape<Map> mapShape = new ResultShape<>(Map.class, strategy, true);
assertCategory(mapShape, true, false, false);
assertEquals(FillStrategy.Map.class, mapShape.getStrategy().getClass());
}
@Test
public void testShapeWithConstrcutorStrategy() {
FillStrategy<List> strategy = new FillStrategy.NewInstance<>(constructor(ArrayList.class, int.class));
ResultShape<List> listShape = new ResultShape<>(List.class, strategy);
assertCategory(listShape, false, true, false);
assertEquals(FillStrategy.NewInstance.class, listShape.getStrategy().getClass());
}
@Test
public void testGetCompositeTypes() {
ResultShape<Object[]> root = new ResultShape<>(Object[].class);
FillStrategy<Bar> strategy1 = new FillStrategy.NewInstance<>(Bar.class);
ResultShape<Bar> bar1 = new ResultShape<>(Bar.class, strategy1, false);
bar1.add(int.class);
FillStrategy<Foo> strategy2 = new FillStrategy.NewInstance<>(constructor(Foo.class, short.class, Bar.class));
ResultShape<Foo> fooBarConstructor = new ResultShape<>(Foo.class, strategy2);
fooBarConstructor.add(short.class);
fooBarConstructor.nest(bar1);
root.add(Foo.class, Object.class);
root.nest(fooBarConstructor);
ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
root.nest(bar2);
assertEquals("Object[]{Foo, Object, Foo{short, Bar{int}}, Bar}", root.toString());
assertEquals(Arrays.asList(Foo.class, Object.class, short.class, int.class, Bar.class),
root.getCompositeTypes());
assertEquals(Arrays.asList(Foo.class, Object.class, Foo.class, Bar.class), root.getTypes());
assertEquals(5, root.argLength());
assertEquals(4, root.length());
}
@Test
public void testRecursiveNestingIsNotAllowed() {
ResultShape<Object[]> root = new ResultShape<>(Object[].class);
ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
bar1.add(int.class);
ResultShape<Foo> fooBarConstructor = new ResultShape<Foo>(Foo.class,
new FillStrategy.NewInstance(constructor(Foo.class, short.class, Bar.class)));
fooBarConstructor.add(short.class);
fooBarConstructor.nest(bar1);
root.add(Foo.class, Object.class);
root.nest(fooBarConstructor);
ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
root.nest(bar2);
try {
bar1.nest(fooBarConstructor);
fail("Expecetd recursive nesting error in nest " + fooBarConstructor + " in " + bar1);
} catch (IllegalArgumentException e) {
}
}
@Test
public void testFill() {
//Fill this shape: Foo{short, Bar{String, Double}};
ResultShape<Foo> foo = new ResultShape<Foo>(Foo.class, new FillStrategy.NewInstance(Foo.class), false);
ResultShape<Bar> bar = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
bar.add(String.class, Double.class);
foo.add(short.class);
foo.nest(bar);
assertEquals("Foo{short, Bar{String, Double}}", foo.toString());
//from this array: 200s, "bar1", 12.3d)
Object[] values = {(short)200, "bar1", 12.3d};
Class[] types = {short.class, String.class, Double.class};
String[] aliases = {"foo-short", "foo-bar-string", "foo-bar-Double"};
Foo result = foo.pack(values, types, aliases);
assertEquals(200, result.shrt);
assertEquals("bar1", result.b.string);
assertEquals(12.3, (double) result.b.Dbl, 0.1d);
}
@Test
public void testFill2() {
//Fill this shape: Object[]{Foo, Object, Foo{short, Bar{String, Double}}, Bar{double}};
ResultShape<Object[]> root = new ResultShape<>(Object[].class);
ResultShape<Bar> bar1 = new ResultShape<>(Bar.class, new FillStrategy.NewInstance<>(Bar.class));
bar1.add(String.class, Double.class);
ResultShape<Foo> fooBarConstr = new ResultShape<>(Foo.class, new FillStrategy.NewInstance<>(Foo.class));
fooBarConstr.add(short.class);
fooBarConstr.nest(bar1);
ResultShape<Bar> bar2 = new ResultShape<>(Bar.class, new FillStrategy.NewInstance<>(Bar.class));
bar2.add(double.class);
root.add(Foo.class, Object.class);
root.nest(fooBarConstr);
root.nest(bar2);
assertEquals("Object[]{Foo, Object, Foo{short, Bar{String, Double}}, Bar{double}}", root.toString());
//from this array: new Foo(), new Object(), 200s, "bar1", 12.3d, 45.6d)
Object[] values = {new Foo(), new Object(), 200, "bar1", 12.3d, 45.6d};
Class[] types = {Foo.class, Object.class, short.class, String.class, Double.class, double.class};
String[] aliases = {"Foo", "Object", "foo-short", "foo-bar-string", "foo-bar-Double", "bar-double"};
Object[] result = root.pack(values, types, aliases);
assertEquals(4, result.length);
assertEquals(Foo.class, result[0].getClass());
assertEquals(Object.class, result[1].getClass());
assertEquals(Foo.class, result[2].getClass());
assertEquals(Bar.class, result[3].getClass());
assertEquals(200, ((Foo)result[2]).shrt);
assertEquals("bar1", ((Foo)result[2]).b.string);
assertEquals(12.3, (double)((Foo)result[2]).b.Dbl, 0.1d);
assertEquals(45.6, ((Bar)result[3]).dbl, 0.1d);
}
void assertCategory(ResultShape<?> s, boolean primitive, boolean compound, boolean nesting) {
if (primitive)
assertTrue(s + " is not primitive", s.isPrimitive());
else
assertFalse(s + " is primitive", s.isPrimitive());
if (compound)
assertTrue(s + " is not compound", s.isCompound());
else
assertFalse(s + " is compound", s.isCompound());
if (nesting)
assertTrue(s + " is not nesting", s.isNesting());
else
assertFalse(s + " is nesting", s.isNesting());
}
void arrayEquals(Object[] a, Object[] b) {
assertEquals(a.length, b.length);
for (int i = 0; i < a.length; i++) {
assertEquals(i+"-th element not equal", a[i], b[i]);
}
}
<T> Constructor<T> constructor(Class<T> t, Class<?>...args) {
try {
return t.getConstructor(args);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
<T> Method method(Class<T> t, String name, Class<?>...args) {
try {
return t.getMethod(name, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static class Foo {
private String string;
private int i;
private short shrt;
private Bar b;
public Foo() {}
public Foo(String s, int i) {this.string = s; this.i = i;}
public Foo(short s, Bar b){this.shrt = s; this.b = b;}
@Override
public String toString() {
return "Foo(string='"+string+"' i="+i+" short="+shrt+" bar="+b+"";}
}
public static class Bar {
private String string;
private Double Dbl;
private double dbl;
public Bar() {}
public Bar(double d) {this.dbl = d;}
public Bar(String s, Double i) {this.string = s; this.Dbl = i;}
@Override
public String toString() {return "Bar(string='"+string+"' Dbl="+Dbl+" dbl="+dbl+"";}
}
}