History tests

This commit is contained in:
serso 2016-01-13 23:09:07 +01:00
parent 1e8be31ab5
commit 6734bfeaa4
14 changed files with 295 additions and 337 deletions

View File

@ -95,7 +95,6 @@ public final class App {
private static volatile Application application;
@Nonnull
private static Executor uiThreadExecutor;
private static volatile boolean initialized;
@Nonnull
private static SharedPreferences preferences;
@Nonnull
@ -132,9 +131,6 @@ public final class App {
public static void init(@Nonnull CalculatorApplication application,
@Nonnull Languages languages) {
if (initialized) {
throw new IllegalStateException("Already initialized!");
}
App.application = application;
App.preferences = PreferenceManager.getDefaultSharedPreferences(application);
App.uiThreadExecutor = application.uiThread;
@ -163,14 +159,6 @@ public final class App {
App.editor = application.editor;
App.display = application.display;
App.bus = application.bus;
App.initialized = true;
}
private static void checkInit() {
if (!initialized) {
throw new IllegalStateException("App should be initialized!");
}
}
/**

View File

@ -1,11 +1,11 @@
package org.solovyev.android.calculator;
import dagger.Component;
import org.solovyev.android.calculator.history.BaseHistoryFragment;
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
@ -13,4 +13,5 @@ public interface AppComponent {
void inject(CalculatorEditorFragment fragment);
void inject(BaseUi ui);
void inject(CalculatorOnscreenService service);
void inject(BaseHistoryFragment fragment);
}

View File

@ -6,21 +6,17 @@ import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import com.squareup.otto.Bus;
import dagger.Module;
import dagger.Provides;
import org.solovyev.android.UiThreadExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javax.annotation.Nonnull;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
@Module
public class AppModule {
@ -43,6 +39,12 @@ public class AppModule {
return new Handler(Looper.getMainLooper());
}
@Provides
@Singleton
Application provideApplication() {
return application;
}
@Provides
@Singleton
Bus provideBus(Handler handler) {

View File

@ -80,19 +80,6 @@ public enum CalculatorEventType {
engine_preferences_changed,
/*
**********************************************************************
*
* HISTORY
*
**********************************************************************
*/
// @Nonnull CalculatorHistoryState
history_state_added,
clear_history_requested,
/*
**********************************************************************
*

View File

@ -30,43 +30,24 @@ import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.text.ClipboardManager;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.view.*;
import android.widget.*;
import com.melnykov.fab.FloatingActionButton;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorActivity;
import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.FragmentUi;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.text.Strings;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import static android.view.Menu.NONE;
import static org.solovyev.android.calculator.CalculatorEventType.clear_history_requested;
public abstract class BaseHistoryFragment extends ListFragment implements CalculatorEventListener {
public abstract class BaseHistoryFragment extends ListFragment {
@Nonnull
private final DialogInterface.OnClickListener clearDialogListener = new DialogInterface.OnClickListener() {
@ -79,14 +60,16 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
}
}
};
@Inject
History history;
@Inject
Bus bus;
@Nonnull
private HistoryArrayAdapter adapter;
@Nonnull
private FragmentUi ui;
@Nullable
private AlertDialog clearDialog;
@Inject
History history;
protected BaseHistoryFragment(@Nonnull CalculatorFragmentType fragmentType) {
ui = new FragmentUi(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false);
@ -114,6 +97,8 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((CalculatorApplication) getActivity().getApplication()).getComponent().inject(this);
bus.register(this);
ui.onCreate(this);
}
@ -139,7 +124,12 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Locator.getInstance().getCalculator().fireCalculatorEvent(clear_history_requested, null);
clearDialog = new AlertDialog.Builder(getActivity()).setTitle(R.string.cpp_clear_history_title)
.setMessage(R.string.cpp_clear_history_message)
.setPositiveButton(R.string.cpp_clear_history, clearDialogListener)
.setNegativeButton(R.string.c_cancel, clearDialogListener)
.create();
clearDialog.show();
}
});
@ -159,7 +149,7 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
public void onResume() {
super.onResume();
this.ui.onResume(this);
ui.onResume(this);
updateAdapter();
}
@ -285,6 +275,7 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
@Override
public void onDestroy() {
bus.unregister(this);
if (clearDialog != null) {
clearDialog.dismiss();
clearDialog = null;
@ -323,31 +314,13 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
return adapter;
}
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case history_state_added:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
@Subscribe
void onHistoryChanged(@Nonnull History.ChangedEvent e) {
if (e.recent != isRecentHistory()) {
return;
}
updateAdapter();
}
});
break;
case clear_history_requested:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
clearDialog = new AlertDialog.Builder(getActivity()).setTitle(R.string.cpp_clear_history_title)
.setMessage(R.string.cpp_clear_history_message)
.setPositiveButton(R.string.cpp_clear_history, clearDialogListener)
.setNegativeButton(R.string.c_cancel, clearDialogListener)
.create();
clearDialog.show();
}
});
break;
}
}
protected abstract boolean isRecentHistory();
}

View File

@ -22,30 +22,24 @@
package org.solovyev.android.calculator.history;
import android.app.Application;
import android.content.SharedPreferences;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.google.common.base.Strings;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.json.JSONArray;
import org.json.JSONException;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.AppModule;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.*;
import org.solovyev.android.io.FileLoader;
import org.solovyev.android.io.FileSaver;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@ -53,16 +47,13 @@ import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import static java.lang.Character.isDigit;
import static android.text.TextUtils.isEmpty;
public class 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_SAVED = new ChangedEvent(false);
@NonNull
private final Runnable writeRecent = new WriteTask(true);
@NonNull
@ -71,17 +62,22 @@ public class History {
private final RecentHistory recent = new RecentHistory();
@Nonnull
private final List<HistoryState> saved = new ArrayList<>();
@Nonnull
private final Bus bus;
@Inject
Handler handler;
@Inject
SharedPreferences preferences;
@Nullable
private EditorState lastEditorState;
@Inject
Editor editor;
@Inject
Application application;
private boolean initialized;
@Inject
public History(Bus bus, @Named(AppModule.THREAD_INIT) Executor initThread) {
bus.register(this);
public History(@NonNull Bus bus, @Nonnull @Named(AppModule.THREAD_INIT) Executor initThread) {
this.bus = bus;
this.bus.register(this);
initThread.execute(new Runnable() {
@Override
public void run() {
@ -90,23 +86,6 @@ public class History {
});
}
private void migrateOldHistory() {
try {
final String xml = preferences.getString("org.solovyev.android.calculator.CalculatorModel_history", null);
if (TextUtils.isEmpty(xml)) {
return;
}
final List<HistoryState> states = convertOldHistory(xml);
if (states == null) {
return;
}
final JSONArray json = RecentHistory.toJson(states);
FileSaver.save(getSavedHistoryFile(), json.toString());
} catch (Exception e) {
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e);
}
}
@Nullable
static List<HistoryState> convertOldHistory(@NonNull String xml) {
final OldHistory history = OldHistory.fromXml(xml);
@ -129,13 +108,13 @@ public class History {
}
@NonNull
private static File getSavedHistoryFile() {
return new File(App.getApplication().getFilesDir(), "history-saved.json");
private File getSavedHistoryFile() {
return new File(application.getFilesDir(), "history-saved.json");
}
@NonNull
private static File getRecentHistoryFile() {
return new File(App.getApplication().getFilesDir(), "history-recent.json");
private File getRecentHistoryFile() {
return new File(application.getFilesDir(), "history-recent.json");
}
@Nonnull
@ -144,7 +123,7 @@ public class History {
return Collections.emptyList();
}
final CharSequence json = FileLoader.load(file);
if (TextUtils.isEmpty(json)) {
if (isEmpty(json)) {
return Collections.emptyList();
}
try {
@ -155,6 +134,44 @@ public class History {
return Collections.emptyList();
}
private static boolean isIntermediate(@Nonnull String olderText,
@Nonnull String newerText) {
if (isEmpty(olderText)) {
return true;
}
if (isEmpty(newerText)) {
return false;
}
final int diff = newerText.length() - olderText.length();
if (diff >= 1) {
return newerText.startsWith(olderText);
} else if (diff <= 1) {
return olderText.startsWith(newerText);
} else if (diff == 0) {
return olderText.equals(newerText);
}
return false;
}
private void migrateOldHistory() {
try {
final String xml = preferences.getString("org.solovyev.android.calculator.CalculatorModel_history", null);
if (isEmpty(xml)) {
return;
}
final List<HistoryState> states = convertOldHistory(xml);
if (states == null) {
return;
}
final JSONArray json = RecentHistory.toJson(states);
FileSaver.save(getSavedHistoryFile(), json.toString());
} catch (Exception e) {
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e);
}
}
private void init() {
Check.isNotMainThread();
migrateOldHistory();
@ -175,7 +192,6 @@ public class History {
public void addRecent(@Nonnull HistoryState state) {
Check.isMainThread();
recent.add(state);
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.history_state_added, state);
onRecentChanged();
}
@ -188,11 +204,13 @@ public class History {
private void onRecentChanged() {
handler.removeCallbacks(writeRecent);
handler.postDelayed(writeRecent, 500);
bus.post(CHANGED_EVENT_RECENT);
}
private void onSavedChanged() {
handler.removeCallbacks(writeSaved);
handler.postDelayed(writeSaved, 500);
bus.post(CHANGED_EVENT_SAVED);
}
@Nonnull
@ -201,8 +219,6 @@ public class History {
final List<HistoryState> result = new LinkedList<>();
final String groupingSeparator = AndroidCalculatorEngine.Preferences.groupingSeparator.getPreference(App.getPreferences());
final List<HistoryState> states = recent.asList();
final int statesCount = states.size();
for (int i = 1; i < statesCount; i++) {
@ -210,13 +226,14 @@ public class History {
final HistoryState newerState = states.get(i);
final String olderText = olderState.editor.getTextString();
final String newerText = newerState.editor.getTextString();
if (!isIntermediate(olderText, newerText, groupingSeparator)) {
if (!isIntermediate(olderText, newerText)) {
result.add(0, olderState);
}
}
if (statesCount > 0) {
// try add last state if not empty
final HistoryState state = states.get(statesCount - 1);
if (!TextUtils.isEmpty(state.editor.getTextString())) {
if (!isEmpty(state.editor.getTextString())) {
result.add(0, state);
}
}
@ -229,53 +246,6 @@ public class History {
return new ArrayList<>(saved);
}
private static boolean isIntermediate(@Nonnull String olderText,
@Nonnull String newerText,
@NonNull String groupingSeparator) {
if (TextUtils.isEmpty(olderText)) {
return true;
}
if (TextUtils.isEmpty(newerText)) {
return false;
}
olderText = trimGroupingSeparators(olderText, groupingSeparator);
newerText = trimGroupingSeparators(newerText, groupingSeparator);
final int diff = newerText.length() - olderText.length();
if (diff >= 1) {
return newerText.startsWith(olderText);
} else if (diff <= 1) {
return olderText.startsWith(newerText);
} else if (diff == 0) {
return olderText.equals(newerText);
}
return false;
}
@NonNull
private static String trimGroupingSeparators(@NonNull String text, @NonNull String groupingSeparator) {
if (TextUtils.isEmpty(groupingSeparator)) {
return text;
}
Check.isTrue(groupingSeparator.length() == 1);
final StringBuilder sb = new StringBuilder(text.length());
for (int i = 0; i < text.length(); i++) {
if (i == 0 || i == text.length() - 1) {
// grouping separator can't be the first and the last character
sb.append(text.charAt(i));
continue;
}
if (isDigit(text.charAt(i - 1)) && text.charAt(i) == groupingSeparator.charAt(0) && isDigit(text.charAt(i + 1))) {
// grouping separator => skip
continue;
}
sb.append(text.charAt(i));
}
return sb.toString();
}
public void clearRecent() {
Check.isMainThread();
recent.clear();
@ -321,27 +291,25 @@ public class History {
onRecentChanged();
}
@Subscribe
public void onEditorChanged(@Nonnull Editor.ChangedEvent e) {
if (!initialized) {
return;
}
lastEditorState = e.newState;
}
@Subscribe
public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
if (!initialized) {
return;
}
if (lastEditorState == null) {
final EditorState editorState = editor.getState();
final DisplayState displayState = e.newState;
if (editorState.sequence != displayState.sequence) {
return;
}
if (lastEditorState.sequence != e.newState.sequence) {
return;
addRecent(HistoryState.newBuilder(editorState, displayState).build());
}
public static class ChangedEvent {
public final boolean recent;
public ChangedEvent(boolean recent) {
this.recent = recent;
}
addRecent(HistoryState.newBuilder(lastEditorState, e.newState).build());
lastEditorState = null;
}
private class WriteTask implements Runnable {

View File

@ -25,9 +25,8 @@ package org.solovyev.android.calculator.history;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.R;
import java.util.List;
import javax.annotation.Nonnull;
import java.util.List;
public class RecentHistoryFragment extends BaseHistoryFragment {
@ -51,4 +50,9 @@ public class RecentHistoryFragment extends BaseHistoryFragment {
history.clearRecent();
getAdapter().clear();
}
@Override
protected boolean isRecentHistory() {
return true;
}
}

View File

@ -25,9 +25,8 @@ package org.solovyev.android.calculator.history;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.R;
import java.util.List;
import javax.annotation.Nonnull;
import java.util.List;
public class SavedHistoryFragment extends BaseHistoryFragment {
@ -51,4 +50,9 @@ public class SavedHistoryFragment extends BaseHistoryFragment {
history.clearSaved();
getAdapter().clear();
}
@Override
protected boolean isRecentHistory() {
return false;
}
}

View File

@ -1,5 +1,6 @@
package org.solovyev.android;
import android.os.Build;
import org.junit.runners.model.InitializationError;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
@ -7,7 +8,7 @@ import org.robolectric.manifest.AndroidManifest;
import org.robolectric.res.Fs;
public class CalculatorTestRunner extends RobolectricGradleTestRunner {
private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18;
public static final int SUPPORTED_SDK = Build.VERSION_CODES.LOLLIPOP;
public CalculatorTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
@ -21,7 +22,7 @@ public class CalculatorTestRunner extends RobolectricGradleTestRunner {
return new AndroidManifest(Fs.fileFromPath(manifestFilePath), Fs.fileFromPath(resourcesFilePath), Fs.fileFromPath(assetsFilePath)) {
@Override
public int getTargetSdkVersion() {
return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
return SUPPORTED_SDK;
}
};
}

View File

@ -22,9 +22,12 @@
package org.solovyev.android.calculator;
import com.squareup.otto.Bus;
import org.mockito.Mockito;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import java.util.concurrent.Executor;
/**
* User: serso
* Date: 10/7/12
@ -33,7 +36,7 @@ import org.solovyev.android.calculator.plot.CalculatorPlotter;
public class AbstractCalculatorTest {
protected void setUp() throws Exception {
Locator.getInstance().init(new CalculatorImpl(null, eventExecutor), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init();
}

View File

@ -23,32 +23,25 @@
package org.solovyev.android.calculator;
import android.content.Context;
import com.squareup.otto.Bus;
import jscl.JsclMathEngine;
import org.junit.Assert;
import org.mockito.Mockito;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.fakes.RoboSharedPreferences;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.text.DecimalFormatSymbols;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.JsclMathEngine;
/**
* User: serso
* Date: 10/7/12
@ -60,8 +53,8 @@ public class CalculatorTestUtils {
public static final int TIMEOUT = 3;
public static void staticSetUp() throws Exception {
App.init(RuntimeEnvironment.application, new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0)));
Locator.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0)));
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init();
final DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols();
@ -71,7 +64,7 @@ public class CalculatorTestUtils {
}
public static void staticSetUp(@Nullable Context context) throws Exception {
Locator.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().init(new CalculatorImpl(Mockito.mock(Bus.class), Mockito.mock(Executor.class)), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init();
if (context != null) {

View File

@ -22,9 +22,11 @@
package org.solovyev.android.calculator;
import android.preference.PreferenceManager;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.robolectric.RuntimeEnvironment;
import javax.annotation.Nonnull;
@ -41,7 +43,7 @@ public class EditorTest extends AbstractCalculatorTest {
@Before
public void setUp() throws Exception {
super.setUp();
this.editor = new Editor(null);
this.editor = new Editor(PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application));
}
@Test

View File

@ -22,61 +22,172 @@
package org.solovyev.android.calculator.history;
import android.content.SharedPreferences;
import android.os.Handler;
import com.squareup.otto.Bus;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.solovyev.android.CalculatorTestRunner;
import org.solovyev.android.calculator.CalculatorTestUtils;
import org.solovyev.android.calculator.BuildConfig;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(CalculatorTestRunner.class)
@Config(constants = BuildConfig.class, sdk = CalculatorTestRunner.SUPPORTED_SDK)
@RunWith(RobolectricGradleTestRunner.class)
public class HistoryTest {
@BeforeClass
public static void setUp() throws Exception {
CalculatorTestUtils.staticSetUp();
private History history;
@Before
public void setUp() throws Exception {
history = new History(Mockito.mock(Bus.class), Mockito.mock(Executor.class));
history.handler = Mockito.mock(Handler.class);
history.preferences = Mockito.mock(SharedPreferences.class);
history.editor = Mockito.mock(Editor.class);
history.application = RuntimeEnvironment.application;
}
@Test
public void testGetStates() throws Exception {
History history = new History(Mockito.any(Bus.class), new Executor() {
@Override
public void execute(@Nonnull Runnable command) {
command.run();
}
});
addState(history, "1");
addState(history, "12");
addState(history, "123");
addState(history, "123+");
addState(history, "123+3");
addState(history, "");
addState(history, "2");
addState(history, "23");
addState(history, "235");
addState(history, "2355");
addState(history, "235");
addState(history, "2354");
addState(history, "23547");
addState("1");
addState("12");
addState("123");
addState("123+");
addState("123+3");
addState("");
addState("2");
addState("23");
addState("235");
addState("2355");
addState("235");
addState("2354");
addState("23547");
final List<HistoryState> states = history.getRecent();
Assert.assertEquals(2, states.size());
Assert.assertEquals("23547", states.get(1).editor.getTextString());
Assert.assertEquals("123+3", states.get(0).editor.getTextString());
assertEquals(2, states.size());
assertEquals("23547", states.get(0).editor.getTextString());
assertEquals("123+3", states.get(1).editor.getTextString());
}
private void addState(@Nonnull History history, @Nonnull String text) {
@Test
public void testRecentHistoryShouldNotContainEmptyStates() throws Exception {
addState("");
addState("1");
addState("12");
addState("");
addState("");
addState("34");
addState("");
final List<HistoryState> states = history.getRecent();
assertEquals(2, states.size());
assertEquals("34", states.get(0).editor.getTextString());
assertEquals("12", states.get(1).editor.getTextString());
}
private void addState(@Nonnull String text) {
history.addRecent(HistoryState.newBuilder(EditorState.create(text, 3), DisplayState.empty()));
}
private static final String oldXml1 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
private static final String oldXml2 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>2</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text></text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>elementary</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
@Test
public void testShouldConvertOldHistory() throws Exception {
List<HistoryState> states = History.convertOldHistory(oldXml1);
assertNotNull(states);
assertEquals(1, states.size());
HistoryState state = states.get(0);
assertEquals(100000000, state.time);
}
}

View File

@ -34,85 +34,6 @@ public class HistoryUtilsTest {
private static final String emptyHistory = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\"/>\n" +
"</history>";
private static final String toXml1 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
private static final String toXml2 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>2</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text></text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>elementary</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
@Test
public void testFromXml() throws Exception {