package com.mapzen.pelias.widget;
import com.mapzen.pelias.BuildConfig;
import com.mapzen.pelias.Pelias;
import com.mapzen.pelias.PeliasService;
import com.mapzen.pelias.PeliasTest;
import com.mapzen.pelias.R;
import com.mapzen.pelias.SavedSearch;
import com.mapzen.pelias.SimpleFeature;
import com.mapzen.pelias.SimpleFeatureTest;
import com.mapzen.pelias.gson.Feature;
import com.mapzen.pelias.gson.Geometry;
import com.mapzen.pelias.gson.Properties;
import com.mapzen.pelias.gson.Result;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import android.app.Activity;
import android.os.Parcel;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import okhttp3.Request;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.http.Query;
@RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21,
shadows = { ShadowInputMethodManager.class })
public class PeliasSearchViewTest {
private static final Activity ACTIVITY = Robolectric.setupActivity(Activity.class);
private PeliasSearchView peliasSearchView;
@Before public void setUp() throws Exception {
ACTIVITY.setTheme(R.style.TestAppTheme);
peliasSearchView = new PeliasSearchView(ACTIVITY);
}
@Test public void shouldNotBeNull() throws Exception {
assertThat(peliasSearchView).isNotNull();
}
@Test public void setAutoCompleteListView_shouldShowListViewWhenQueryGetsFocus()
throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(GONE);
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(true);
assertThat(listView.getVisibility()).isEqualTo(VISIBLE);
}
@Test public void setAutoCompleteListView_shouldHideListViewWhenQueryLosesFocus()
throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(VISIBLE);
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(false);
assertThat(listView.getVisibility()).isEqualTo(GONE);
}
@Test public void setAutoCompleteListView_shouldShowImeWhenQueryGetsFocus() throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(GONE);
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(false);
shadowOf(queryText).setViewFocus(true);
Robolectric.flushForegroundThreadScheduler();
assertThat(ShadowInputMethodManager.isSoftInputVisible()).isTrue();
}
@Test public void setAutoCompleteListView_shouldHideImeWhenQueryGetsFocus() throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(GONE);
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(true);
shadowOf(queryText).setViewFocus(false);
Robolectric.flushForegroundThreadScheduler();
assertThat(ShadowInputMethodManager.isSoftInputVisible()).isFalse();
}
@Test public void disableAutoKeyboardShow_shouldNotShowImeWhenQueryGetsFocus() throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(GONE);
peliasSearchView.disableAutoKeyboardShow();
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(true);
Robolectric.flushForegroundThreadScheduler();
assertThat(ShadowInputMethodManager.isSoftInputVisible()).isFalse();
}
@Test public void enableAutoKeyboardShow_shouldShowImeWhenQueryGetsFocus() throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setVisibility(GONE);
peliasSearchView.disableAutoKeyboardShow();
peliasSearchView.enableAutoKeyboardShow();
peliasSearchView.setAutoCompleteListView(listView);
AutoCompleteTextView queryText = getQueryTextView();
shadowOf(queryText).setViewFocus(true);
Robolectric.flushForegroundThreadScheduler();
assertThat(ShadowInputMethodManager.isSoftInputVisible()).isTrue();
}
@Test public void onQueryTextSubmit_shouldNotClearFocus() throws Exception {
peliasSearchView.requestFocus();
peliasSearchView.onQueryTextSubmit("query");
assertThat(peliasSearchView.isFocused()).isTrue();
}
@Test public void onQueryTextSubmit_shouldHideListView() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.onQueryTextSubmit("query");
assertThat(listView.getVisibility()).isEqualTo(GONE);
}
@Test public void onQueryTextSubmit_submitListener_shouldNotHideListView() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.setSearchSubmitListener(new TestSearchSubmitListener());
peliasSearchView.onQueryTextSubmit("query");
assertThat(listView.getVisibility()).isEqualTo(VISIBLE);
}
@Test public void onQueryTextSubmit_submitListener_shouldNotSearch() throws Exception {
peliasSearchView.setSearchSubmitListener(new TestSearchSubmitListener());
Pelias pelias = mock(Pelias.class);
peliasSearchView.setPelias(pelias);
peliasSearchView.onQueryTextSubmit("query");
verify(pelias, times(0)).search(anyString(), any(Callback.class));
}
@Test public void onQueryTextSubmit_shouldSaveSearch() throws Exception {
SavedSearch savedSearch = new SavedSearch();
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.onQueryTextSubmit("query");
assertThat(savedSearch.size()).isEqualTo(1);
assertThat(savedSearch.get(0).getTerm()).isEqualTo("query");
}
@Test public void loadSavedSearches_shouldAddTermsToAutoCompleteListView() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
final AutoCompleteAdapter adapter =
new AutoCompleteAdapter(ACTIVITY, android.R.layout.simple_list_item_1);
final SavedSearch savedSearch = new SavedSearch();
savedSearch.store("query");
listView.setAdapter(adapter);
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.loadSavedSearches();
assertThat(adapter.getCount()).isEqualTo(1);
assertThat(((TextView) adapter.getView(0, null, null)).getText()).isEqualTo("query");
}
@Test public void loadSavedSearches_shouldAddPayloadToAutocompleteListView() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
final AutoCompleteAdapter adapter =
new AutoCompleteAdapter(ACTIVITY, android.R.layout.simple_list_item_1);
final SavedSearch savedSearch = new SavedSearch();
final Parcel payload = Parcel.obtain();
final SimpleFeature simpleFeature = SimpleFeatureTest.getTestSimpleFeature();
simpleFeature.writeToParcel(payload, 0);
payload.setDataPosition(0);
savedSearch.store("Test SimpleFeature", payload);
listView.setAdapter(adapter);
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.loadSavedSearches();
assertThat(adapter.getCount()).isEqualTo(1);
assertThat(adapter.getItem(0).getText()).isEqualTo(simpleFeature.label());
assertThat(adapter.getItem(0).getSimpleFeature()).isEqualTo(simpleFeature);
}
@Test public void onQueryTextSubmit_shouldFetchSearchResults() throws Exception {
final Pelias pelias = new TestPelias();
final TestCallback callback = new TestCallback();
pelias.setLocationProvider(new PeliasTest.TestLocationProvider());
peliasSearchView.setPelias(pelias);
peliasSearchView.setCallback(callback);
peliasSearchView.setQuery("query", true);
assertThat(callback.result).isNotNull();
assertThat(callback.error).isNull();
}
@Test public void onQueryTextSubmit_shouldHandleNullBody() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
final TestEmptyAdapter adapter = new TestEmptyAdapter();
listView.setAdapter(adapter);
peliasSearchView.setAutoCompleteListView(listView);
final Pelias pelias = new TestEmptyPelias();
final Callback<Result> callback = peliasSearchView.getSuggestCallback();
pelias.setLocationProvider(new PeliasTest.TestLocationProvider());
peliasSearchView.setPelias(pelias);
peliasSearchView.setCallback(callback);
peliasSearchView.setQuery("query", true);
assertThat(adapter.getCount()).isEqualTo(0);
}
@Test public void onItemClick_shouldSetQuery() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setAdapter(new TestAdapter());
peliasSearchView.setAutoCompleteListView(listView);
listView.performItemClick(null, 1, 0);
assertThat(peliasSearchView.getQuery().toString()).isEqualTo("query");
}
@Test public void onItemClick_simpleFeature_shouldSetQuery() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setAdapter(new TestSimpleFeatureAdapter());
peliasSearchView.setAutoCompleteListView(listView);
listView.performItemClick(null, 1, 0);
assertThat(peliasSearchView.getQuery().toString()).isEqualTo("query");
}
@Test public void onItemClick_noFocus_shouldHideListView() throws Exception {
final AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
listView.setAdapter(new TestSimpleFeatureAdapter());
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.clearFocus();
listView.performItemClick(null, 1, 0);
assertThat(listView.getVisibility()).isEqualTo(GONE);
}
@Test public void onQueryTextSubmit_shouldNotifyOnSubmitListener() throws Exception {
TestOnSubmitListener listener = new TestOnSubmitListener();
peliasSearchView.setOnSubmitListener(listener);
peliasSearchView.onQueryTextSubmit("query");
assertThat(listener.submit).isTrue();
}
@Test public void setOnPeliasFocusChangeListener_shouldNotifyListener() throws Exception {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
TestOnFocusChangeListener listener = new TestOnFocusChangeListener();
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.setOnPeliasFocusChangeListener(listener);
shadowOf(getQueryTextView()).setViewFocus(true);
assertThat(listener.hasFocus).isTrue();
}
@Test public void onBackPressListener_shouldNotifyWhenKeyboardVisibleAndBackPressed()
throws Exception {
TestOnBackPressListener listener = new TestOnBackPressListener();
peliasSearchView.setOnBackPressListener(listener);
shadowOf(getQueryTextView()).setViewFocus(true);
peliasSearchView.notifyOnBackPressListener();
assertThat(listener.pressed).isTrue();
}
@Test public void onBackPressListener_shouldNotNotifyOnAutocompleteItemClicked() {
TestOnBackPressListener listener = new TestOnBackPressListener();
peliasSearchView.setOnBackPressListener(listener);
shadowOf(getQueryTextView()).setViewFocus(true);
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
peliasSearchView.setAutoCompleteListView(listView);
final AutoCompleteAdapter adapter =
new AutoCompleteAdapter(ACTIVITY, android.R.layout.simple_list_item_1);
final SavedSearch savedSearch = new SavedSearch();
final Parcel payload = Parcel.obtain();
final SimpleFeature simpleFeature = SimpleFeatureTest.getTestSimpleFeature();
simpleFeature.writeToParcel(payload, 0);
payload.setDataPosition(0);
savedSearch.store("Test", payload);
listView.setAdapter(adapter);
peliasSearchView.setAutoCompleteListView(listView);
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.loadSavedSearches();
shadowOf(listView).performItemClick(0);
assertThat(listener.pressed).isFalse();
}
@Test public void onBackPressListener_shouldNotNotifyOnSearchSubmitted() {
TestOnBackPressListener listener = new TestOnBackPressListener();
peliasSearchView.setOnBackPressListener(listener);
shadowOf(getQueryTextView()).setViewFocus(true);
peliasSearchView.onQueryTextSubmit("Test");
assertThat(listener.pressed).isFalse();
}
@Test public void onBackPressListener_shouldNotNotifyWhenSearchViewFocused() {
TestOnBackPressListener listener = new TestOnBackPressListener();
peliasSearchView.setOnBackPressListener(listener);
shadowOf(getQueryTextView()).setViewFocus(true);
assertThat(listener.pressed).isFalse();
}
@Test public void shouldCacheSearchResultsByDefault() {
assertThat(peliasSearchView.cacheSearchResults()).isTrue();
}
@Test public void setCacheSearchResults_shouldSaveQueryOnSearch() {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
peliasSearchView.setAutoCompleteListView(listView);
SavedSearch savedSearch = new SavedSearch();
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.onQueryTextSubmit("test");
assertThat(savedSearch.getItems().size()).isEqualTo(1);
}
@Test public void setCacheSearchResultsDisabled_shouldNotSaveQueryOnSearch() {
AutoCompleteListView listView = new AutoCompleteListView(ACTIVITY);
peliasSearchView.setAutoCompleteListView(listView);
SavedSearch savedSearch = new SavedSearch();
peliasSearchView.setSavedSearch(savedSearch);
peliasSearchView.setCacheSearchResults(false);
peliasSearchView.onQueryTextSubmit("test");
assertThat(savedSearch.getItems().size()).isEqualTo(0);
}
@Test public void setSavedSearch_shouldClearSaveSearchesIfCacheSearchResultsDisabled() {
peliasSearchView.setCacheSearchResults(false);
SavedSearch savedSearch = new SavedSearch();
savedSearch.store("test");
peliasSearchView.setSavedSearch(savedSearch);
assertThat(savedSearch.getItems().size()).isEqualTo(0);
}
private AutoCompleteTextView getQueryTextView() {
final LinearLayout linearLayout1 = (LinearLayout) peliasSearchView.getChildAt(0);
final LinearLayout linearLayout2 = (LinearLayout) linearLayout1.getChildAt(2);
final LinearLayout linearLayout3 = (LinearLayout) linearLayout2.getChildAt(1);
return (AutoCompleteTextView) linearLayout3.getChildAt(0);
}
private class TestPelias extends Pelias {
protected TestPelias() {
super(new TestPeliasService());
}
}
private class TestPeliasService implements PeliasService {
@Override public Call<Result> getSuggest(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon) {
return new TestCall();
}
@Override public Call<Result> getSuggest(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon,
@Query("layers") String layers, @Query("boundary.country") String country,
@Query("sources") String source) {
return new TestCall();
}
@Override public Call<Result> getSearch(@Query("text") String query,
@Query("focus.viewport.min_lon") double minLon,
@Query("focus.viewport.min_lat") double minLat,
@Query("focus.viewport.max_lon") double maxLon,
@Query("focus.viewport.max_lat") double maxLat) {
return new TestCall();
}
@Override public Call<Result> getSearch(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon) {
return new TestCall();
}
@Override public Call<Result> getReverse(@Query("point.lat") double lat,
@Query("point.lon") double lon) {
return new TestCall();
}
@Override
public Call<Result> getReverse(@Query("point.lat") double lat, @Query("point.lon") double lon,
@Query("sources") String sources) {
return new TestCall();
}
@Override public Call<Result> getPlace(@Query("ids") String ids) {
return new TestCall();
}
}
private class TestCall implements Call<Result> {
@Override public Response<Result> execute() throws IOException {
return Response.success(new Result());
}
@Override public void enqueue(Callback<Result> callback) {
callback.onResponse(null, Response.success(new Result()));
}
@Override public boolean isExecuted() {
return false;
}
@Override public void cancel() {
}
@Override public boolean isCanceled() {
return false;
}
@Override public Call<Result> clone() {
return null;
}
@Override public Request request() {
return null;
}
}
private class TestEmptyPelias extends Pelias {
protected TestEmptyPelias() {
super(new TestEmptyPeliasService());
}
}
private class TestEmptyPeliasService implements PeliasService {
@Override public Call<Result> getSuggest(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon) {
return new TestEmptyCall();
}
@Override public Call<Result> getSuggest(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon,
@Query("layers") String layers, @Query("boundary.country") String country,
@Query("sources") String source) {
return new TestEmptyCall();
}
@Override public Call<Result> getSearch(@Query("text") String query,
@Query("focus.viewport.min_lon") double minLon,
@Query("focus.viewport.min_lat") double minLat,
@Query("focus.viewport.max_lon") double maxLon,
@Query("focus.viewport.max_lat") double maxLat) {
return new TestEmptyCall();
}
@Override public Call<Result> getSearch(@Query("text") String query,
@Query("focus.point.lat") double lat, @Query("focus.point.lon") double lon) {
return new TestEmptyCall();
}
@Override public Call<Result> getReverse(@Query("point.lat") double lat,
@Query("point.lon") double lon) {
return new TestEmptyCall();
}
@Override
public Call<Result> getReverse(@Query("point.lat") double lat, @Query("point.lon") double lon,
@Query("sources") String sources) {
return new TestEmptyCall();
}
@Override public Call<Result> getPlace(@Query("ids") String ids) {
return new TestEmptyCall();
}
}
private class TestEmptyCall implements Call<Result> {
@Override public Response<Result> execute() throws IOException {
return Response.success(null);
}
@Override public void enqueue(Callback<Result> callback) {
callback.onResponse(null, null);
}
@Override public boolean isExecuted() {
return false;
}
@Override public void cancel() {
}
@Override public boolean isCanceled() {
return false;
}
@Override public Call<Result> clone() {
return null;
}
@Override public Request request() {
return null;
}
}
private class TestEmptyAdapter extends AutoCompleteAdapter {
Collection<? extends AutoCompleteItem> items = new HashSet<>();
public TestEmptyAdapter() {
super(ACTIVITY, android.R.layout.simple_list_item_1);
}
@Override public void addAll(Collection<? extends AutoCompleteItem> collection) {
this.items = collection;
}
@Override public AutoCompleteItem getItem(int position) {
return new AutoCompleteItem("query");
}
@Override public int getCount() {
return items.size();
}
}
private class TestCallback implements Callback<Result> {
private Result result;
private Throwable error;
@Override public void onResponse(Call<Result> call, Response<Result> response) {
result = response.body();
}
@Override public void onFailure(Call<Result> call, Throwable t) {
error = t;
}
}
private class TestAdapter extends AutoCompleteAdapter {
public TestAdapter() {
super(ACTIVITY, android.R.layout.simple_list_item_1);
}
@Override public AutoCompleteItem getItem(int position) {
return new AutoCompleteItem("query");
}
@Override public int getCount() {
return 1;
}
}
private class TestSimpleFeatureAdapter extends AutoCompleteAdapter {
public TestSimpleFeatureAdapter() {
super(ACTIVITY, android.R.layout.simple_list_item_1);
}
@Override public AutoCompleteItem getItem(int position) {
Feature feature = new Feature();
feature.properties = new Properties();
feature.properties.label = "query";
feature.geometry = new Geometry();
feature.geometry.coordinates = new ArrayList<>();
feature.geometry.coordinates.add(0.0);
feature.geometry.coordinates.add(1.0);
return new AutoCompleteItem(SimpleFeature.fromFeature(feature));
}
@Override public int getCount() {
return 1;
}
}
private class TestOnSubmitListener implements PeliasSearchView.OnSubmitListener {
private boolean submit;
@Override public void onSubmit() {
submit = true;
}
}
private class TestOnFocusChangeListener implements View.OnFocusChangeListener {
private boolean hasFocus;
@Override public void onFocusChange(View v, boolean hasFocus) {
this.hasFocus = hasFocus;
}
}
private class TestOnBackPressListener implements PeliasSearchView.OnBackPressListener {
private boolean pressed;
@Override public void onBackPressed() {
pressed = true;
}
}
private class TestSearchSubmitListener implements SearchSubmitListener {
@Override public boolean searchOnSearchKeySubmit() {
return false;
}
@Override public boolean hideAutocompleteOnSearchSubmit() {
return false;
}
}
}