summaryrefslogtreecommitdiffstats
path: root/tests/src/com
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2015-03-11 18:43:24 -0700
committerHans Boehm <hboehm@google.com>2015-04-07 18:05:42 -0700
commit75ca21c698808b61238a3aff3e0a3dfd5ba95d0e (patch)
tree2d53dac90347479e33fe61338a81083c96585644 /tests/src/com
parent682ff5e8ad465d74b289590e5c88e0cf129ca90b (diff)
downloadandroid_packages_apps_ExactCalculator-75ca21c698808b61238a3aff3e0a3dfd5ba95d0e.tar.gz
android_packages_apps_ExactCalculator-75ca21c698808b61238a3aff3e0a3dfd5ba95d0e.tar.bz2
android_packages_apps_ExactCalculator-75ca21c698808b61238a3aff3e0a3dfd5ba95d0e.zip
Add tests, fix BoundedRational bugs
Add back some basic test infrastructure from the KitKat calculator, updated to make it work with the current code base and asynchronous expression evaluation. Add BoundedRational tests, designed to check that we get all the corner cases, particularly for degree-based trig functions, right. Fix a couple of BoundedRational typos that caused these tests to fail. Change-Id: I81d8f3d9bde6aa6c20f9958eabd62979babeff5b
Diffstat (limited to 'tests/src/com')
-rw-r--r--tests/src/com/android/calculator2/BRTest.java195
-rw-r--r--tests/src/com/android/calculator2/CalculatorHitSomeButtons.java164
2 files changed, 359 insertions, 0 deletions
diff --git a/tests/src/com/android/calculator2/BRTest.java b/tests/src/com/android/calculator2/BRTest.java
new file mode 100644
index 0000000..bd7070a
--- /dev/null
+++ b/tests/src/com/android/calculator2/BRTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+// A test for BoundedRationals package.
+
+package com.android.calculator2;
+
+import com.hp.creals.CR;
+import com.hp.creals.UnaryCRFunction;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import java.math.BigInteger;
+
+public class BRTest extends TestCase {
+ private static void check(boolean x, String s) {
+ if (!x) throw new AssertionFailedError(s);
+ }
+ final static int TEST_PREC = -100; // 100 bits to the right of
+ // binary point.
+ private static void checkEq(BoundedRational x, CR y, String s) {
+ check(x.CRValue().compareTo(y, TEST_PREC) == 0, s);
+ }
+ private static void checkWeakEq(BoundedRational x, CR y, String s) {
+ if (x != null) checkEq(x, y, s);
+ }
+
+ private final static UnaryCRFunction ASIN = UnaryCRFunction.asinFunction;
+ private final static UnaryCRFunction ACOS = UnaryCRFunction.acosFunction;
+ private final static UnaryCRFunction ATAN = UnaryCRFunction.atanFunction;
+ private final static UnaryCRFunction TAN = UnaryCRFunction.tanFunction;
+ private final static BoundedRational BR_0 = new BoundedRational(0);
+ private final static BoundedRational BR_M1 = new BoundedRational(-1);
+ private final static BoundedRational BR_2 = new BoundedRational(2);
+ private final static BoundedRational BR_M2 = new BoundedRational(-2);
+ private final static BoundedRational BR_15 = new BoundedRational(15);
+ private final static BoundedRational BR_390 = new BoundedRational(390);
+ private final static BoundedRational BR_M390 = new BoundedRational(-390);
+ private final static CR CR_1 = CR.valueOf(1);
+
+ private final static CR RADIANS_PER_DEGREE = CR.PI.divide(CR.valueOf(180));
+ private final static CR DEGREES_PER_RADIAN = CR.valueOf(180).divide(CR.PI);
+ private final static CR LN10 = CR.valueOf(10).ln();
+
+ private static CR toRadians(CR x) {
+ return x.multiply(RADIANS_PER_DEGREE);
+ }
+
+ private static CR fromRadians(CR x) {
+ return x.multiply(DEGREES_PER_RADIAN);
+ }
+
+ // We assume that x is simple enough that we don't overflow bounds.
+ private static void checkBR(BoundedRational x) {
+ check(x != null, "test data should not be null");
+ CR xAsCR = x.CRValue();
+ checkEq(BoundedRational.add(x, BoundedRational.ONE), xAsCR.add(CR_1),
+ "add 1:" + x);
+ checkEq(BoundedRational.subtract(x, BoundedRational.MINUS_THIRTY),
+ xAsCR.subtract(CR.valueOf(-30)), "sub -30:" + x);
+ checkEq(BoundedRational.multiply(x, BR_15),
+ xAsCR.multiply(CR.valueOf(15)), "multiply 15:" + x);
+ checkEq(BoundedRational.divide(x, BR_15),
+ xAsCR.divide(CR.valueOf(15)), "divide 15:" + x);
+ checkWeakEq(BoundedRational.sin(x), xAsCR.sin(), "sin:" + x);
+ checkWeakEq(BoundedRational.cos(x), xAsCR.cos(), "cos:" + x);
+ checkWeakEq(BoundedRational.tan(x), TAN.execute(xAsCR), "tan:" + x);
+ checkWeakEq(BoundedRational.degreeSin(x), toRadians(xAsCR).sin(),
+ "degree sin:" + x);
+ checkWeakEq(BoundedRational.degreeCos(x), toRadians(xAsCR).cos(),
+ "degree cos:" + x);
+ BigInteger big_x = BoundedRational.asBigInteger(x);
+ long long_x = (big_x == null? 0 : big_x.longValue());
+ try {
+ checkWeakEq(BoundedRational.degreeTan(x),
+ TAN.execute(toRadians(xAsCR)), "degree tan:" + x);
+ check((long_x - 90) % 180 != 0, "missed undefined tan: " + x);
+ } catch (ArithmeticException ignored) {
+ check((long_x - 90) % 180 == 0, "exception on defined tan: " + x);
+ }
+ if (x.compareTo(BoundedRational.ONE) <= 0
+ && x.compareTo(BoundedRational.MINUS_ONE) >= 0) {
+ checkWeakEq(BoundedRational.asin(x), ASIN.execute(xAsCR),
+ "asin:" + x);
+ checkWeakEq(BoundedRational.acos(x), ACOS.execute(xAsCR),
+ "acos:" + x);
+ checkWeakEq(BoundedRational.degreeAsin(x),
+ fromRadians(ASIN.execute(xAsCR)), "degree asin:" + x);
+ checkWeakEq(BoundedRational.degreeAcos(x),
+ fromRadians(ACOS.execute(xAsCR)), "degree acos:" + x);
+ }
+ checkWeakEq(BoundedRational.atan(x), fromRadians(ATAN.execute(xAsCR)),
+ "atan:" + x);
+ checkWeakEq(BoundedRational.degreeAtan(x),
+ fromRadians(ATAN.execute(xAsCR)), "degree atan:" + x);
+ if (x.signum() > 0) {
+ checkWeakEq(BoundedRational.ln(x), xAsCR.ln(), "ln:" + x);
+ checkWeakEq(BoundedRational.log(x), xAsCR.ln().divide(LN10),
+ "log:" + x);
+ checkWeakEq(BoundedRational.sqrt(x), xAsCR.sqrt(), "sqrt:" + x);
+ checkEq(BoundedRational.pow(x, BR_15),
+ xAsCR.ln().multiply(CR.valueOf(15)).exp(),
+ "pow(x,15):" + x);
+ }
+ }
+
+ public void testBR() {
+ checkEq(BR_0, CR.valueOf(0), "0");
+ checkEq(BR_390, CR.valueOf(390), "390");
+ checkEq(BR_15, CR.valueOf(15), "15");
+ checkEq(BR_M390, CR.valueOf(-390), "-390");
+ checkEq(BR_M1, CR.valueOf(-1), "-1");
+ checkEq(BR_2, CR.valueOf(2), "2");
+ checkEq(BR_M2, CR.valueOf(-2), "-2");
+ check(BR_0.signum() == 0, "signum(0)");
+ check(BR_M1.signum() == -1, "signum(-1)");
+ check(BR_2.signum() == 1, "signum(2)");
+ // We check values that include all interesting degree values.
+ BoundedRational r = BR_M390;
+ while (!r.equals(BR_390)) {
+ check(r != null, "loop counter overflowed!");
+ checkBR(r);
+ r = BoundedRational.add(r, BR_15);
+ }
+ checkBR(BoundedRational.HALF);
+ checkBR(BoundedRational.MINUS_HALF);
+ checkBR(BoundedRational.ONE);
+ checkBR(BoundedRational.MINUS_ONE);
+ checkBR(new BoundedRational(1000));
+ checkBR(new BoundedRational(100));
+ checkBR(new BoundedRational(4,9));
+ check(BoundedRational.sqrt(new BoundedRational(4,9)) != null,
+ "sqrt(4/9) is null");
+ checkBR(BoundedRational.negate(new BoundedRational(4,9)));
+ checkBR(new BoundedRational(5,9));
+ checkBR(new BoundedRational(5,10));
+ checkBR(new BoundedRational(5,10));
+ checkBR(new BoundedRational(4,13));
+ checkBR(new BoundedRational(36));
+ checkBR(BoundedRational.negate(new BoundedRational(36)));
+ check(BoundedRational.pow(null, BR_15) == null, "pow(null, 15)");
+ }
+
+ public void testBRexceptions() {
+ try {
+ BoundedRational.ln(BR_M1);
+ check(false, "ln(-1)");
+ } catch (ArithmeticException ignored) {}
+ try {
+ BoundedRational.log(BR_M2);
+ check(false, "log(-2)");
+ } catch (ArithmeticException ignored) {}
+ try {
+ BoundedRational.sqrt(BR_M1);
+ check(false, "sqrt(-1)");
+ } catch (ArithmeticException ignored) {}
+ try {
+ BoundedRational.asin(BR_M2);
+ check(false, "asin(-2)");
+ } catch (ArithmeticException ignored) {}
+ try {
+ BoundedRational.degreeAcos(BR_2);
+ check(false, "degree acos(2)");
+ } catch (ArithmeticException ignored) {}
+ }
+
+ public void testBROverflow() {
+ BoundedRational sum = new BoundedRational(0);
+ long i;
+ for (i = 1; i < 1000; ++i) {
+ sum = BoundedRational.add(sum,
+ BoundedRational.inverse(new BoundedRational(i)));
+ if (sum == null) break;
+ }
+ // Experimentally, this overflows at 139, which seems
+ // plausible based on the Wolfram Alpha result.
+ // This test is robust against minor changes in MAX_SIZE.
+ check(i > 100, "Harmonic series overflowed at " + i);
+ check(i < 1000, "Harmonic series didn't overflow");
+ }
+}
diff --git a/tests/src/com/android/calculator2/CalculatorHitSomeButtons.java b/tests/src/com/android/calculator2/CalculatorHitSomeButtons.java
new file mode 100644
index 0000000..d26a5cb
--- /dev/null
+++ b/tests/src/com/android/calculator2/CalculatorHitSomeButtons.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * 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 com.android.calculator2;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.graphics.Rect;
+import android.test.TouchUtils;
+
+import com.android.calculator2.Calculator;
+import com.android.calculator2.R;
+import com.android.calculator2.CalculatorResult;
+
+/**
+ * Instrumentation tests for poking some buttons
+ *
+ */
+
+public class CalculatorHitSomeButtons extends ActivityInstrumentationTestCase <Calculator>{
+ public boolean setup = false;
+ private static final String TAG = "CalculatorTests";
+ Calculator mActivity = null;
+ Instrumentation mInst = null;
+
+ public CalculatorHitSomeButtons() {
+ super("com.android.calculator2", Calculator.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInst = getInstrumentation();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+/*
+ @LargeTest
+ public void testPressSomeKeys() {
+ Log.v(TAG, "Pressing some keys!");
+
+ // Make sure that we clear the output
+ press(KeyEvent.KEYCODE_ENTER);
+ press(KeyEvent.KEYCODE_CLEAR);
+
+ // 3 + 4 * 5 => 23
+ press(KeyEvent.KEYCODE_3);
+ press(KeyEvent.KEYCODE_PLUS);
+ press(KeyEvent.KEYCODE_4);
+ press(KeyEvent.KEYCODE_9 | KeyEvent.META_SHIFT_ON);
+ press(KeyEvent.KEYCODE_5);
+ press(KeyEvent.KEYCODE_ENTER);
+
+ checkDisplay("23");
+ }
+*/
+
+ @LargeTest
+ public void testTapSomeButtons() {
+ // TODO: This probably makes way too many hardcoded assumptions about locale.
+ // The calculator will need a routine to internationalize the output.
+ // We should use that here, too.
+ Log.v(TAG, "Tapping some buttons!");
+
+ // Make sure that we clear the output
+ tap(R.id.eq);
+ tap(R.id.del);
+
+ // 567 / 3 => 189
+ tap(R.id.digit_5);
+ tap(R.id.digit_6);
+ tap(R.id.digit_7);
+ tap(R.id.op_div);
+ tap(R.id.digit_3);
+ tap(R.id.eq);
+
+ checkDisplay("189");
+
+ // make sure we can continue calculations also
+ // 189 - 789 => -600
+ tap(R.id.op_sub);
+ tap(R.id.digit_7);
+ tap(R.id.digit_8);
+ tap(R.id.digit_9);
+ tap(R.id.eq);
+
+ // Careful: the first digit in the expected value is \u2212, not "-" (a hyphen)
+ checkDisplay(mActivity.getString(R.string.op_sub) + "600");
+ }
+
+ // helper functions
+ private void press(int keycode) {
+ mInst.sendKeyDownUpSync(keycode);
+ }
+
+ private boolean tap(int id) {
+ View view = mActivity.findViewById(id);
+ if(view != null) {
+ TouchUtils.clickView(this, view);
+ return true;
+ }
+ return false;
+ }
+
+ private void checkDisplay(final String s) {
+ mInst.waitForIdle(new Runnable () {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(20); // Wait for background computation
+ } catch(InterruptedException ignored) {
+ fail("Unexpected interrupt");
+ }
+ mInst.waitForIdle(new Runnable () {
+ @Override
+ public void run() {
+ assertEquals(displayVal(), s);
+ }
+ });
+ }
+ });
+ }
+
+ private String displayVal() {
+ CalculatorResult display = (CalculatorResult) mActivity.findViewById(R.id.result);
+ assertNotNull(display);
+
+ EditText box = (EditText) display;
+ assertNotNull(box);
+
+ return box.getText().toString();
+ }
+}
+