diff src/tests/gov/nasa/jpf/util/SplitInputStreamTest.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/gov/nasa/jpf/util/SplitInputStreamTest.java	Fri Jan 23 10:14:01 2015 -0800
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2014, United States Government, as represented by the
+ * Administrator of the National Aeronautics and Space Administration.
+ * All rights reserved.
+ *
+ * The Java Pathfinder core (jpf-core) platform is licensed under the
+ * Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ * 
+ *        http://www.apache.org/licenses/LICENSE-2.0. 
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package gov.nasa.jpf.util;
+
+import gov.nasa.jpf.util.test.TestJPF;
+import gov.nasa.jpf.vm.Verify;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.security.SecureRandom;
+import java.util.Random;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class SplitInputStreamTest extends TestJPF {
+
+  private static final Random s_random = Verify.isRunningInJPF() ? null : new SecureRandom();
+  private static final String s_jpfArgs[] = new String[]{
+    "+listener+=,gov.nasa.jpf.listener.PreciseRaceDetector",
+    "+classpath=build/main"
+  };
+  private SplitInputStream m_fixture;
+  private InputStream m_input;
+  private byte m_expect[];
+
+  @Before
+  public void before() throws IOException {
+    initialize(10, SplitInputStream.INITIAL_BUFFER_SIZE);
+  }
+
+  public void initialize(int length, int bufferSize) throws IOException {
+    ByteArrayInputStream source;
+    int i;
+
+    m_expect = new byte[length];
+
+    if (s_random != null) {
+      s_random.nextBytes(m_expect);
+    } else {
+      for (i = m_expect.length; --i >= 0;) {
+        m_expect[i] = (byte) i;
+      }
+    }
+
+    source = new ByteArrayInputStream(m_expect);
+    m_fixture = new SplitInputStream(source, 2, bufferSize);
+    m_input = m_fixture.getStream(0);
+
+    assertEquals(2, m_fixture.getStreamCount());
+  }
+
+  @After
+  public void after() throws IOException {
+    InputStream input;
+    int i, j;
+
+    for (i = m_fixture.getStreamCount(); --i > 0;) {
+      input = m_fixture.getStream(i);
+
+      for (j = m_expect.length - input.available(); j < m_expect.length; j++) {
+        assertEquals(m_expect[j] & 0x0FF, input.read());
+      }
+
+      assertEquals(-1, input.read());
+      assertEquals(-1, input.read(new byte[1]));
+    }
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void passNullPointerToConstructor() throws IOException {
+    InputStream source;
+
+    source = null;
+
+    new SplitInputStream(source, 1);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void passZeroStreamsToConstructor() throws IOException {
+    InputStream source;
+
+    source = new ByteArrayInputStream(m_expect);
+
+    new SplitInputStream(source, 0);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void passZeroBufferSizeToConstructor() throws IOException {
+    InputStream source;
+
+    source = new ByteArrayInputStream(m_expect);
+
+    new SplitInputStream(source, 2, 0);
+  }
+
+  @Test
+  public void readByte() throws IOException {
+    assertEquals(m_expect[0] & 0x0FF, m_input.read());
+  }
+
+  @Test
+  public void readEveryByteValue() throws IOException {
+    ByteArrayInputStream source;
+    int i;
+
+    m_expect = new byte[256];
+
+    for (i = 256; --i >= 0;) {
+      m_expect[i] = (byte) i;
+    }
+
+    source = new ByteArrayInputStream(m_expect);
+    m_fixture = new SplitInputStream(source, 2, 256);
+    m_input = m_fixture.getStream(0);
+
+    for (i = 0; i < 256; i++) {
+      assertEquals(i, m_input.read());
+    }
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void readNullBuffer() throws IOException {
+    m_input.read(null, 0, 1);
+  }
+
+  @Test(expected = IndexOutOfBoundsException.class)
+  public void readIndexNegOne() throws IOException {
+    m_input.read(new byte[0], -1, 0);
+  }
+
+  @Test(expected = IndexOutOfBoundsException.class)
+  public void readLengthNegOne() throws IOException {
+    m_input.read(new byte[0], 0, -1);
+  }
+
+  @Test(expected = IndexOutOfBoundsException.class)
+  public void readBeyondEnd() throws IOException {
+    m_input.read(new byte[16], 8, 9);
+  }
+
+  @Test
+  public void readLengthZero() throws IOException {
+    m_input.read(new byte[1], 0, 0);
+    assertEquals(m_expect[0] & 0x0FF, m_input.read());
+  }
+
+  @Test
+  public void readArray() throws IOException {
+    int offset, length, delta;
+    byte buffer[];
+
+    length = m_expect.length;
+    buffer = new byte[length];
+
+    for (offset = 0; offset < length; offset += delta) {
+      delta = m_input.read(buffer);
+
+      assertTrue(delta >= 0);
+    }
+
+    assertArrayEquals(m_expect, buffer);
+  }
+
+  @Test
+  public void readArrayEveryByteValue() throws IOException {
+    ByteArrayInputStream source;
+    int i, delta;
+    byte actual[];
+
+    m_expect = new byte[256];
+    actual = new byte[256];
+
+    for (i = 256; --i >= 0;) {
+      m_expect[i] = (byte) i;
+    }
+
+    source = new ByteArrayInputStream(m_expect);
+    m_fixture = new SplitInputStream(source, 2);
+    m_input = m_fixture.getStream(0);
+
+    for (i = 0; i < 256; i += delta) {
+      delta = m_input.read(actual, i, 256 - i);
+
+      assertTrue(delta >= 0);
+    }
+
+    assertArrayEquals(m_expect, actual);
+  }
+
+  @Test
+  public void skipZero() throws IOException {
+    assertEquals(0, m_input.skip(0));
+  }
+
+  @Test
+  public void skipNegOne() throws IOException {
+    assertEquals(0, m_input.skip(-1));
+  }
+
+  @Test
+  public void skip() throws IOException {
+    assertEquals(m_expect.length / 2, m_input.skip(m_expect.length / 2));
+  }
+
+  @Test
+  public void skipToEnd() throws IOException {
+    assertEquals(m_expect.length, m_input.skip(m_expect.length));
+  }
+
+  @Test
+  public void skipBeyondEnd() throws IOException {
+    assertEquals(m_expect.length, m_input.skip(m_expect.length + 1));
+    assertEquals(0, m_input.skip(1));
+  }
+
+  @Test
+  public void readByteAfterClose() throws IOException {
+    m_input.close();
+    assertEquals(-1, m_input.read());
+  }
+
+  @Test
+  public void readBufferAfterClose() throws IOException {
+    m_input.close();
+    assertEquals(-1, m_input.read(new byte[1], 0, 1));
+  }
+
+  @Test
+  public void skipAfterClose() throws IOException {
+    m_input.close();
+    assertEquals(0, m_input.skip(1));
+  }
+
+  @Test
+  public void availableAfterClose() throws IOException {
+    assertEquals(m_expect.length, m_input.available());
+    m_input.close();
+    assertEquals(0, m_input.available());
+  }
+
+  @Test
+  public void availableAtEnd() throws IOException {
+    int i;
+
+    for (i = 0; i < m_expect.length; i++) {
+      assertEquals(m_expect.length - i, m_input.available());
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+
+    assertEquals(0, m_input.available());
+  }
+
+  @Test
+  public void availableNeverReads() throws IOException {
+    SplitInputStream split;
+    InputStream source, stream;
+
+    source = new InputStream() {
+
+      @Override
+	public int read() {
+        fail();
+
+        return (0);
+      }
+    };
+
+    split = new SplitInputStream(source, 1);
+    stream = split.getStream(0);
+
+    assertEquals(0, stream.available());
+  }
+
+  @Test
+  public void closeSource() throws IOException {
+    SplitInputStream split;
+    CloseCountInputStream source;
+    InputStream input;
+    int i;
+
+    source = new CloseCountInputStream();
+    split = new SplitInputStream(source, 2);
+    input = split.getStream(0);
+
+    for (i = split.getStreamCount() + 5; --i >= 0;) {
+      input.close();
+    }
+
+    assertEquals(0, source.getCloseCount());
+
+    input = split.getStream(1);
+
+    input.close();
+    assertEquals(1, source.getCloseCount());
+
+    for (i = split.getStreamCount() + 5; --i >= 0;) {
+      input.close();
+    }
+
+    assertEquals(1, source.getCloseCount());
+  }
+
+  @Test
+  public void overflowAvailable() throws IOException {
+    SplitInputStream split;
+    MaxAvailableInputStream source;
+    InputStream input;
+
+    source = new MaxAvailableInputStream();
+    split = new SplitInputStream(source, 1);
+    input = split.getStream(0);
+
+    assertEquals(0, input.read());
+    assertEquals(Integer.MAX_VALUE, input.available());
+  }
+
+  @Test
+  public void expand() throws IOException {
+    int i, length;
+
+    length = 2 * SplitInputStream.INITIAL_BUFFER_SIZE;
+
+    initialize(length, SplitInputStream.INITIAL_BUFFER_SIZE);
+
+    for (i = 0; i < length; i++) {
+      assertEquals(length - i, m_input.available());
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+  }
+
+  @Test
+  public void wrap() throws IOException {
+    int i, length;
+
+    length = 2 * SplitInputStream.INITIAL_BUFFER_SIZE;
+
+    initialize(length, SplitInputStream.INITIAL_BUFFER_SIZE);
+
+    for (i = 0; i < SplitInputStream.INITIAL_BUFFER_SIZE - 5; i++) {
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+
+    m_input = m_fixture.getStream(1);
+
+    for (i = 0; i < SplitInputStream.INITIAL_BUFFER_SIZE; i++) {
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+
+    assertEquals(SplitInputStream.INITIAL_BUFFER_SIZE, m_input.available());
+  }
+
+  @Test
+  public void ignoreClosedStream() throws IOException, NoSuchFieldException, IllegalAccessException {
+    Field bufferField;
+    int i, length;
+    byte expect[], actual[];
+
+    length = 2 * SplitInputStream.INITIAL_BUFFER_SIZE;
+
+    initialize(length, SplitInputStream.INITIAL_BUFFER_SIZE);
+    m_input.close();
+
+    bufferField = SplitInputStream.class.getDeclaredField("m_buffer");
+
+    bufferField.setAccessible(true);
+
+    expect = (byte[]) bufferField.get(m_fixture);
+    m_input = m_fixture.getStream(1);
+
+    for (i = 0; i < length; i++) {
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+
+    actual = (byte[]) bufferField.get(m_fixture);
+
+    assertSame(expect, actual);
+  }
+
+  @Test
+  public void bufferSize1() throws IOException {
+    int i;
+
+    initialize(10, 1);
+
+    for (i = 0; i < m_expect.length; i++) {
+      assertEquals(m_expect[i] & 0x0FF, m_input.read());
+    }
+  }
+
+  @Ignore("This test takes too long for everyone to run all the time.  There are 101,174 states which take about 4 minutes to run.")
+  @Test
+  public void concurrentRead() throws IOException, InterruptedException {
+    InputStream source;
+    Thread thread1, thread2;
+    Runnable task;
+
+    if (verifyNoPropertyViolation(s_jpfArgs)) {
+      source = new InputStream() {
+
+        private Thread m_reader;
+
+        @Override
+		public int read() {
+          if (m_reader == null) {
+            m_reader = Thread.currentThread();    // JPF will catch the race condition if 2 threads call read concurrently.
+          } else {
+            assertSame(m_reader, Thread.currentThread());
+          }
+
+          return (0);
+        }
+      };
+
+      m_fixture = new SplitInputStream(source, 2);
+
+      task = new Runnable() {
+
+        @Override
+		public void run() {
+          try {
+            m_fixture.getStream(0).read();
+          } catch (IOException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+
+      thread1 = new Thread(task);
+
+      task = new Runnable() {
+
+        @Override
+		public void run() {
+          try {
+            m_fixture.getStream(1).read();
+          } catch (IOException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+
+      thread2 = new Thread(task);
+
+      thread1.start();
+      thread2.start();
+
+      thread1.join();
+      thread2.join();
+    }
+  }
+
+  @Test
+  public void concurrentAvailable() throws InterruptedException {
+    InputStream source;
+    Thread thread1, thread2;
+    Runnable task;
+
+    if (verifyNoPropertyViolation(s_jpfArgs)) {
+      source = new InputStream() {
+
+        private Thread m_access;
+
+        @Override
+		public int read() {
+          fail();
+
+          return (0);
+        }
+
+        @Override
+		public int available() {
+          assertNull(m_access);
+
+          m_access = Thread.currentThread();    // JPF will catch the race condition if 2 threads call concurrently.
+          m_access = null;
+
+          return (0);
+        }
+      };
+
+      m_fixture = new SplitInputStream(source, 2);
+
+      task = new Runnable() {
+
+        @Override
+		public void run() {
+          try {
+            m_fixture.getStream(0).available();
+          } catch (IOException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+
+      thread1 = new Thread(task);
+
+      task = new Runnable() {
+
+        @Override
+		public void run() {
+          try {
+            m_fixture.getStream(1).available();
+          } catch (IOException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+
+      thread2 = new Thread(task);
+
+      thread1.start();
+      thread2.start();
+
+      thread1.join();
+      thread2.join();
+    }
+  }
+
+  @Ignore("This test takes too long for everyone to run all the time.  There are 230,360 states which take about 5 minutes to run.")
+  @Test
+  public void thoroughJPFTest() throws InterruptedException, IOException {
+    Thread thread1, thread2;
+
+    if (verifyNoPropertyViolation(s_jpfArgs)) {
+      initialize(4, 2);
+
+      thread1 = new Thread(new JPFTask(0));
+      thread2 = new Thread(new JPFTask(1));
+
+      thread1.start();
+      thread2.start();
+
+      thread1.join();
+      thread2.join();
+    }
+  }
+
+  private static class CloseCountInputStream extends InputStream {
+
+    private int m_closeCount;
+
+    @Override
+	public int read() {
+      return (0);
+    }
+
+    @Override
+	public int available() {
+      return (m_closeCount == 0 ? 1 : 0);
+    }
+
+    @Override
+	public void close() {
+      m_closeCount++;
+    }
+
+    public int getCloseCount() {
+      return (m_closeCount);
+    }
+  }
+
+  private static class MaxAvailableInputStream extends InputStream {
+
+    private int m_data;
+
+    @Override
+	public int read() {
+      return (m_data++);
+    }
+
+    @Override
+	public int available() {
+      return (Integer.MAX_VALUE);
+    }
+  }
+
+  private class JPFTask implements Runnable {
+
+    private final InputStream m_input;
+
+    public JPFTask(int index) {
+      m_input = m_fixture.getStream(index);
+    }
+
+    @Override
+	public void run() {
+      try {
+        unsafe();
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    private void unsafe() throws IOException {
+      int i, expect, actual, test;
+      byte buffer[];
+
+      //System.out.print("#" + Thread.currentThread().getId() + " | Test ");
+      test = Verify.getInt(0, 4);
+
+      //System.out.println(test);
+
+      switch (test) {
+        case 0:
+          m_input.close();
+          break;
+
+        case 1:
+          assertEquals(4, m_input.available());
+          break;
+
+        case 2:
+          expect = Verify.getInt(-1, 5);
+          actual = (int) m_input.skip(expect);
+          expect = Math.max(expect, 0);
+          expect = Math.min(expect, 4);
+
+          assertTrue(actual <= expect);
+          break;
+
+        case 3:
+          for (i = 0; i < 4; i++) {
+            assertEquals(m_expect[i], m_input.read());
+          }
+
+          break;
+
+        case 4:
+          buffer = new byte[1];
+
+          for (i = 0; i < 4; i++) {
+            assertEquals(1, m_input.read(buffer));
+            assertEquals(m_expect[i], buffer[0]);
+          }
+          break;
+      }
+    }
+  }
+}