1/******************************************************************************* 2 * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12package org.jacoco.core.data; 13 14import static org.junit.Assert.assertEquals; 15import static org.junit.Assert.assertFalse; 16import static org.junit.Assert.assertNotNull; 17import static org.junit.Assert.assertTrue; 18import static org.junit.Assert.fail; 19 20import java.io.ByteArrayInputStream; 21import java.io.ByteArrayOutputStream; 22import java.io.IOException; 23import java.io.OutputStream; 24import java.util.Arrays; 25import java.util.Random; 26 27import org.junit.Before; 28import org.junit.Test; 29 30/** 31 * Unit tests for {@link ExecutionDataReader} and {@link ExecutionDataWriter}. 32 * The tests don't care about the written binary format, they just verify 33 * symmetry. 34 */ 35public class ExecutionDataReaderWriterTest { 36 37 protected ByteArrayOutputStream buffer; 38 39 private ExecutionDataWriter writer; 40 41 private ExecutionDataStore store; 42 43 private SessionInfo sessionInfo; 44 45 private Random random; 46 47 @Before 48 public void setup() throws IOException { 49 buffer = new ByteArrayOutputStream(); 50 writer = createWriter(buffer); 51 store = new ExecutionDataStore(); 52 random = new Random(5); 53 } 54 55 @Test 56 public void testEmpty() throws IOException { 57 final ExecutionDataReader reader = createReader(); 58 reader.setSessionInfoVisitor(new ISessionInfoVisitor() { 59 public void visitSessionInfo(final SessionInfo info) { 60 fail("No data expected."); 61 } 62 }); 63 reader.setExecutionDataVisitor(new IExecutionDataVisitor() { 64 public void visitClassExecution(final ExecutionData data) { 65 fail("No data expected."); 66 } 67 }); 68 assertFalse(reader.read()); 69 } 70 71 @Test 72 public void testFlush() throws IOException { 73 final boolean[] flushCalled = new boolean[] { false }; 74 final OutputStream out = new OutputStream() { 75 @Override 76 public void write(int b) throws IOException { 77 } 78 79 @Override 80 public void flush() throws IOException { 81 flushCalled[0] = true; 82 } 83 }; 84 new ExecutionDataWriter(out).flush(); 85 assertTrue(flushCalled[0]); 86 } 87 88 @Test 89 public void testCustomBlocks() throws IOException { 90 buffer.write(-22); 91 buffer.write(-33); 92 final ExecutionDataReader reader = new ExecutionDataReader( 93 new ByteArrayInputStream(buffer.toByteArray())) { 94 95 @Override 96 protected boolean readBlock(byte blocktype) throws IOException { 97 switch (blocktype) { 98 case -22: 99 return true; 100 case -33: 101 return false; 102 } 103 return super.readBlock(blocktype); 104 } 105 }; 106 assertTrue(reader.read()); 107 } 108 109 @Test 110 public void testGetFileHeader() { 111 byte[] header = ExecutionDataWriter.getFileHeader(); 112 assertEquals(5, header.length); 113 assertEquals(0x01, 0xFF & header[0]); 114 assertEquals(0xC0, 0xFF & header[1]); 115 assertEquals(0xC0, 0xFF & header[2]); 116 final char version = ExecutionDataWriter.FORMAT_VERSION; 117 assertEquals(version >> 8, 0xFF & header[3]); 118 assertEquals(version & 0xFF, 0xFF & header[4]); 119 } 120 121 @Test 122 public void testMultipleHeaders() throws IOException { 123 new ExecutionDataWriter(buffer); 124 new ExecutionDataWriter(buffer); 125 new ExecutionDataWriter(buffer); 126 assertFalse(createReader().read()); 127 } 128 129 @Test(expected = IOException.class) 130 public void testInvalidMagicNumber() throws IOException { 131 buffer = new ByteArrayOutputStream(); 132 buffer.write(ExecutionDataWriter.BLOCK_HEADER); 133 buffer.write(0x12); 134 buffer.write(0x34); 135 createReader().read(); 136 } 137 138 @Test(expected = IOException.class) 139 public void testInvalidHeaderVersion() throws IOException { 140 buffer = new ByteArrayOutputStream(); 141 buffer.write(ExecutionDataWriter.BLOCK_HEADER); 142 buffer.write(0xC0); 143 buffer.write(0xC0); 144 final char version = ExecutionDataWriter.FORMAT_VERSION - 1; 145 buffer.write(version >> 8); 146 buffer.write(version & 0xFF); 147 createReader().read(); 148 } 149 150 @Test(expected = IOException.class) 151 public void testMissingHeader() throws IOException { 152 buffer.reset(); 153 writer.visitClassExecution(new ExecutionData(Long.MIN_VALUE, "Sample", 154 createData(0))); 155 createReaderWithVisitors().read(); 156 } 157 158 @Test(expected = IOException.class) 159 public void testUnknownBlock() throws IOException { 160 buffer.write(0xff); 161 createReader().read(); 162 } 163 164 @Test 165 public void testEmptyFile() throws IOException { 166 buffer = new ByteArrayOutputStream(); 167 createReader().read(); 168 } 169 170 // === Session Info === 171 172 @Test(expected = IOException.class) 173 public void testNoSessionInfoVisitor() throws IOException { 174 writer.visitSessionInfo(new SessionInfo("x", 0, 1)); 175 createReader().read(); 176 } 177 178 @Test 179 public void testSessionInfo() throws IOException { 180 writer.visitSessionInfo(new SessionInfo("TestSession", 181 2837123124567891234L, 3444234223498879234L)); 182 assertFalse(createReaderWithVisitors().read()); 183 assertNotNull(sessionInfo); 184 assertEquals("TestSession", sessionInfo.getId()); 185 assertEquals(2837123124567891234L, sessionInfo.getStartTimeStamp()); 186 assertEquals(3444234223498879234L, sessionInfo.getDumpTimeStamp()); 187 } 188 189 @Test(expected = RuntimeException.class) 190 public void testSessionInfoIOException() throws IOException { 191 final boolean[] broken = new boolean[1]; 192 final ExecutionDataWriter writer = createWriter(new OutputStream() { 193 @Override 194 public void write(int b) throws IOException { 195 if (broken[0]) { 196 throw new IOException(); 197 } 198 } 199 }); 200 broken[0] = true; 201 writer.visitSessionInfo(new SessionInfo("X", 0, 0)); 202 } 203 204 // === Execution Data === 205 206 @Test(expected = IOException.class) 207 public void testNoExecutionDataVisitor() throws IOException { 208 writer.visitClassExecution(new ExecutionData(Long.MIN_VALUE, "Sample", 209 createData(0))); 210 createReader().read(); 211 } 212 213 @Test 214 public void testMinClassId() throws IOException { 215 final boolean[] data = createData(0); 216 writer.visitClassExecution(new ExecutionData(Long.MIN_VALUE, "Sample", 217 data)); 218 assertFalse(createReaderWithVisitors().read()); 219 assertArrayEquals(data, store.get(Long.MIN_VALUE).getProbes()); 220 } 221 222 @Test 223 public void testMaxClassId() throws IOException { 224 final boolean[] data = createData(0); 225 writer.visitClassExecution(new ExecutionData(Long.MAX_VALUE, "Sample", 226 data)); 227 assertFalse(createReaderWithVisitors().read()); 228 assertArrayEquals(data, store.get(Long.MAX_VALUE).getProbes()); 229 } 230 231 @Test 232 public void testEmptyClass() throws IOException { 233 final boolean[] data = createData(0); 234 writer.visitClassExecution(new ExecutionData(3, "Sample", data)); 235 assertFalse(createReaderWithVisitors().read()); 236 assertArrayEquals(data, store.get(3).getProbes()); 237 } 238 239 @Test 240 public void testOneClass() throws IOException { 241 final boolean[] data = createData(5); 242 writer.visitClassExecution(new ExecutionData(3, "Sample", data)); 243 assertFalse(createReaderWithVisitors().read()); 244 assertArrayEquals(data, store.get(3).getProbes()); 245 } 246 247 @Test 248 public void testTwoClasses() throws IOException { 249 final boolean[] data1 = createData(5); 250 final boolean[] data2 = createData(7); 251 writer.visitClassExecution(new ExecutionData(333, "Sample", data1)); 252 writer.visitClassExecution(new ExecutionData(-45, "Sample", data2)); 253 assertFalse(createReaderWithVisitors().read()); 254 assertArrayEquals(data1, store.get(333).getProbes()); 255 assertArrayEquals(data2, store.get(-45).getProbes()); 256 } 257 258 @Test 259 public void testBigClass() throws IOException { 260 final boolean[] data = createData(117); 261 writer.visitClassExecution(new ExecutionData(123, "Sample", data)); 262 assertFalse(createReaderWithVisitors().read()); 263 assertArrayEquals(data, store.get(123).getProbes()); 264 } 265 266 @Test(expected = RuntimeException.class) 267 public void testExecutionDataIOException() throws IOException { 268 final boolean[] broken = new boolean[1]; 269 final ExecutionDataWriter writer = createWriter(new OutputStream() { 270 @Override 271 public void write(int b) throws IOException { 272 if (broken[0]) { 273 throw new IOException(); 274 } 275 } 276 }); 277 broken[0] = true; 278 writer.visitClassExecution(new ExecutionData(3, "Sample", createData(1))); 279 } 280 281 private ExecutionDataReader createReaderWithVisitors() throws IOException { 282 final ExecutionDataReader reader = createReader(); 283 reader.setExecutionDataVisitor(store); 284 reader.setSessionInfoVisitor(new ISessionInfoVisitor() { 285 public void visitSessionInfo(SessionInfo info) { 286 sessionInfo = info; 287 } 288 }); 289 return reader; 290 } 291 292 private boolean[] createData(final int probeCount) { 293 final boolean[] data = new boolean[random.nextInt(probeCount + 1)]; 294 for (int j = 0; j < data.length; j++) { 295 data[j] = random.nextBoolean(); 296 } 297 return data; 298 } 299 300 private void assertArrayEquals(final boolean[] expected, 301 final boolean[] actual) { 302 assertTrue(Arrays.equals(expected, actual)); 303 } 304 305 protected ExecutionDataWriter createWriter(OutputStream out) 306 throws IOException { 307 return new ExecutionDataWriter(out); 308 } 309 310 protected ExecutionDataReader createReader() throws IOException { 311 return new ExecutionDataReader(new ByteArrayInputStream( 312 buffer.toByteArray())); 313 } 314 315} 316