This commit is contained in:
Sergey Solovyev 2012-10-13 14:02:44 +04:00
parent a60e0caeb8
commit 10e05d88b0
4 changed files with 132 additions and 19 deletions

View File

@ -64,6 +64,13 @@ public class CalculatorEditorImplTest extends AbstractCalculatorTest {
viewState = this.calculatorEditor.insert("9"); viewState = this.calculatorEditor.insert("9");
Assert.assertEquals("9testtest12345678990", viewState.getText()); Assert.assertEquals("9testtest12345678990", viewState.getText());
Assert.assertEquals(1, viewState.getSelection()); Assert.assertEquals(1, viewState.getSelection());
viewState = this.calculatorEditor.insert("öäü");
Assert.assertEquals("9öäütesttest12345678990", viewState.getText());
this.calculatorEditor.setCursorOnEnd();
viewState = this.calculatorEditor.insert("öäü");
Assert.assertEquals("9öäütesttest12345678990öäü", viewState.getText());
} }
@Test @Test

View File

@ -49,7 +49,7 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
// NOTE: static because super constructor calls some overridden methods (like onSelectionChanged and current lock is not yet created) // NOTE: static because super constructor calls some overridden methods (like onSelectionChanged and current lock is not yet created)
@NotNull @NotNull
private static final Object lock = new Object(); private static final Object viewLock = new Object();
@NotNull @NotNull
private final Handler uiHandler = new Handler(); private final Handler uiHandler = new Handler();
@ -154,30 +154,32 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
@Override @Override
public void setState(@NotNull final CalculatorEditorViewState viewState) { public void setState(@NotNull final CalculatorEditorViewState viewState) {
synchronized (viewLock) {
final CharSequence text = prepareText(viewState.getText(), highlightText); final CharSequence text = prepareText(viewState.getText(), highlightText);
uiHandler.post(new Runnable() { uiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
final AndroidCalculatorEditorView editorView = AndroidCalculatorEditorView.this; final AndroidCalculatorEditorView editorView = AndroidCalculatorEditorView.this;
synchronized (lock) { synchronized (viewLock) {
try { try {
editorView.viewStateChange = true; editorView.viewStateChange = true;
editorView.viewState = viewState; editorView.viewState = viewState;
editorView.setText(text, BufferType.EDITABLE); editorView.setText(text, BufferType.EDITABLE);
editorView.setSelection(viewState.getSelection()); editorView.setSelection(viewState.getSelection());
} finally { } finally {
editorView.viewStateChange = false; editorView.viewStateChange = false;
}
} }
} }
} });
}); }
} }
@Override @Override
protected void onSelectionChanged(int selStart, int selEnd) { protected void onSelectionChanged(int selStart, int selEnd) {
synchronized (lock) { synchronized (viewLock) {
if (!viewStateChange) { if (!viewStateChange) {
// external text change => need to notify editor // external text change => need to notify editor
super.onSelectionChanged(selStart, selEnd); super.onSelectionChanged(selStart, selEnd);
@ -187,7 +189,7 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
} }
public void handleTextChange(Editable s) { public void handleTextChange(Editable s) {
synchronized (lock) { synchronized (viewLock) {
if (!viewStateChange) { if (!viewStateChange) {
// external text change => need to notify editor // external text change => need to notify editor
CalculatorLocatorImpl.getInstance().getEditor().setText(String.valueOf(s)); CalculatorLocatorImpl.getInstance().getEditor().setText(String.valueOf(s));

View File

@ -0,0 +1,83 @@
package org.solovyev.android.calculator;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.solovyev.common.text.StringUtils;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* User: serso
* Date: 10/13/12
* Time: 1:11 PM
*/
@RunWith(value = CalculatorppTestRunner.class)
public class AndroidCalculatorEditorViewTest {
@BeforeClass
public static void staticSetUp() throws Exception {
CalculatorTestUtils.staticSetUp(null);
}
@Before
public void setUp() throws Exception {
CalculatorActivity context = new CalculatorActivity();
CalculatorTestUtils.initViews(context);
}
@Test
public void testAsyncWork() throws Exception {
final int threadNum = 10;
final int count = 10;
final int maxTextLength = 100;
final Random random = new Random(new Date().getTime());
final CountDownLatch startLatchLatch = new CountDownLatch(threadNum);
final CountDownLatch finishLatch = new CountDownLatch(threadNum * count);
final AtomicBoolean error = new AtomicBoolean(false);
for ( int i = 0; i < threadNum; i++ ) {
new Thread(new Runnable() {
@Override
public void run() {
try {
startLatchLatch.await();
} catch (InterruptedException e) {
System.out.println(e);
error.set(true);
for ( int j = 0; j < count; j++ ) {
finishLatch.countDown();
}
return;
}
for ( int j = 0; j < count; j++ ) {
try {
int textLength = random.nextInt(maxTextLength);
CalculatorLocatorImpl.getInstance().getEditor().insert(StringUtils.generateRandomString(textLength), textLength);
} catch (Throwable e) {
System.out.println(e);
error.set(true);
} finally {
finishLatch.countDown();
}
}
}
}).start();
startLatchLatch.countDown();
}
if ( finishLatch.await(60, TimeUnit.SECONDS) ) {
Assert.assertFalse(error.get());
} else {
Assert.fail("Too long execution!");
}
}
}

View File

@ -1,7 +1,9 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context;
import jscl.JsclMathEngine; import jscl.JsclMathEngine;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.CalculatorHistory;
@ -12,11 +14,30 @@ import org.solovyev.android.calculator.history.CalculatorHistory;
*/ */
public class CalculatorTestUtils { public class CalculatorTestUtils {
public static void staticSetUp() throws Exception { public static void staticSetUp(@Nullable Context context) throws Exception {
CalculatorLocatorImpl.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class), new SystemOutCalculatorLogger()); CalculatorLocatorImpl.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class), new SystemOutCalculatorLogger());
CalculatorLocatorImpl.getInstance().getEngine().init(); CalculatorLocatorImpl.getInstance().getEngine().init();
if ( context != null ) {
initViews(context);
}
} }
public static void initViews(@NotNull Context context) {
final AndroidCalculatorEditorView editor = new AndroidCalculatorEditorView(context);
editor.init(context);
CalculatorLocatorImpl.getInstance().getEditor().setView(editor);
final AndroidCalculatorDisplayView display = new AndroidCalculatorDisplayView(context);
display.init(context);
CalculatorLocatorImpl.getInstance().getDisplay().setView(display);
}
public static void staticSetUp() throws Exception {
staticSetUp(null);
}
@NotNull @NotNull
static CalculatorEngineImpl newCalculatorEngine() { static CalculatorEngineImpl newCalculatorEngine() {
final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class); final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class);