From ff53b67e3d18741923f20b131a143b3931df3c71 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Sat, 19 Jun 2010 17:36:04 +0000 Subject: [PATCH] Test that @Transform works in its various supported use cases, and fails as early as possible in situations where the developer is fucking up. --- .../samskivert/depot/tests/TransformTest.java | 249 ++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/java/com/samskivert/depot/tests/TransformTest.java diff --git a/src/java/com/samskivert/depot/tests/TransformTest.java b/src/java/com/samskivert/depot/tests/TransformTest.java new file mode 100644 index 0000000..dee855b --- /dev/null +++ b/src/java/com/samskivert/depot/tests/TransformTest.java @@ -0,0 +1,249 @@ +// +// $Id$ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2010 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.tests; + +import java.lang.reflect.Field; +import java.util.Set; + +import org.junit.Test; + +import com.samskivert.depot.Key; +import com.samskivert.depot.expression.ColumnExp; + +import com.samskivert.depot.DepotRepository; +import com.samskivert.depot.PersistenceContext; +import com.samskivert.depot.PersistentRecord; +import com.samskivert.depot.Transformer; +import com.samskivert.depot.Transformers; +import com.samskivert.depot.annotation.Id; +import com.samskivert.depot.annotation.Transform; +import com.samskivert.depot.impl.FieldMarshaller; + +import static org.junit.Assert.*; + +/** + * Tests the @Transform annotation. + */ +public class TransformTest extends TestBase +{ + @Transform(CustomTypeTransformer.class) + public static class CustomType + { + public final String value; + + public CustomType (String value) { + this.value = value; + } + + @Override public boolean equals (Object other) { + return !(other instanceof CustomType) ? false : + value.equals(((CustomType)other).value); + } + + @Override public int hashCode () { + return value.hashCode(); + } + } + + @Transform(CustomTypeTransformer.class) + public static class InvalidCustomType + { + } + + @Transform(ShortEnumTransformer.class) + public static interface ShortEnum + { + public short toShort (); + } + + public enum Ordinal implements ShortEnum { + ONE(1), TWO(2), THREE(3); + + public short toShort () { + return _code; + } + + Ordinal (int code) { + _code = (short)code; + } + protected short _code; + } + + public static class CustomTypeTransformer implements Transformer + { + public String toPersistent (CustomType value) { + return value.value; + } + + public CustomType fromPersistent (Class ftype, String value) { + return new CustomType(value); + } + } + + public static class ShortEnumTransformer implements Transformer + { + public Short toPersistent (ShortEnum value) { + return value.toShort(); + } + public ShortEnum fromPersistent (Class ftype, Short value) { + @SuppressWarnings("unchecked") Class eclass = (Class)ftype; + return fromShort(eclass, value); + } + private enum Dummy implements ShortEnum { + DUMMY; + public short toShort () { return 0; } + }; + } + + public static class TransformRecord extends PersistentRecord + { + // AUTO-GENERATED: FIELDS START + public static final Class _R = TransformRecord.class; + public static final ColumnExp RECORD_ID = colexp(_R, "recordId"); + public static final ColumnExp STRINGS = colexp(_R, "strings"); + public static final ColumnExp CUSTOM = colexp(_R, "custom"); + public static final ColumnExp ORDINAL = colexp(_R, "ordinal"); + // AUTO-GENERATED: FIELDS END + + public static final int SCHEMA_VERSION = 1; + + @Id public int recordId; + + @Transform(Transformers.CommaSeparatedString.class) + public String[] strings; + + public CustomType custom; + + public Ordinal ordinal; + + // AUTO-GENERATED: METHODS START + /** + * Create and return a primary {@link Key} to identify a {@link TestRecord} + * with the supplied key values. + */ + public static Key getKey (int recordId) + { + return newKey(_R, recordId); + } + + /** Register the key fields in an order matching the getKey() factory. */ + static { registerKeyFields(RECORD_ID); } + // AUTO-GENERATED: METHODS END + } + + public static class BadTransformRecord extends PersistentRecord + { + @Transform(Transformers.CommaSeparatedString.class) + public Thread thread; + + public InvalidCustomType invalid; + } + + public static class TransformRepository extends DepotRepository + { + public TransformRepository (PersistenceContext ctx) { + super(ctx); + } + + public TransformRecord loadNoCache (int recordId) + { + return load(TransformRecord.getKey(recordId), CacheStrategy.NONE); + } + + @Override // from DepotRepository + protected void getManagedRecords (Set> classes) { + classes.add(TransformRecord.class); + } + } + + @Test public void testValidAnnotations () + throws NoSuchFieldException + { + Field field = TransformRecord.class.getField("strings"); + assertTrue(FieldMarshaller.createMarshaller(field) != null); + + field = TransformRecord.class.getField("custom"); + assertTrue(FieldMarshaller.createMarshaller(field).getClass(). + getName().endsWith("FieldMarshaller$TransformingMarshaller")); + } + + @Test public void testInvalidFieldAnnotation () + throws NoSuchFieldException + { + try { + Field field = BadTransformRecord.class.getField("thread"); + FieldMarshaller.createMarshaller(field); + fail(); + } catch (IllegalArgumentException iae) { + assertTrue(iae.getMessage().indexOf("@Transform error") != -1); + } + } + + @Test public void testInvalidTypeAnnotation () + throws NoSuchFieldException + { + try { + Field field = BadTransformRecord.class.getField("invalid"); + FieldMarshaller.createMarshaller(field); + fail(); + } catch (IllegalArgumentException iae) { + assertTrue(iae.getMessage().indexOf("@Transform error") != -1); + } + } + + @Test public void testCreateReadDelete () + { + TransformRecord in = new TransformRecord(); + in.recordId = 1; + in.strings = new String[] { "one", "two", "three" }; + in.custom = new CustomType("custom"); + in.ordinal = Ordinal.THREE; + _repo.insert(in); + + TransformRecord out = _repo.loadNoCache(in.recordId); + assertNotNull(out != null); // we got a result + assertTrue(in != out); // it didn't come from the cache + + // make sure all of the fields were marshalled and unmarshalled correctly + assertEquals(in.recordId, out.recordId); + assertArrayEquals(in.strings, out.strings); + assertEquals(in.custom, out.custom); + assertEquals(in.ordinal, out.ordinal); + + // finally clean up after ourselves + _repo.delete(TransformRecord.getKey(in.recordId)); + assertNull(_repo.loadNoCache(in.recordId)); + } + + protected static & ShortEnum> E fromShort (Class eclass, short code) + { + for (E value : eclass.getEnumConstants()) { + if (value.toShort() == code) { + return value; + } + } + throw new IllegalArgumentException(eclass + " has no value with code " + code); + } + + // the HSQL in-memory database persists for the lifetime of the VM, which means we have to + // clean up after ourselves in every test; thus we go ahead and share a repository + protected TransformRepository _repo = new TransformRepository(createPersistenceContext()); +}