001: /*
002: * Copyright 2002 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: TestObject.java,v 1.8 2004/03/22 04:58:13 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.test;
012:
013: import com.triactive.jdo.store.OID;
014: import java.io.Serializable;
015: import java.util.ArrayList;
016: import java.util.Collection;
017: import java.util.HashMap;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Map.Entry;
021: import java.util.Random;
022: import javax.jdo.JDOHelper;
023:
024: public abstract class TestObject implements Cloneable, Serializable {
025: protected static Random r = new Random(0);
026:
027: public static boolean allowNegativeByteValues = true;
028:
029: protected byte nextByte() {
030: if (allowNegativeByteValues)
031: return (byte) (r.nextInt((int) Byte.MAX_VALUE * 2) - Byte.MAX_VALUE);
032: else
033: return (byte) r.nextInt((int) Byte.MAX_VALUE + 1);
034: }
035:
036: protected char nextCharacter() {
037: return (char) ('!' + r.nextInt(93));
038: }
039:
040: protected String nextString(int length) {
041: StringBuffer s = new StringBuffer();
042:
043: while (length-- > 0)
044: s.append(nextCharacter());
045:
046: return s.toString();
047: }
048:
049: protected byte[] nextBinary(int length) {
050: byte[] ba = new byte[length];
051:
052: for (int i = 0; i < length; ++i)
053: ba[i] = (byte) (r.nextInt((int) Byte.MAX_VALUE * 2) - Byte.MAX_VALUE);
054:
055: return ba;
056: }
057:
058: /*
059: * Indicates whether or not the next random nullable field value should be
060: * null. Returns true approx. 20% of the time.
061: */
062: protected boolean nextNull() {
063: return r.nextInt(5) < 1;
064: }
065:
066: public Object clone() {
067: Object obj = null;
068:
069: try {
070: obj = super .clone();
071: } catch (CloneNotSupportedException e) {
072: }
073:
074: return obj;
075: }
076:
077: public abstract void fillRandom();
078:
079: /**
080: * Indicates whether some other object is "equal to" this one. By comparing
081: * against an original copy of the object, <code>compareTo()</code> can be
082: * used to verify that the object has been written to a database and read
083: * back correctly.
084: *
085: * @param obj the reference object with which to compare
086: *
087: * @return <code>true</code> if this object is equal to the obj argument;
088: * <code>false</code> otherwise.
089: */
090:
091: public abstract boolean compareTo(Object obj);
092:
093: public boolean equals(Object obj) {
094: if (obj == this )
095: return true;
096:
097: Object id = JDOHelper.getObjectId(this );
098:
099: return id == null ? super .equals(obj) : id.equals(JDOHelper
100: .getObjectId(obj));
101: }
102:
103: public int hashCode() {
104: Object id = JDOHelper.getObjectId(this );
105:
106: return id == null ? super .hashCode() : id.hashCode();
107: }
108:
109: public String toString() {
110: StringBuffer s = new StringBuffer(getClass().getName() + ":");
111:
112: s.append(" JVM id = ").append(System.identityHashCode(this ));
113: s.append('\n');
114:
115: Object id = JDOHelper.getObjectId(this );
116: s.append(" JDO id = ").append(id);
117: if (id instanceof OID)
118: s.append(" (").append(((OID) id).longValue()).append(')');
119: s.append('\n');
120:
121: return s.toString();
122: }
123:
124: public static Object clone(Object o) {
125: if (o instanceof Number || o instanceof String
126: || o instanceof Boolean)
127: return o;
128:
129: try {
130: return o.getClass().getMethod("clone", null)
131: .invoke(o, null);
132: } catch (RuntimeException e) {
133: throw e;
134: } catch (Exception e) {
135: throw new RuntimeException("Clone failed", e);
136: }
137: }
138:
139: /**
140: * Compares two objects for equality.
141: * Returns true if and only if the two objects compare equal to each other.
142: * If the objects are an instance of TestObject the {@link #compareTo} is
143: * used, which ensures that the object's contents are compared and not just
144: * their JDO ID's.
145: * Otherwise the equals() method is used.
146: *
147: * @return <tt>true</tt> if the objects compare equal,
148: * <tt>false</tt> otherwise.
149: */
150:
151: public static boolean compareObject(Object o1, Object o2) {
152: if (o1 == null)
153: return o2 == null;
154: else if (o1 instanceof TestObject)
155: return ((TestObject) o1).compareTo(o2);
156: else
157: return o1.equals(o2);
158: }
159:
160: /**
161: * Compares two collections for equality.
162: * Returns true if and only if the two collections contain the same number
163: * of objects and each element of the first collection has exactly one
164: * corresponding element in the second collection that compares equal
165: * according to {@link #compareObject}.
166: *
167: * @return <tt>true</tt> if the collections compare equal,
168: * <tt>false</tt> otherwise.
169: */
170:
171: public static boolean compareCollection(Collection c1, Collection c2) {
172: if (c1 == null)
173: return c2 == null;
174: else if (c2 == null)
175: return false;
176:
177: if (c1.size() != c2.size())
178: return false;
179:
180: c2 = new ArrayList(c2);
181:
182: Iterator i = c1.iterator();
183:
184: while (i.hasNext()) {
185: Object obj = i.next();
186:
187: boolean found = false;
188: Iterator j = c2.iterator();
189:
190: while (j.hasNext()) {
191: if (compareObject(obj, j.next())) {
192: j.remove();
193: found = true;
194: break;
195: }
196: }
197:
198: if (!found)
199: return false;
200: }
201:
202: return c2.isEmpty();
203: }
204:
205: /**
206: * Compares two maps.
207: * Returns true if and only if the two maps contain the same number of
208: * entries and each entry of the first map has a corresponding entry in the
209: * second map whose key and value both compare equal according to
210: * {@link #compareObject}.
211: *
212: * @return <tt>true</tt> if the maps compare equal,
213: * <tt>false</tt> otherwise.
214: */
215:
216: public static boolean compareMap(Map m1, Map m2) {
217: if (m1 == null)
218: return m2 == null;
219: else if (m2 == null)
220: return false;
221:
222: if (m1.size() != m2.size())
223: return false;
224:
225: m2 = new HashMap(m2);
226:
227: Iterator i = m1.entrySet().iterator();
228:
229: while (i.hasNext()) {
230: Entry e1 = (Entry) i.next();
231:
232: boolean found = false;
233: Iterator j = m2.entrySet().iterator();
234:
235: while (j.hasNext()) {
236: Entry e2 = (Entry) j.next();
237:
238: if (compareObject(e1.getKey(), e2.getKey())
239: && compareObject(e1.getValue(), e2.getValue())) {
240: j.remove();
241: found = true;
242: break;
243: }
244: }
245:
246: if (!found)
247: return false;
248: }
249:
250: return m2.isEmpty();
251: }
252: }
|