Tests added

This commit is contained in:
serso 2016-01-14 12:36:52 +01:00
parent 5efa9cd3a0
commit e015a12718
9 changed files with 195 additions and 30 deletions

View File

@ -33,21 +33,27 @@ import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.history.HistoryDragProcessor; import org.solovyev.android.calculator.history.HistoryDragProcessor;
import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.AngleUnitsButton;
import org.solovyev.android.calculator.view.LongClickEraser; import org.solovyev.android.calculator.view.LongClickEraser;
import org.solovyev.android.calculator.view.NumeralBasesButton; import org.solovyev.android.calculator.view.NumeralBasesButton;
import org.solovyev.android.calculator.view.ViewsCache; import org.solovyev.android.calculator.view.ViewsCache;
import org.solovyev.android.views.dragbutton.*; import org.solovyev.android.views.dragbutton.DirectionDragButton;
import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.DragListener;
import org.solovyev.android.views.dragbutton.SimpleDragListener;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.angleUnit; import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.angleUnit;
@ -118,6 +124,9 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
@Inject @Inject
Editor editor; Editor editor;
@Inject
History history;
protected void onCreate(@Nonnull Activity activity) { protected void onCreate(@Nonnull Activity activity) {
((CalculatorApplication) activity.getApplication()).getComponent().inject(this); ((CalculatorApplication) activity.getApplication()).getComponent().inject(this);
@ -166,7 +175,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
final ViewsCache views = ViewsCache.forView(root); final ViewsCache views = ViewsCache.forView(root);
setOnDragListeners(views, activity); setOnDragListeners(views, activity);
HistoryDragProcessor historyDragProcessor = new HistoryDragProcessor(); HistoryDragProcessor historyDragProcessor = new HistoryDragProcessor(history);
final DragListener historyDragListener = newDragListener(historyDragProcessor, activity); final DragListener historyDragListener = newDragListener(historyDragProcessor, activity);
final DragButton historyButton = getButton(views, R.id.cpp_button_history); final DragButton historyButton = getButton(views, R.id.cpp_button_history);
if (historyButton != null) { if (historyButton != null) {

View File

@ -1,5 +1,6 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -13,8 +14,10 @@ import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton;
public final class CalculatorBroadcaster implements SharedPreferences.OnSharedPreferenceChangeListener { @Singleton
public class Broadcaster implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String ACTION_INIT = "org.solovyev.android.calculator.INIT"; public static final String ACTION_INIT = "org.solovyev.android.calculator.INIT";
public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED"; public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED";
@ -26,8 +29,8 @@ public final class CalculatorBroadcaster implements SharedPreferences.OnSharedPr
private final Intents intents = new Intents(); private final Intents intents = new Intents();
@Inject @Inject
public CalculatorBroadcaster(@Nonnull Context context, @Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Nonnull Handler handler) { public Broadcaster(@Nonnull Application application, @Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Nonnull Handler handler) {
this.context = context; this.context = application;
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
bus.register(this); bus.register(this);
handler.postDelayed(new Runnable() { handler.postDelayed(new Runnable() {

View File

@ -34,6 +34,7 @@ import org.acra.ACRA;
import org.acra.ACRAConfiguration; import org.acra.ACRAConfiguration;
import org.acra.sender.HttpSender; import org.acra.sender.HttpSender;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.language.Language; import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
@ -84,6 +85,12 @@ public class CalculatorApplication extends android.app.Application implements Sh
@Named(AppModule.THREAD_UI) @Named(AppModule.THREAD_UI)
Executor uiThread; Executor uiThread;
@Inject
History history;
@Inject
Broadcaster broadcaster;
@Override @Override
public void onCreate() { public void onCreate() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

View File

@ -57,14 +57,17 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton;
import static android.text.TextUtils.isEmpty; import static android.text.TextUtils.isEmpty;
@Singleton
public class History { public class History {
public static final String TAG = App.subTag("History"); public static final String TAG = App.subTag("History");
private static final ChangedEvent CHANGED_EVENT_RECENT = new ChangedEvent(true); private static final ChangedEvent CHANGED_EVENT_RECENT = new ChangedEvent(true);
private static final ChangedEvent CHANGED_EVENT_SAVED = new ChangedEvent(false); private static final ChangedEvent CHANGED_EVENT_SAVED = new ChangedEvent(false);
private static final int MAX_INTERMEDIATE_STREAK = 5;
@NonNull @NonNull
private final Runnable writeRecent = new WriteTask(true); private final Runnable writeRecent = new WriteTask(true);
@NonNull @NonNull
@ -74,6 +77,8 @@ public class History {
@Nonnull @Nonnull
private final List<HistoryState> saved = new ArrayList<>(); private final List<HistoryState> saved = new ArrayList<>();
@Nonnull @Nonnull
private final Application application;
@Nonnull
private final Bus bus; private final Bus bus;
@Inject @Inject
Handler handler; Handler handler;
@ -81,12 +86,10 @@ public class History {
SharedPreferences preferences; SharedPreferences preferences;
@Inject @Inject
Editor editor; Editor editor;
@Inject
Application application;
private boolean initialized;
@Inject @Inject
public History(@NonNull Bus bus, @Nonnull @Named(AppModule.THREAD_INIT) Executor initThread) { public History(@NonNull Application application, @NonNull Bus bus, @Nonnull @Named(AppModule.THREAD_INIT) Executor initThread) {
this.application = application;
this.bus = bus; this.bus = bus;
this.bus.register(this); this.bus.register(this);
initThread.execute(new Runnable() { initThread.execute(new Runnable() {
@ -117,7 +120,7 @@ public class History {
} }
@Nonnull @Nonnull
private static List<HistoryState> loadStates(@Nonnull File file) { static List<HistoryState> loadStates(@Nonnull File file) {
if (!file.exists()) { if (!file.exists()) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -219,7 +222,6 @@ public class History {
Check.isTrue(saved.isEmpty()); Check.isTrue(saved.isEmpty());
recent.addAll(recentStates); recent.addAll(recentStates);
saved.addAll(savedStates); saved.addAll(savedStates);
initialized = true;
} }
}); });
} }
@ -258,13 +260,17 @@ public class History {
final List<HistoryState> states = recent.asList(); final List<HistoryState> states = recent.asList();
final int statesCount = states.size(); final int statesCount = states.size();
int streak = 0;
for (int i = 1; i < statesCount; i++) { for (int i = 1; i < statesCount; i++) {
final HistoryState olderState = states.get(i - 1); final HistoryState olderState = states.get(i - 1);
final HistoryState newerState = states.get(i); final HistoryState newerState = states.get(i);
final String olderText = olderState.editor.getTextString(); final String olderText = olderState.editor.getTextString();
final String newerText = newerState.editor.getTextString(); final String newerText = newerState.editor.getTextString();
if (!isIntermediate(olderText, newerText, groupingSeparator)) { if (streak >= MAX_INTERMEDIATE_STREAK || !isIntermediate(olderText, newerText, groupingSeparator)) {
result.add(0, olderState); result.add(0, olderState);
streak = 0;
} else {
streak++;
} }
} }
if (statesCount > 0) { if (statesCount > 0) {
@ -330,9 +336,6 @@ public class History {
@Subscribe @Subscribe
public void onDisplayChanged(@Nonnull Display.ChangedEvent e) { public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
if (!initialized) {
return;
}
final EditorState editorState = editor.getState(); final EditorState editorState = editor.getState();
final DisplayState displayState = e.newState; final DisplayState displayState = e.newState;
if (editorState.sequence != displayState.sequence) { if (editorState.sequence != displayState.sequence) {

View File

@ -30,12 +30,15 @@ import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.SimpleDragListener; import org.solovyev.android.views.dragbutton.SimpleDragListener;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Inject;
public class HistoryDragProcessor implements SimpleDragListener.DragProcessor { public class HistoryDragProcessor implements SimpleDragListener.DragProcessor {
@Inject @Nonnull
History history; private final History history;
public HistoryDragProcessor(@Nonnull History history) {
this.history = history;
}
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {

View File

@ -16,7 +16,7 @@ import java.util.List;
public class RecentHistory { public class RecentHistory {
private static final int MAX_HISTORY = 20; private static final int MAX_HISTORY = 40;
@NonNull @NonNull
private final List<HistoryState> list = new LinkedList<>(); private final List<HistoryState> list = new LinkedList<>();

View File

@ -59,10 +59,10 @@ import javax.annotation.Nullable;
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT; import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
import static android.content.Intent.ACTION_CONFIGURATION_CHANGED; import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static android.os.Build.VERSION_CODES.JELLY_BEAN; import static android.os.Build.VERSION_CODES.JELLY_BEAN;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_DISPLAY_STATE_CHANGED; import static org.solovyev.android.calculator.Broadcaster.ACTION_DISPLAY_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_EDITOR_STATE_CHANGED; import static org.solovyev.android.calculator.Broadcaster.ACTION_EDITOR_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_INIT; import static org.solovyev.android.calculator.Broadcaster.ACTION_INIT;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_THEME_CHANGED; import static org.solovyev.android.calculator.Broadcaster.ACTION_THEME_CHANGED;
import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent; import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent;
public class CalculatorWidget extends AppWidgetProvider { public class CalculatorWidget extends AppWidgetProvider {

View File

@ -35,10 +35,13 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.solovyev.android.CalculatorTestRunner; import org.solovyev.android.CalculatorTestRunner;
import org.solovyev.android.calculator.BuildConfig; import org.solovyev.android.calculator.BuildConfig;
import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.jscl.JsclOperation;
import java.io.File;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -47,6 +50,7 @@ import javax.annotation.Nonnull;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -61,11 +65,10 @@ public class HistoryTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
history = new History(mock(Bus.class), mock(Executor.class)); history = new History(RuntimeEnvironment.application, mock(Bus.class), mock(Executor.class));
history.handler = mock(Handler.class); history.handler = mock(Handler.class);
history.preferences = mock(SharedPreferences.class); history.preferences = mock(SharedPreferences.class);
history.editor = mock(Editor.class); history.editor = mock(Editor.class);
history.application = RuntimeEnvironment.application;
} }
@Test @Test
@ -85,9 +88,11 @@ public class HistoryTest {
addState("23547"); addState("23547");
final List<HistoryState> states = history.getRecent(); final List<HistoryState> states = history.getRecent();
assertEquals(2, states.size()); assertEquals(3, states.size());
assertEquals("23547", states.get(0).editor.getTextString()); assertEquals("23547", states.get(0).editor.getTextString());
assertEquals("123+3", states.get(1).editor.getTextString()); // intermediate state
assertEquals("235", states.get(1).editor.getTextString());
assertEquals("123+3", states.get(2).editor.getTextString());
} }
@Test @Test
@ -257,4 +262,57 @@ public class HistoryTest {
assertEquals(true, state.display.valid); assertEquals(true, state.display.valid);
assertNull(state.display.getResult()); assertNull(state.display.getResult());
} }
@Test
public void testShouldAddStateIfEditorAndDisplayAreInSync() throws Exception {
final EditorState editorState = EditorState.create("editor", 2);
when(history.editor.getState()).thenReturn(editorState);
final DisplayState displayState = DisplayState.createError(JsclOperation.numeric, "test", editorState.sequence);
history.onDisplayChanged(new Display.ChangedEvent(DisplayState.empty(), displayState));
final List<HistoryState> states = history.getRecent();
assertEquals(1, states.size());
assertSame(editorState, states.get(0).editor);
assertSame(displayState, states.get(0).display);
}
@Test
public void testShouldNotAddStateIfEditorAndDisplayAreOutOfSync() throws Exception {
final EditorState editorState = EditorState.create("editor", 2);
when(history.editor.getState()).thenReturn(editorState);
final DisplayState displayState = DisplayState.createError(JsclOperation.numeric, "test", editorState.sequence - 1);
history.onDisplayChanged(new Display.ChangedEvent(DisplayState.empty(), displayState));
final List<HistoryState> states = history.getRecent();
assertEquals(0, states.size());
}
@Test
public void testShouldLoadStates() throws Exception {
final List<HistoryState> states = History.loadStates(new File(HistoryTest.class.getResource("recent-history.json").getFile()));
assertEquals(8, states.size());
HistoryState state = states.get(0);
assertEquals(1452770652381L, state.time);
assertEquals("", state.comment);
assertEquals("01 234 567 890 123 456 789", state.editor.getTextString());
assertEquals(26, state.editor.selection);
assertEquals("1 234 567 890 123 460 000", state.display.text);
state = states.get(4);
assertEquals(1452770626394L, state.time);
assertEquals("", state.comment);
assertEquals("985", state.editor.getTextString());
assertEquals(3, state.editor.selection);
assertEquals("985", state.display.text);
state = states.get(7);
assertEquals(1452770503823L, state.time);
assertEquals("", state.comment);
assertEquals("52", state.editor.getTextString());
assertEquals(2, state.editor.selection);
assertEquals("52", state.display.text);
}
} }

View File

@ -0,0 +1,82 @@
[
{
"e": {
"t": "01 234 567 890 123 456 789",
"s": 26
},
"d": {
"t": "1 234 567 890 123 460 000"
},
"t": 1452770652381
},
{
"e": {
"t": "01 234 567 890 123 456",
"s": 22
},
"d": {
"t": "1 234 567 890 123 460"
},
"t": 1452770651761
},
{
"e": {
"t": "01 234 567 890",
"s": 14
},
"d": {
"t": "1 234 567 890"
},
"t": 1452770650247
},
{
"e": {
"t": "01 234",
"s": 6
},
"d": {
"t": "1 234"
},
"t": 1452770632934
},
{
"e": {
"t": "985",
"s": 3
},
"d": {
"t": "985"
},
"t": 1452770626394
},
{
"e": {
"t": "34 155+552",
"s": 10
},
"d": {
"t": "34 707"
},
"t": 1452770497135
},
{
"e": {
"t": "9",
"s": 1
},
"d": {
"t": "9"
},
"t": 1452770502906
},
{
"e": {
"t": "52",
"s": 2
},
"d": {
"t": "52"
},
"t": 1452770503823
}
]