From 41a8578529dedf1e81218d4429954d6ccd9d67af Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Mon, 20 Apr 2009 15:59:57 +0800 Subject: Improve the design of ICancelable. --- .../android/camera/gallery/BaseCancelableTest.java | 232 +++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 tests/src/com/android/camera/gallery/BaseCancelableTest.java (limited to 'tests') diff --git a/tests/src/com/android/camera/gallery/BaseCancelableTest.java b/tests/src/com/android/camera/gallery/BaseCancelableTest.java new file mode 100644 index 0000000..330e2f1 --- /dev/null +++ b/tests/src/com/android/camera/gallery/BaseCancelableTest.java @@ -0,0 +1,232 @@ +package com.android.camera.gallery; + +import android.test.AndroidTestCase; +import android.util.Log; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + +public class BaseCancelableTest extends AndroidTestCase { + private static final String TAG = "BaseCancelableTest"; + + private static class TestTask extends BaseCancelable { + + private boolean mDone = false; + private boolean mCancel = false; + private boolean mRunning = false; + private boolean mFireError = false; + + @Override + public synchronized boolean requestCancel() { + if (super.requestCancel()) { + mCancel = true; + notifyAll(); + return true; + } + return false; + } + + public synchronized void waitUntilRunning() + throws InterruptedException { + while (!mRunning) { + wait(); + } + } + + @Override + protected synchronized Integer execute() throws Exception { + mRunning = true; + notifyAll(); + + while (!mDone && !mCancel) { + wait(); + } + if (mFireError) throw new IllegalStateException(); + return 0; + } + + public synchronized void completeTask() { + mDone = true; + notifyAll(); + } + + public synchronized void completeTaskWithException() { + mDone = true; + mFireError = true; + notifyAll(); + } + } + + public void testSimpleFlow() throws Exception { + TestTask task = new TestTask(); + task.completeTask(); + assertEquals(0, task.get().intValue()); + } + + private void assertCancellationException(BaseCancelable task) + throws Exception { + try { + task.get(); + fail("expect a " + CancellationException.class); + } catch (CancellationException e) { + // expected + } + } + + private void assertExecutionException(BaseCancelable task) + throws Exception { + try { + task.get(); + fail("expect a " + ExecutionException.class); + } catch (ExecutionException e) { + // expected + } + } + + public void testCancelInInitialState() throws Exception { + TestTask task = new TestTask(); + task.requestCancel(); + assertCancellationException(task); + } + + public void testCancelInRunningState() throws Exception { + final TestTask task = new TestTask(); + new Thread() { + @Override + public void run() { + try { + task.waitUntilRunning(); + assertTrue(task.requestCancel()); + } catch (InterruptedException e) { + Log.e(TAG, "interrupt", e); + } + } + }.start(); + assertCancellationException(task); + } + + public void testConcurrentGet() throws Exception { + final TestTask task = new TestTask(); + new Thread() { + @Override + public void run() { + try { + assertEquals(0, task.get().intValue()); + } catch (InterruptedException e) { + Log.e(TAG, "interrupt", e); + } catch (ExecutionException e) { + Log.e(TAG, "execution fail: ", e); + } + } + }.start(); + task.waitUntilRunning(); + task.completeTask(); + assertEquals(0, task.get().intValue()); + } + + public void testConcurrentGetOnCancled() throws Exception { + final TestTask task = new TestTask(); + new Thread() { + @Override + public void run() { + try { + assertCancellationException(task); + } catch (Exception e) { + Log.e(TAG, "Exception", e); + } + } + }.start(); + task.waitUntilRunning(); + task.requestCancel(); + assertCancellationException(task); + } + + private static class AddTask extends BaseCancelable { + private final Cancelable mTasks[]; + + public AddTask(Cancelable ... tasks) { + mTasks = tasks.clone(); + } + + @Override + protected Integer execute() throws Exception { + int sum = 0; + for (int i = 0, n = mTasks.length; i < n; ++i) { + sum += runSubTask(mTasks[i]); + } + return sum; + } + } + + public void testExecuteSubtask() throws Exception { + TestTask subtask = new TestTask(); + @SuppressWarnings("unchecked") + AddTask addTask = new AddTask(subtask); + subtask.completeTask(); + assertEquals(0, addTask.get().intValue()); + } + + public void testExecuteSubtaskWithError() throws Exception { + TestTask subtask = new TestTask(); + @SuppressWarnings("unchecked") + AddTask addTask = new AddTask(subtask); + subtask.completeTaskWithException(); + assertExecutionException(addTask); + } + + public void testCancelWithSubtask() throws Exception { + final TestTask subtask = new TestTask(); + @SuppressWarnings("unchecked") + final AddTask addTask = new AddTask(subtask); + new Thread() { + @Override + public void run() { + try { + subtask.waitUntilRunning(); + } catch (InterruptedException e) { + Log.e(TAG, "interrupted", e); + } + addTask.requestCancel(); + } + }.start(); + assertCancellationException(addTask); + } + + private static class TaskSet extends BaseCancelable { + private final TestTask mTasks[]; + private int mExecutedTaskCount = 0; + + public TaskSet(TestTask ... tasks) { + mTasks = tasks.clone(); + } + + @Override + protected Integer execute() throws Exception { + int exceptionCount = 0; + for (TestTask task : mTasks) { + try { + ++ mExecutedTaskCount; + runSubTask(task); + } catch (ExecutionException e) { + ++ exceptionCount; + } + } + return exceptionCount; + } + + } + + public void testHandleExceptionInSubTasks() throws Exception { + TestTask task0 = new TestTask(); + TestTask task1 = new TestTask(); + TestTask task2 = new TestTask(); + + task0.completeTask(); + task1.completeTaskWithException(); + task2.completeTask(); + TaskSet taskSet = new TaskSet(task0, task1, task2); + + assertEquals(1, taskSet.get().intValue()); + assertEquals(3, taskSet.mExecutedTaskCount); + } +} -- cgit v1.1