package com.openxc.messages.streamers; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import com.openxc.messages.NamedVehicleMessage; import com.openxc.messages.SerializationException; import com.openxc.messages.SimpleVehicleMessage; import com.openxc.messages.VehicleMessage; @RunWith(RobolectricTestRunner.class) public class BinaryStreamerTest { BinaryStreamer streamer; SimpleVehicleMessage message = new SimpleVehicleMessage("foo", "bar"); @Before public void setup() { streamer = new BinaryStreamer(); } @Test public void emptyHasNoMessages() { assertThat(streamer.parseNextMessage(), nullValue()); } @Test public void deserializeBadLengthReturnsNull() throws SerializationException { byte[] data = new byte[]{0,1,2,3,4}; streamer.receive(data, data.length); assertThat(streamer.parseNextMessage(), nullValue()); } @Test(expected=SerializationException.class) public void serializeEmptyFails() throws SerializationException { streamer.serializeForStream(new VehicleMessage()); } @Test public void receiveLessThanFullBufferDoesntGrabAll() throws SerializationException { byte[] serialized = streamer.serializeForStream(message); streamer.receive(serialized, serialized.length / 2); assertThat(streamer.parseNextMessage(), nullValue()); } @Test public void readingGenericThenSpecific() throws SerializationException { NamedVehicleMessage namedMessage = new NamedVehicleMessage("baz"); byte[] bytes = streamer.serializeForStream(namedMessage); streamer.receive(bytes, bytes.length); bytes = streamer.serializeForStream(message); streamer.receive(bytes, bytes.length); assertThat(streamer.parseNextMessage(), equalTo((VehicleMessage) namedMessage)); assertThat(streamer.parseNextMessage(), equalTo((VehicleMessage) message)); } @Test public void readLinesOne() throws SerializationException { byte[] serialized = streamer.serializeForStream(message); streamer.receive(serialized, serialized.length); VehicleMessage deserialized = streamer.parseNextMessage(); assertThat(deserialized, notNullValue()); assertThat(deserialized, instanceOf(NamedVehicleMessage.class)); NamedVehicleMessage deserializedMessage = (NamedVehicleMessage) deserialized; assertThat(message, equalTo(deserializedMessage)); assertThat(streamer.parseNextMessage(), nullValue()); } @Test public void leavePartial() throws SerializationException { byte[] bytes = streamer.serializeForStream(message); streamer.receive(bytes, bytes.length); NamedVehicleMessage namedMessage = new NamedVehicleMessage("baz"); bytes = streamer.serializeForStream(namedMessage); streamer.receive(bytes, bytes.length / 2); assertThat(streamer.parseNextMessage(), notNullValue()); assertThat(streamer.parseNextMessage(), nullValue()); } @Test public void completePartial() throws SerializationException { byte[] bytes = streamer.serializeForStream(message); streamer.receive(bytes, bytes.length); NamedVehicleMessage namedMessage = new NamedVehicleMessage("baz"); bytes = streamer.serializeForStream(namedMessage); streamer.receive(bytes, bytes.length / 2); assertThat(streamer.parseNextMessage(), notNullValue()); int remainingBytes = bytes.length / 2; byte[] remainder = new byte[remainingBytes]; System.arraycopy(bytes, remainingBytes, remainder, 0, remainingBytes); streamer.receive(remainder, remainingBytes); assertThat(streamer.parseNextMessage(), notNullValue()); assertThat(streamer.parseNextMessage(), nullValue()); } @Test public void deserializeSerialized() throws SerializationException { byte[] data = streamer.serializeForStream(message); streamer.receive(data, data.length); VehicleMessage deserialized = streamer.parseNextMessage(); assertEquals(message, deserialized); } @Test public void dontDeserializeIfStreamTooShort() throws SerializationException { byte[] data = streamer.serializeForStream(message); byte[] half = new byte[data.length]; System.arraycopy(data, 0, half, 0, data.length / 2); streamer.receive(half, data.length / 2); assertThat(streamer.parseNextMessage(), nullValue()); System.arraycopy(data, data.length / 2, half, 0, data.length - data.length / 2); streamer.receive(half, half.length); VehicleMessage deserialized = streamer.parseNextMessage(); assertEquals(message, deserialized); } // @Test // TODO the binary deserialization can get in a really messed up state if it // gets too far off, but i can't seem to reliably trip it in a test. it's // fixed in code now and works well over Bluetooth, but I think we could // make it better. // public void ignoreJunkDataInFront() throws SerializationException { // byte[] data = streamer.serializeForStream(message); // byte[] junk = new byte[] { 0x12, 0x0b }; // byte[] dataWithJunkPrefix = new byte[data.length + junk.length]; // System.arraycopy(junk, 0, dataWithJunkPrefix, 0, junk.length); // System.arraycopy(data, 0, dataWithJunkPrefix, junk.length, data.length); // streamer.receive(dataWithJunkPrefix, dataWithJunkPrefix.length); // VehicleMessage deserialized = streamer.parseNextMessage(); // assertEquals(message, deserialized); // } @Test public void logTransferStatsAfterMegabyte() throws SerializationException { byte[] data = streamer.serializeForStream(message); for(int i = 0; i < 10000; i++) { streamer.receive(data, data.length); } for(int i = 0; i < 10000; i++) { VehicleMessage deserialized = streamer.parseNextMessage(); assertEquals(message, deserialized); } } }