package net.time4j;
import net.time4j.engine.ChronoElement;
import net.time4j.format.CalendarText;
import net.time4j.scale.TimeScale;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(JUnit4.class)
public class SerializationTest {
private static final int N = 1000;
private static final int GRAPH_SIZE = 50;
private boolean output = false;
@Before
public void setUp() {
try {
this.output = false;
this.sizeOfDate();
this.sizeOfTime();
} catch (Exception ex) {
// ignore exceptions in warm-up phase
} finally {
this.output = true;
}
}
@Test
public void roundtripOfDate()
throws IOException, ClassNotFoundException {
int len1 = roundtrip(PlainDate.of(2100, 4, 30));
int len2 = roundtrip(PlainDate.of(1849, 4, 30));
int len3 = roundtrip(PlainDate.of(-20000, 4, 30));
assertThat(len2 - len1, is(1));
assertThat(len3 - len2, is(2));
}
@Test
public void sizeOfDate()
throws IOException, ClassNotFoundException {
Object[] sers = new Object[GRAPH_SIZE];
for (int i = 0; i < sers.length; i++) {
sers[i] = PlainDate.of(2012 + i, 2, 28);
}
Info info = analyze("[PlainDate]", sers);
assertThat(info.first, is(41));
assertThat(info.next, is(12));
}
@Test
public void roundtripOfTime()
throws IOException, ClassNotFoundException {
roundtrip(PlainTime.of(12));
roundtrip(PlainTime.of(12, 24));
roundtrip(PlainTime.of(12, 24, 52));
roundtrip(PlainTime.of(12, 24, 52, 123456789));
}
@Test
public void sizeOfTime()
throws IOException, ClassNotFoundException {
Object[] sers = new Object[GRAPH_SIZE];
for (int i = 0; i < sers.length; i++) {
sers[i] = PlainTime.of(13, 52, i % 10, 0);
}
Info info = analyze("[PlainTime]", sers);
assertThat(info.first, is(41));
assertThat(info.next, is(12));
}
@Test
public void roundtripOfTimestamp()
throws IOException, ClassNotFoundException {
roundtrip(PlainTimestamp.of(2012, 2, 29, 15, 59, 30));
}
@Test
public void sizeOfTimestamp()
throws IOException, ClassNotFoundException {
Object[] sers = new Object[GRAPH_SIZE];
for (int i = 0; i < sers.length; i++) {
sers[i] = PlainTimestamp.of(2012 + i, 12, 30, 13, i % 60);
}
Info info = analyze("[PlainTimestamp]", sers);
assertThat(info.first, is(42)); // old = 62
assertThat(info.next, is(14)); // old = 34
}
@Test
public void roundtripOfWeekmodel()
throws IOException, ClassNotFoundException {
int result =
roundtrip(
Weekmodel.ISO,
Weekmodel.of(Locale.US),
Weekmodel.of(new Locale("", "YE")));
assertThat(
(result == 63 || result == 62), // depends on if i18n-module exists
is(true)); // erstes, zweites und drittes Datenpaket
}
@SuppressWarnings("unchecked")
@Test
public void roundtripOfWeekmodelElement()
throws IOException, ClassNotFoundException {
ChronoElement<Integer> element = Weekmodel.ISO.weekOfYear();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(element);
byte[] data = baos.toByteArray();
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Object ser = ois.readObject();
ois.close();
assertThat(ser == element, is(true)); // test of readResolve
assertThat(PlainDate.of(2012, 1, 1).get((ChronoElement<Integer>) ser), is(Integer.valueOf(52)));
}
@Test
public void roundTripOfMoment()
throws IOException, ClassNotFoundException {
roundtrip(
Moment.UNIX_EPOCH,
Moment.of(1341100824, 987654321, TimeScale.UTC));
}
@Test
public void sizeOfMoment()
throws IOException, ClassNotFoundException {
Object[] sers = new Object[GRAPH_SIZE];
int offset = 2 * 365 * 86400;
for (int i = 0; i < sers.length; i++) {
sers[i] =
Moment.of(1341100798 + i - offset, 123456789, TimeScale.UTC);
}
Info info = analyze("[MOMENT]", sers);
assertThat(info.first, is(51));
assertThat(info.next, is(22));
}
@Test
public void roundTripOfDuration()
throws IOException, ClassNotFoundException {
roundtrip(
Duration.ofZero(),
Duration.of(4, ClockUnit.HOURS),
Duration.ofCalendarUnits(0, 13, 5));
}
@Test
public void sizeOfDuration()
throws IOException, ClassNotFoundException {
Object[] sers = new Object[GRAPH_SIZE];
for (int i = 0; i < sers.length; i++) {
sers[i] = Duration.ofCalendarUnits(i, i % 12, 30);
}
Info info = analyze("[Duration]", sers);
assertThat(info.first, is(126));
assertThat(info.next, is(47));
}
@Test
public void roundTripOfZonalDateTime() throws IOException, ClassNotFoundException {
ZonalDateTime zdt = Moment.UNIX_EPOCH.inZonalView("Europe/Berlin");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
zdt.write(oos);
byte[] data = baos.toByteArray();
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
ZonalDateTime ser = ZonalDateTime.read(ois);
ois.close();
assertThat(zdt.equals(ser), is(true));
}
@Test
public void roundTripOfDayPeriodElements() throws IOException, ClassNotFoundException {
Object o1 = new DayPeriod.Element(true, Locale.ENGLISH, CalendarText.ISO_CALENDAR_TYPE);
Object o2 = new DayPeriod.Element(false, Locale.GERMAN, CalendarText.ISO_CALENDAR_TYPE);
Map<PlainTime, String> custom = new HashMap<PlainTime, String>();
custom.put(PlainTime.midnightAtStartOfDay(), "midnight");
custom.put(PlainTime.of(0, 1), "night");
custom.put(PlainTime.of(6, 30), "morning");
custom.put(PlainTime.of(12), "noon");
custom.put(PlainTime.of(12, 1), "afternoon");
custom.put(PlainTime.of(18, 30), "evening");
Object o3 = new DayPeriod.Element(false, DayPeriod.of(custom));
roundtrip(o1, o2, o3);
}
@Test(expected=NotSerializableException.class)
public void dayPeriodNotSerializable() throws IOException, ClassNotFoundException {
roundtrip(DayPeriod.of(Locale.ENGLISH));
}
private Info analyze(String msg, Object[] sers)
throws IOException, ClassNotFoundException {
// Maßzahlen für Netzlaufzeit
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(sers[0]);
int first = baos.size();
for (int i = 1; i < sers.length; i++) {
oos.writeObject(sers[i]);
}
oos.close();
int next = ((baos.size() - first) / (sers.length - 1));
if (this.output) {
System.out.println("FIRST: " + first);
System.out.println("NEXT: " + next);
System.out.println("AVG: " + (baos.size() / sers.length));
} else {
return null;
}
// Maßzahl für Serialisierungsaufwand
baos = new ByteArrayOutputStream(sers.length * (next + 1));
long t0 = System.nanoTime();
for (int i = 0; i < N; i++) {
baos.reset();
oos = new ObjectOutputStream(baos);
for (int j = 0; j < sers.length; j++) {
oos.writeObject(sers[j]);
}
oos.close();
}
long t1 = System.nanoTime();
System.out.printf(msg + " Writing: %d%n", (t1 - t0) / 1000000);
// Maßzahl für Deserialisierungsaufwand
byte[] data = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
t0 = System.nanoTime();
for (int i = 0; i < N; i++) {
bais.reset();
ObjectInputStream ois = new ObjectInputStream(bais);
for (int j = 0; j < sers.length; j++) {
ois.readObject();
}
ois.close();
}
t1 = System.nanoTime();
System.out.printf(msg + " Reading: %d%n", (t1 - t0) / 1000000);
return new Info(first, next);
}
private static int roundtrip(Object... obj)
throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
for (int i = 0; i < obj.length; i++) {
oos.writeObject(obj[i]);
}
byte[] data = baos.toByteArray();
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
for (int i = 0; i < obj.length; i++) {
assertThat(ois.readObject(), is(obj[i]));
}
ois.close();
return data.length;
}
private static class Info {
final int first;
final int next;
Info(int first, int next) {
super();
this.first = first;
this.next = next;
}
}
}