/* * Copyright (c) 2015 Oleksandr Tyshkovets <olexandr.tyshkovets@gmail.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.support.test.espresso.ViewAction; import android.support.test.espresso.action.CoordinatesProvider; import android.support.test.espresso.action.GeneralClickAction; import android.support.test.espresso.action.Press; import android.support.test.espresso.action.Tap; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.view.View; import org.gnucash.android.R; import org.gnucash.android.app.GnuCashApplication; 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.db.adapter.TransactionsDbAdapter; import org.gnucash.android.importer.GncXmlImporter; import org.gnucash.android.model.AccountType; 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.model.TransactionType; import org.gnucash.android.test.ui.util.DisableAnimationsRule; import org.gnucash.android.ui.report.BaseReportFragment; import org.gnucash.android.ui.report.ReportsActivity; import org.gnucash.android.ui.report.piechart.PieChartFragment; import org.gnucash.android.ui.settings.PreferenceActivity; import org.gnucash.android.util.BookUtils; import org.joda.time.LocalDateTime; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.math.BigDecimal; import java.util.Locale; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.assertj.core.api.Assertions.assertThat; @RunWith(AndroidJUnit4.class) public class PieChartReportTest { public static final String TAG = PieChartReportTest.class.getName(); private static final String TRANSACTION_NAME = "Pizza"; private static final double TRANSACTION_AMOUNT = 9.99; private static final String TRANSACTION2_NAME = "1984"; private static final double TRANSACTION2_AMOUNT = 12.49; private static final String TRANSACTION3_NAME = "Nice gift"; private static final double TRANSACTION3_AMOUNT = 2000.00; private static final String CASH_IN_WALLET_ASSET_ACCOUNT_UID = "b687a487849470c25e0ff5aaad6a522b"; private static final String DINING_EXPENSE_ACCOUNT_UID = "62922c5ccb31d6198259739d27d858fe"; private static final String DINING_EXPENSE_ACCOUNT_NAME = "Dining"; private static final String BOOKS_EXPENSE_ACCOUNT_UID = "a8b342435aceac7c3cac214f9385dd72"; private static final String BOOKS_EXPENSE_ACCOUNT_NAME = "Books"; private static final String GIFTS_RECEIVED_INCOME_ACCOUNT_UID = "b01950c0df0890b6543209d51c8e0b0f"; private static final String GIFTS_RECEIVED_INCOME_ACCOUNT_NAME = "Gifts Received"; public static Commodity CURRENCY; private static AccountsDbAdapter mAccountsDbAdapter; private static TransactionsDbAdapter mTransactionsDbAdapter; private ReportsActivity mReportsActivity; @Rule public ActivityTestRule<ReportsActivity> mActivityRule = new ActivityTestRule<>(ReportsActivity.class); @ClassRule public static DisableAnimationsRule disableAnimationsRule = new DisableAnimationsRule(); private static String testBookUID; private static String oldActiveBookUID; public PieChartReportTest() { //nothing to se here, move along CURRENCY = new Commodity("US Dollars", "USD", 100); } @BeforeClass public static void prepareTestCase() throws Exception { Context context = GnuCashApplication.getAppContext(); oldActiveBookUID = BooksDbAdapter.getInstance().getActiveBookUID(); testBookUID = GncXmlImporter.parse(context.getResources().openRawResource(R.raw.default_accounts)); BookUtils.loadBook(testBookUID); mTransactionsDbAdapter = TransactionsDbAdapter.getInstance(); mAccountsDbAdapter = AccountsDbAdapter.getInstance(); CURRENCY = CommoditiesDbAdapter.getInstance().getCommodity("USD"); PreferenceActivity.getActiveBookSharedPreferences().edit() .putString(context.getString(R.string.key_default_currency), CURRENCY.getCurrencyCode()) .commit(); } @Before public void setUp() throws Exception { mTransactionsDbAdapter.deleteAllRecords(); mReportsActivity = mActivityRule.getActivity(); assertThat(mAccountsDbAdapter.getRecordsCount()).isGreaterThan(20); //lots of accounts in the default onView(withId(R.id.btn_pie_chart)).perform(click()); } /** * Add a transaction for the current month in order to test the report view * @throws Exception */ private void addTransactionForCurrentMonth() throws Exception { Transaction transaction = new Transaction(TRANSACTION_NAME); transaction.setTime(System.currentTimeMillis()); Split split = new Split(new Money(BigDecimal.valueOf(TRANSACTION_AMOUNT), CURRENCY), DINING_EXPENSE_ACCOUNT_UID); split.setType(TransactionType.DEBIT); transaction.addSplit(split); transaction.addSplit(split.createPair(CASH_IN_WALLET_ASSET_ACCOUNT_UID)); mTransactionsDbAdapter.addRecord(transaction, DatabaseAdapter.UpdateMethod.insert); } /** * Add a transactions for the previous month for testing pie chart * @param minusMonths Number of months prior */ private void addTransactionForPreviousMonth(int minusMonths) { Transaction transaction = new Transaction(TRANSACTION2_NAME); transaction.setTime(new LocalDateTime().minusMonths(minusMonths).toDate().getTime()); Split split = new Split(new Money(BigDecimal.valueOf(TRANSACTION2_AMOUNT), CURRENCY), BOOKS_EXPENSE_ACCOUNT_UID); split.setType(TransactionType.DEBIT); transaction.addSplit(split); transaction.addSplit(split.createPair(CASH_IN_WALLET_ASSET_ACCOUNT_UID)); mTransactionsDbAdapter.addRecord(transaction, DatabaseAdapter.UpdateMethod.insert); } @Test public void testNoData() { onView(withId(R.id.pie_chart)).perform(click()); onView(withId(R.id.selected_chart_slice)).check(matches(withText(R.string.label_select_pie_slice_to_see_details))); } @Test public void testSelectingValue() throws Exception { addTransactionForCurrentMonth(); addTransactionForPreviousMonth(1); refreshReport(); onView(withId(R.id.pie_chart)).perform(clickXY(Position.BEGIN, Position.MIDDLE)); float percent = (float) (TRANSACTION_AMOUNT / (TRANSACTION_AMOUNT + TRANSACTION2_AMOUNT) * 100); String selectedText = String.format(Locale.US, BaseReportFragment.SELECTED_VALUE_PATTERN, DINING_EXPENSE_ACCOUNT_NAME, TRANSACTION_AMOUNT, percent); onView(withId(R.id.selected_chart_slice)).check(matches(withText(selectedText))); } @Test public void testSpinner() throws Exception { Split split = new Split(new Money(BigDecimal.valueOf(TRANSACTION3_AMOUNT), CURRENCY), GIFTS_RECEIVED_INCOME_ACCOUNT_UID); Transaction transaction = new Transaction(TRANSACTION3_NAME); transaction.addSplit(split); transaction.addSplit(split.createPair(CASH_IN_WALLET_ASSET_ACCOUNT_UID)); mTransactionsDbAdapter.addRecord(transaction, DatabaseAdapter.UpdateMethod.insert); refreshReport(); Thread.sleep(1000); onView(withId(R.id.report_account_type_spinner)).perform(click()); onView(withText(AccountType.INCOME.name())).perform(click()); onView(withId(R.id.pie_chart)).perform(clickXY(Position.BEGIN, Position.MIDDLE)); String selectedText = String.format(PieChartFragment.SELECTED_VALUE_PATTERN, GIFTS_RECEIVED_INCOME_ACCOUNT_NAME, TRANSACTION3_AMOUNT, 100f); onView(withId(R.id.selected_chart_slice)).check(matches(withText(selectedText))); onView(withId(R.id.report_account_type_spinner)).perform(click()); onView(withText(AccountType.EXPENSE.name())).perform(click()); onView(withId(R.id.pie_chart)).perform(click()); onView(withId(R.id.selected_chart_slice)).check(matches(withText(R.string.label_select_pie_slice_to_see_details))); } public static ViewAction clickXY(final Position horizontal, final Position vertical){ return new GeneralClickAction( Tap.SINGLE, new CoordinatesProvider() { @Override public float[] calculateCoordinates(View view) { int[] xy = new int[2]; view.getLocationOnScreen(xy); float x = horizontal.getPosition(xy[0], view.getWidth()); float y = vertical.getPosition(xy[1], view.getHeight()); return new float[]{x, y}; } }, Press.FINGER); } private enum Position { BEGIN { @Override public float getPosition(int viewPos, int viewLength) { return viewPos + (viewLength * 0.15f); } }, MIDDLE { @Override public float getPosition(int viewPos, int viewLength) { return viewPos + (viewLength * 0.5f); } }, END { @Override public float getPosition(int viewPos, int viewLength) { return viewPos + (viewLength * 0.85f); } }; abstract float getPosition(int widgetPos, int widgetLength); } /** * Refresh reports */ private void refreshReport(){ try { mActivityRule.runOnUiThread(new Runnable() { @Override public void run() { mReportsActivity.refresh(); } }); } catch (Throwable t){ System.err.println("Faile to refresh reports"); } } @After public void tearDown() throws Exception { mReportsActivity.finish(); } @AfterClass public static void cleanup(){ BooksDbAdapter booksDbAdapter = BooksDbAdapter.getInstance(); booksDbAdapter.setActive(oldActiveBookUID); booksDbAdapter.deleteRecord(testBookUID); } }