Changes
This commit is contained in:
@@ -13,10 +13,7 @@ import static org.solovyev.android.calculator.CalculatorEventType.*;
|
||||
public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
|
||||
@NotNull
|
||||
private volatile CalculatorEventData lastCalculatorEventData;
|
||||
|
||||
@NotNull
|
||||
private final Object lastCalculatorEventDataLock = new Object();
|
||||
private final CalculatorEventHolder lastEvent;
|
||||
|
||||
@Nullable
|
||||
private CalculatorDisplayView view;
|
||||
@@ -32,7 +29,7 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
|
||||
public CalculatorDisplayImpl(@NotNull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
this.lastCalculatorEventData = CalculatorUtils.createFirstEventDataId();
|
||||
this.lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
}
|
||||
|
||||
@@ -91,9 +88,7 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorEventData getLastEventData() {
|
||||
synchronized (lastCalculatorEventDataLock) {
|
||||
return lastCalculatorEventData;
|
||||
}
|
||||
return lastEvent.getLastEventData();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,18 +97,9 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
@Nullable Object data) {
|
||||
if (calculatorEventType.isOfType(calculation_result, calculation_failed, calculation_cancelled, conversion_result, conversion_failed)) {
|
||||
|
||||
boolean processEvent = false;
|
||||
boolean sameSequence = false;
|
||||
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
|
||||
|
||||
synchronized (lastCalculatorEventDataLock) {
|
||||
if (calculatorEventData.isAfter(lastCalculatorEventData)) {
|
||||
sameSequence = calculatorEventData.isSameSequence(lastCalculatorEventData);
|
||||
lastCalculatorEventData = calculatorEventData;
|
||||
processEvent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processEvent) {
|
||||
if (result.isNewAfter()) {
|
||||
switch (calculatorEventType) {
|
||||
case conversion_failed:
|
||||
processConversationFailed((CalculatorConversionEventData) calculatorEventData, (ConversionFailure) data);
|
||||
|
@@ -26,12 +26,16 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
@NotNull
|
||||
private final Calculator calculator;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEventHolder lastEventHolder;
|
||||
|
||||
@NotNull
|
||||
private final CursorControlAdapter cursorControlAdapter = new CursorControlAdapter(this);
|
||||
|
||||
public CalculatorEditorImpl(@NotNull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
this.lastEventHolder = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,12 +84,16 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData,
|
||||
@NotNull CalculatorEventType calculatorEventType,
|
||||
@Nullable Object data) {
|
||||
switch (calculatorEventType) {
|
||||
case use_history_state:
|
||||
final CalculatorHistoryState calculatorHistoryState = (CalculatorHistoryState)data;
|
||||
final EditorHistoryState editorState = calculatorHistoryState.getEditorState();
|
||||
this.setText(StringUtils.getNotEmpty(editorState.getText(), ""), editorState.getCursorPosition());
|
||||
break;
|
||||
final CalculatorEventHolder.Result result = lastEventHolder.apply(calculatorEventData);
|
||||
|
||||
if (result.isNewAfter()) {
|
||||
switch (calculatorEventType) {
|
||||
case use_history_state:
|
||||
final CalculatorHistoryState calculatorHistoryState = (CalculatorHistoryState)data;
|
||||
final EditorHistoryState editorState = calculatorHistoryState.getEditorState();
|
||||
this.setText(StringUtils.getNotEmpty(editorState.getText(), ""), editorState.getCursorPosition());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,70 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/9/12
|
||||
* Time: 9:59 PM
|
||||
*/
|
||||
public class CalculatorEventHolder {
|
||||
|
||||
@NotNull
|
||||
private volatile CalculatorEventData lastEventData;
|
||||
|
||||
public CalculatorEventHolder(@NotNull CalculatorEventData lastEventData) {
|
||||
this.lastEventData = lastEventData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized CalculatorEventData getLastEventData() {
|
||||
return lastEventData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized Result apply(@NotNull CalculatorEventData newEventData) {
|
||||
final Result result = new Result(lastEventData, newEventData);
|
||||
|
||||
if (result.isNewAfter()) {
|
||||
this.lastEventData = newEventData;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEventData lastEventData;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEventData newEventData;
|
||||
|
||||
@Nullable
|
||||
private Boolean after = null;
|
||||
|
||||
@Nullable
|
||||
private Boolean sameSequence = null;
|
||||
|
||||
public Result(@NotNull CalculatorEventData lastEventData,
|
||||
@NotNull CalculatorEventData newEventData) {
|
||||
this.lastEventData = lastEventData;
|
||||
this.newEventData = newEventData;
|
||||
}
|
||||
|
||||
public boolean isNewAfter() {
|
||||
if (after == null) {
|
||||
after = newEventData.isAfter(lastEventData);
|
||||
}
|
||||
return after;
|
||||
}
|
||||
|
||||
public boolean isSameSequence() {
|
||||
if (sameSequence == null) {
|
||||
sameSequence = newEventData.isSameSequence(lastEventData);
|
||||
}
|
||||
return sameSequence;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,138 +1,144 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.JsclMathEngine;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mockito.Mockito;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistory;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/7/12
|
||||
* Time: 8:40 PM
|
||||
*/
|
||||
public class CalculatorTestUtils {
|
||||
|
||||
// in seconds
|
||||
public static final int TIMEOUT = 1000;
|
||||
|
||||
public static void staticSetUp() throws Exception {
|
||||
CalculatorLocatorImpl.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class));
|
||||
CalculatorLocatorImpl.getInstance().getEngine().init();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static CalculatorEngineImpl newCalculatorEngine() {
|
||||
final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class);
|
||||
|
||||
final JsclMathEngine jsclEngine = JsclMathEngine.getInstance();
|
||||
|
||||
final CalculatorVarsRegistry varsRegistry = new CalculatorVarsRegistry(jsclEngine.getConstantsRegistry(), mathEntityDao);
|
||||
final CalculatorFunctionsMathRegistry functionsRegistry = new CalculatorFunctionsMathRegistry(jsclEngine.getFunctionsRegistry(), mathEntityDao);
|
||||
final CalculatorOperatorsMathRegistry operatorsRegistry = new CalculatorOperatorsMathRegistry(jsclEngine.getOperatorsRegistry(), mathEntityDao);
|
||||
final CalculatorPostfixFunctionsRegistry postfixFunctionsRegistry = new CalculatorPostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry(), mathEntityDao);
|
||||
|
||||
return new CalculatorEngineImpl(jsclEngine, varsRegistry, functionsRegistry, operatorsRegistry, postfixFunctionsRegistry, null);
|
||||
}
|
||||
|
||||
public static void assertEval(@NotNull String expected, @NotNull String expression) {
|
||||
assertEval(expected, expression, JsclOperation.numeric);
|
||||
}
|
||||
|
||||
public static void assertEval(@NotNull String expected, @NotNull String expression, @NotNull JsclOperation operation) {
|
||||
final Calculator calculator = CalculatorLocatorImpl.getInstance().getCalculator();
|
||||
|
||||
CalculatorLocatorImpl.getInstance().getDisplay().setViewState(CalculatorDisplayViewStateImpl.newDefaultInstance());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
|
||||
try {
|
||||
calculator.addCalculatorEventListener(calculatorEventListener);
|
||||
calculatorEventListener.setCalculatorEventData(calculator.evaluate(operation, expression));
|
||||
|
||||
if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
Assert.assertNotNull(calculatorEventListener.getResult());
|
||||
Assert.assertEquals(expected, calculatorEventListener.getResult().getText());
|
||||
} else {
|
||||
Assert.fail("Too long wait for: " + expression);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
calculator.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertError(@NotNull String expression) {
|
||||
assertError(expression, JsclOperation.numeric);
|
||||
}
|
||||
|
||||
private static final class TestCalculatorEventListener implements CalculatorEventListener {
|
||||
|
||||
@Nullable
|
||||
private CalculatorEventData calculatorEventData;
|
||||
|
||||
@NotNull
|
||||
private final CountDownLatch latch;
|
||||
|
||||
@Nullable
|
||||
private volatile CalculatorDisplayViewState result = null;
|
||||
|
||||
public TestCalculatorEventListener(@NotNull CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public void setCalculatorEventData(@Nullable CalculatorEventData calculatorEventData) {
|
||||
this.calculatorEventData = calculatorEventData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
if ( this.calculatorEventData != null && calculatorEventData.isSameSequence(this.calculatorEventData) ) {
|
||||
if ( calculatorEventType == CalculatorEventType.display_state_changed ) {
|
||||
final CalculatorDisplayChangeEventData displayChange = (CalculatorDisplayChangeEventData)data;
|
||||
|
||||
result = displayChange.getNewValue();
|
||||
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CalculatorDisplayViewState getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertError(@NotNull String expression, @NotNull JsclOperation operation) {
|
||||
final Calculator calculator = CalculatorLocatorImpl.getInstance().getCalculator();
|
||||
|
||||
CalculatorLocatorImpl.getInstance().getDisplay().setViewState(CalculatorDisplayViewStateImpl.newDefaultInstance());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
|
||||
try {
|
||||
calculator.addCalculatorEventListener(calculatorEventListener);
|
||||
calculatorEventListener.setCalculatorEventData(calculator.evaluate(operation, expression));
|
||||
|
||||
if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
Assert.assertNotNull(calculatorEventListener.getResult());
|
||||
Assert.assertFalse(calculatorEventListener.getResult().isValid());
|
||||
} else {
|
||||
Assert.fail("Too long wait for: " + expression);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
calculator.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.JsclMathEngine;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mockito.Mockito;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistory;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/7/12
|
||||
* Time: 8:40 PM
|
||||
*/
|
||||
public class CalculatorTestUtils {
|
||||
|
||||
// in seconds
|
||||
public static final int TIMEOUT = 1;
|
||||
|
||||
public static void staticSetUp() throws Exception {
|
||||
CalculatorLocatorImpl.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class));
|
||||
CalculatorLocatorImpl.getInstance().getEngine().init();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static CalculatorEngineImpl newCalculatorEngine() {
|
||||
final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class);
|
||||
|
||||
final JsclMathEngine jsclEngine = JsclMathEngine.getInstance();
|
||||
|
||||
final CalculatorVarsRegistry varsRegistry = new CalculatorVarsRegistry(jsclEngine.getConstantsRegistry(), mathEntityDao);
|
||||
final CalculatorFunctionsMathRegistry functionsRegistry = new CalculatorFunctionsMathRegistry(jsclEngine.getFunctionsRegistry(), mathEntityDao);
|
||||
final CalculatorOperatorsMathRegistry operatorsRegistry = new CalculatorOperatorsMathRegistry(jsclEngine.getOperatorsRegistry(), mathEntityDao);
|
||||
final CalculatorPostfixFunctionsRegistry postfixFunctionsRegistry = new CalculatorPostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry(), mathEntityDao);
|
||||
|
||||
return new CalculatorEngineImpl(jsclEngine, varsRegistry, functionsRegistry, operatorsRegistry, postfixFunctionsRegistry, null);
|
||||
}
|
||||
|
||||
public static void assertEval(@NotNull String expected, @NotNull String expression) {
|
||||
assertEval(expected, expression, JsclOperation.numeric);
|
||||
}
|
||||
|
||||
public static void assertEval(@NotNull String expected, @NotNull String expression, @NotNull JsclOperation operation) {
|
||||
final Calculator calculator = CalculatorLocatorImpl.getInstance().getCalculator();
|
||||
|
||||
CalculatorLocatorImpl.getInstance().getDisplay().setViewState(CalculatorDisplayViewStateImpl.newDefaultInstance());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
|
||||
try {
|
||||
calculator.addCalculatorEventListener(calculatorEventListener);
|
||||
|
||||
calculatorEventListener.setCalculatorEventData(calculator.evaluate(operation, expression));
|
||||
|
||||
if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
Assert.assertNotNull(calculatorEventListener.getResult());
|
||||
Assert.assertEquals(expected, calculatorEventListener.getResult().getText());
|
||||
} else {
|
||||
Assert.fail("Too long wait for: " + expression);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
calculator.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertError(@NotNull String expression) {
|
||||
assertError(expression, JsclOperation.numeric);
|
||||
}
|
||||
|
||||
private static final class TestCalculatorEventListener implements CalculatorEventListener {
|
||||
|
||||
@Nullable
|
||||
private CalculatorEventData calculatorEventData;
|
||||
|
||||
@NotNull
|
||||
private final CountDownLatch latch;
|
||||
|
||||
@Nullable
|
||||
private volatile CalculatorDisplayViewState result = null;
|
||||
|
||||
public TestCalculatorEventListener(@NotNull CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public void setCalculatorEventData(@Nullable CalculatorEventData calculatorEventData) {
|
||||
this.calculatorEventData = calculatorEventData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
if ( this.calculatorEventData != null && calculatorEventData.isSameSequence(this.calculatorEventData) ) {
|
||||
if (calculatorEventType == CalculatorEventType.display_state_changed) {
|
||||
final CalculatorDisplayChangeEventData displayChange = (CalculatorDisplayChangeEventData) data;
|
||||
|
||||
result = displayChange.getNewValue();
|
||||
|
||||
try {
|
||||
// need to sleep a little bit as await
|
||||
new CountDownLatch(1).await(100, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CalculatorDisplayViewState getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertError(@NotNull String expression, @NotNull JsclOperation operation) {
|
||||
final Calculator calculator = CalculatorLocatorImpl.getInstance().getCalculator();
|
||||
|
||||
CalculatorLocatorImpl.getInstance().getDisplay().setViewState(CalculatorDisplayViewStateImpl.newDefaultInstance());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
|
||||
try {
|
||||
calculator.addCalculatorEventListener(calculatorEventListener);
|
||||
calculatorEventListener.setCalculatorEventData(calculator.evaluate(operation, expression));
|
||||
|
||||
if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
Assert.assertNotNull(calculatorEventListener.getResult());
|
||||
Assert.assertFalse(calculatorEventListener.getResult().isValid());
|
||||
} else {
|
||||
Assert.fail("Too long wait for: " + expression);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
calculator.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user