@Test
  public void testPollBatch() {
    try {
      ClosableBlockingQueue<String> queue = new ClosableBlockingQueue<>();

      assertNull(queue.pollBatch());

      queue.add("a");
      queue.add("b");

      assertEquals(asList("a", "b"), queue.pollBatch());
      assertNull(queue.pollBatch());

      queue.add("c");

      assertEquals(singletonList("c"), queue.pollBatch());
      assertNull(queue.pollBatch());

      assertTrue(queue.close());

      try {
        queue.pollBatch();
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testPeekAndPoll() {
    try {
      ClosableBlockingQueue<String> queue = new ClosableBlockingQueue<>();

      assertNull(queue.peek());
      assertNull(queue.peek());
      assertNull(queue.poll());
      assertNull(queue.poll());

      assertEquals(0, queue.size());

      queue.add("a");
      queue.add("b");
      queue.add("c");

      assertEquals(3, queue.size());

      assertEquals("a", queue.peek());
      assertEquals("a", queue.peek());
      assertEquals("a", queue.peek());

      assertEquals(3, queue.size());

      assertEquals("a", queue.poll());
      assertEquals("b", queue.poll());

      assertEquals(1, queue.size());

      assertEquals("c", queue.peek());
      assertEquals("c", queue.peek());

      assertEquals("c", queue.poll());

      assertEquals(0, queue.size());
      assertNull(queue.poll());
      assertNull(queue.peek());
      assertNull(queue.peek());

      assertTrue(queue.close());

      try {
        queue.peek();
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }

      try {
        queue.poll();
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testGetElementBlocking() {
    try {
      ClosableBlockingQueue<String> queue = new ClosableBlockingQueue<>();

      assertNull(queue.getElementBlocking(1));
      assertNull(queue.getElementBlocking(3));
      assertNull(queue.getElementBlocking(2));

      assertEquals(0, queue.size());

      queue.add("a");
      queue.add("b");
      queue.add("c");
      queue.add("d");
      queue.add("e");
      queue.add("f");

      assertEquals(6, queue.size());

      assertEquals("a", queue.getElementBlocking(99));
      assertEquals("b", queue.getElementBlocking());

      assertEquals(4, queue.size());

      assertEquals("c", queue.getElementBlocking(0));
      assertEquals("d", queue.getElementBlocking(1000000));
      assertEquals("e", queue.getElementBlocking());
      assertEquals("f", queue.getElementBlocking(1786598));

      assertEquals(0, queue.size());

      assertNull(queue.getElementBlocking(1));
      assertNull(queue.getElementBlocking(3));
      assertNull(queue.getElementBlocking(2));

      assertTrue(queue.close());

      try {
        queue.getElementBlocking();
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }

      try {
        queue.getElementBlocking(1000000000L);
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testGetBatchBlocking() {
    try {
      ClosableBlockingQueue<String> queue = new ClosableBlockingQueue<>();

      assertEquals(emptyList(), queue.getBatchBlocking(1));
      assertEquals(emptyList(), queue.getBatchBlocking(3));
      assertEquals(emptyList(), queue.getBatchBlocking(2));

      queue.add("a");
      queue.add("b");

      assertEquals(asList("a", "b"), queue.getBatchBlocking(900000009));

      queue.add("c");
      queue.add("d");

      assertEquals(asList("c", "d"), queue.getBatchBlocking());

      assertEquals(emptyList(), queue.getBatchBlocking(2));

      queue.add("e");

      assertEquals(singletonList("e"), queue.getBatchBlocking(0));

      queue.add("f");

      assertEquals(singletonList("f"), queue.getBatchBlocking(1000000000));

      assertEquals(0, queue.size());

      assertEquals(emptyList(), queue.getBatchBlocking(1));
      assertEquals(emptyList(), queue.getBatchBlocking(3));
      assertEquals(emptyList(), queue.getBatchBlocking(2));

      assertTrue(queue.close());

      try {
        queue.getBatchBlocking();
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }

      try {
        queue.getBatchBlocking(1000000000L);
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testCloseNonEmptyQueue() {
    try {
      ClosableBlockingQueue<Integer> queue = new ClosableBlockingQueue<>(asList(1, 2, 3));
      assertTrue(queue.isOpen());

      assertFalse(queue.close());
      assertFalse(queue.close());

      queue.poll();

      assertFalse(queue.close());
      assertFalse(queue.close());

      queue.pollBatch();

      assertTrue(queue.close());
      assertFalse(queue.isOpen());

      assertFalse(queue.addIfOpen(42));
      assertTrue(queue.isEmpty());

      try {
        queue.add(99);
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testCloseEmptyQueue() {
    try {
      ClosableBlockingQueue<String> queue = new ClosableBlockingQueue<>();
      assertTrue(queue.isOpen());
      assertTrue(queue.close());
      assertFalse(queue.isOpen());

      assertFalse(queue.addIfOpen("element"));
      assertTrue(queue.isEmpty());

      try {
        queue.add("some element");
        fail("should cause an exception");
      } catch (IllegalStateException ignored) {
        // expected
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }