/*
* Copyright (c) 2016 Felipe Morato <me@fmorato.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gnucash.android.test.ui;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.contrib.DrawerActions;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import org.gnucash.android.R;
import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.DatabaseHelper;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.db.adapter.CommoditiesDbAdapter;
import org.gnucash.android.db.adapter.DatabaseAdapter;
import org.gnucash.android.model.Account;
import org.gnucash.android.model.Commodity;
import org.gnucash.android.model.Money;
import org.gnucash.android.model.Split;
import org.gnucash.android.model.Transaction;
import org.gnucash.android.ui.account.AccountsActivity;
import org.junit.Assume;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.clearText;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.swipeUp;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.gnucash.android.test.ui.AccountsActivityTest.preventFirstRunDialogs;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OwnCloudExportTest {
private AccountsActivity mAccountsActivity;
private SharedPreferences mPrefs;
private String OC_SERVER = "https://demo.owncloud.org";
private String OC_USERNAME = "test";
private String OC_PASSWORD = "test";
private String OC_DIR = "gc_test";
/**
* A JUnit {@link Rule @Rule} to launch your activity under test. This is a replacement
* for {@link ActivityInstrumentationTestCase2}.
* <p>
* Rules are interceptors which are executed for each test method and will run before
* any of your setup code in the {@link Before @Before} method.
* <p>
* {@link ActivityTestRule} will create and launch of the activity for you and also expose
* the activity under test. To get a reference to the activity you can use
* the {@link ActivityTestRule#getActivity()} method.
*/
@Rule
public ActivityTestRule<AccountsActivity> mActivityRule = new ActivityTestRule<>(
AccountsActivity.class);
@Before
public void setUp() throws Exception {
mAccountsActivity = mActivityRule.getActivity();
mPrefs = mAccountsActivity.getSharedPreferences(
mAccountsActivity.getString(R.string.owncloud_pref), Context.MODE_PRIVATE);
preventFirstRunDialogs(getInstrumentation().getTargetContext());
// creates Account and transaction
String activeBookUID = BooksDbAdapter.getInstance().getActiveBookUID();
DatabaseHelper mDbHelper = new DatabaseHelper(mAccountsActivity, activeBookUID);
SQLiteDatabase mDb;
try {
mDb = mDbHelper.getWritableDatabase();
} catch (SQLException e) {
Log.e(getClass().getName(), "Error getting database: " + e.getMessage());
mDb = mDbHelper.getReadableDatabase();
}
@SuppressWarnings("unused") //this call initializes constants in Commodity
CommoditiesDbAdapter commoditiesDbAdapter = new CommoditiesDbAdapter(mDb);
AccountsDbAdapter mAccountsDbAdapter = AccountsDbAdapter.getInstance();
mAccountsDbAdapter.deleteAllRecords();
String currencyCode = GnuCashApplication.getDefaultCurrencyCode();
Commodity.DEFAULT_COMMODITY = CommoditiesDbAdapter.getInstance().getCommodity(currencyCode);
Account account = new Account("ownCloud");
Transaction transaction = new Transaction("birds");
transaction.setTime(System.currentTimeMillis());
Split split = new Split(new Money("11.11", currencyCode), account.getUID());
transaction.addSplit(split);
transaction.addSplit(split.createPair(
mAccountsDbAdapter.getOrCreateImbalanceAccountUID(Commodity.DEFAULT_COMMODITY)));
account.addTransaction(transaction);
mAccountsDbAdapter.addRecord(account, DatabaseAdapter.UpdateMethod.insert);
SharedPreferences.Editor editor = mPrefs.edit();
editor.putBoolean(mAccountsActivity.getString(R.string.key_owncloud_sync), false).apply();
editor.putInt(mAccountsActivity.getString(R.string.key_last_export_destination), 0);
editor.apply();
}
/**
* Test if there is an active internet connection on the device/emulator
* @return {@code true} is an internet connection is available, {@code false} otherwise
*/
public static boolean hasActiveInternetConnection(){
ConnectivityManager connectivityManager
= (ConnectivityManager) GnuCashApplication.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
/**
* It might fail if it takes too long to connect to the server or if there is no network
*/
@Test
public void OwnCloudCredentials() {
Assume.assumeTrue(hasActiveInternetConnection());
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(swipeUp());
onView(withText(R.string.title_settings)).perform(click());
onView(withText(R.string.header_backup_and_export_settings)).perform(click());
onView(withText(R.string.title_owncloud_sync_preference)).perform(click());
onView(withId(R.id.owncloud_hostname)).check(matches(isDisplayed()));
onView(withId(R.id.owncloud_hostname)).perform(clearText()).perform(typeText(OC_SERVER), closeSoftKeyboard());
onView(withId(R.id.owncloud_username)).perform(clearText()).perform(typeText(OC_USERNAME), closeSoftKeyboard());
onView(withId(R.id.owncloud_password)).perform(clearText()).perform(typeText(OC_PASSWORD), closeSoftKeyboard());
onView(withId(R.id.owncloud_dir)).perform(clearText()).perform(typeText(OC_DIR), closeSoftKeyboard());
onView(withId(R.id.btn_save)).perform(click());
sleep(5000);
onView(withId(R.id.btn_save)).perform(click());
assertEquals(mPrefs.getString(mAccountsActivity.getString(R.string.key_owncloud_server), null), OC_SERVER);
assertEquals(mPrefs.getString(mAccountsActivity.getString(R.string.key_owncloud_username), null), OC_USERNAME);
assertEquals(mPrefs.getString(mAccountsActivity.getString(R.string.key_owncloud_password), null), OC_PASSWORD);
assertEquals(mPrefs.getString(mAccountsActivity.getString(R.string.key_owncloud_dir), null), OC_DIR);
assertTrue(mPrefs.getBoolean(mAccountsActivity.getString(R.string.key_owncloud_sync), false));
}
//// FIXME: 20.04.2017 This test now fails since introduction of SAF.
public void OwnCloudExport() {
Assume.assumeTrue(hasActiveInternetConnection());
mPrefs.edit().putBoolean(mAccountsActivity.getString(R.string.key_owncloud_sync), true).commit();
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withText(R.string.nav_menu_export)).perform(click());
Espresso.closeSoftKeyboard();
Espresso.pressBack(); //close the SAF file picker window
onView(withId(R.id.spinner_export_destination)).perform(click());
String[] destinations = mAccountsActivity.getResources().getStringArray(R.array.export_destinations);
onView(withText(destinations[3])).perform(click());
onView(withId(R.id.menu_save)).perform(click());
assertToastDisplayed(String.format(mAccountsActivity.getString(R.string.toast_exported_to), "ownCloud -> " + OC_DIR));
}
/**
* Checks that a specific toast message is displayed
* @param toastString String that should be displayed
*/
private void assertToastDisplayed(String toastString) {
onView(withText(toastString))
.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))
.check(matches(isDisplayed()));
}
/**
* Sleep the thread for a specified period
* @param millis Duration to sleep in milliseconds
*/
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}