### Question:
SerializingExecutor implements Executor, Runnable { @Override public void execute(Runnable r) { runQueue.add(checkNotNull(r, "'r' must not be null.")); schedule(r); } SerializingExecutor(Executor executor); @Override void execute(Runnable r); @Override void run();  }### Answer:
@Test public void serial() { executor.execute(new AddToRuns(1)); assertEquals(Collections.<Integer>emptyList(), runs); singleExecutor.drain(); assertEquals(Arrays.asList(1), runs); executor.execute(new AddToRuns(2)); assertEquals(Arrays.asList(1), runs); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2), runs); }
@Test public void parallel() { executor.execute(new AddToRuns(1)); executor.execute(new AddToRuns(2)); executor.execute(new AddToRuns(3)); assertEquals(Collections.<Integer>emptyList(), runs); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2, 3), runs); }
@Test public void reentrant() { executor.execute(new Runnable() { @Override public void run() { executor.execute(new AddToRuns(3)); runs.add(1); } }); executor.execute(new AddToRuns(2)); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2, 3), runs); }
@Test public void testFirstRunnableThrows() { final RuntimeException ex = new RuntimeException(); executor.execute(new Runnable() { @Override public void run() { runs.add(1); throw ex; } }); executor.execute(new AddToRuns(2)); executor.execute(new AddToRuns(3)); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2, 3), runs); }
@Test public void lastRunnableThrows() { final RuntimeException ex = new RuntimeException(); executor.execute(new AddToRuns(1)); executor.execute(new AddToRuns(2)); executor.execute(new Runnable() { @Override public void run() { runs.add(3); throw ex; } }); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2, 3), runs); executor.execute(new AddToRuns(4)); assertEquals(Arrays.asList(1, 2, 3), runs); singleExecutor.drain(); assertEquals(Arrays.asList(1, 2, 3, 4), runs); }
@Test public void firstExecuteThrows() { final RuntimeException ex = new RuntimeException(); ForwardingExecutor forwardingExecutor = new ForwardingExecutor(new Executor() { @Override public void execute(Runnable r) { throw ex; } }); executor = new SerializingExecutor(forwardingExecutor); try { executor.execute(new AddToRuns(1)); fail("expected exception"); } catch (RuntimeException e) { assertSame(ex, e); } assertEquals(Collections.<Integer>emptyList(), runs); forwardingExecutor.executor = singleExecutor; executor.execute(new AddToRuns(2)); executor.execute(new AddToRuns(3)); assertEquals(Collections.<Integer>emptyList(), runs); singleExecutor.drain(); assertEquals(Arrays.asList(2, 3), runs); }
@Test public void direct() { executor = new SerializingExecutor(MoreExecutors.directExecutor()); executor.execute(new AddToRuns(1)); assertEquals(Arrays.asList(1), runs); executor.execute(new AddToRuns(2)); assertEquals(Arrays.asList(1, 2), runs); executor.execute(new AddToRuns(3)); assertEquals(Arrays.asList(1, 2, 3), runs); }
@Test public void testDirectReentrant() { executor = new SerializingExecutor(MoreExecutors.directExecutor()); executor.execute(new Runnable() { @Override public void run() { executor.execute(new AddToRuns(2)); runs.add(1); } }); assertEquals(Arrays.asList(1, 2), runs); executor.execute(new AddToRuns(3)); assertEquals(Arrays.asList(1, 2, 3), runs); }