package com.llamacorp.equate;
import android.test.mock.MockResources;
import junit.framework.TestCase;
import java.math.BigDecimal;
import java.math.MathContext;
public class CalculatorJUnitTest extends TestCase {
//THIS STUFF IS THE SAME AS CALC
//we want the display precision to be a bit less than calculated
//private MathContext mcOperate = new MathContext(intCalcPrecision);
private MathContext mcDisp = new MathContext(intDisplayPrecision);
//precision for all calculations
public static final int intDisplayPrecision = 15;
public static final int intCalcPrecision = intDisplayPrecision + 2;
/**
* Used to get a test calculator with a mocked resource file
*
* @return test calculator
*/
private Calculator getTestCalc() {
//TODO make this into something cleaner--use Mockito to completely fake the resource
MockResources mockResources = new MockResources() {
@Override
public String[] getStringArray(int id) {
if (id == R.array.unit_type_array_combined){
return new String[]{"key_currency|Currency|Currency", "key_temp|Temperature|Temp", "key_weight|Weight|Weight", "key_len|Length|Length", "key_area|Area|Area", "key_vol|Volume|Volume", "key_speed|Speed|Speed", "key_time|Time|Time", "key_fuel|FuelEconomy|FuelEco", "key_power|Power|Power", "key_energy|Energy|Energy", "key_force|Force|Force", "key_torque|Torque|Torque", "key_pressure|Pressure|Pressure", "key_digital|DigitalStorage|Digital"};
}
return null;
}
};
return Calculator.getTestCalculator(mockResources);
}
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testParseKeyPressed() {
Calculator calc = getTestCalc();
//try all ops before (should do nothing), try double decimal, try changing op, and extra equals
loadStringToCalc("=++/-+-*--1..+4.34b+-2-==", calc);
assertEquals("1.3", calc.toString());
//should clear the expression
loadStringToCalc("b", calc);
assertEquals("", calc.toString());
//test clear key
loadStringToCalc(".01=5c", calc);
assertEquals("", calc.toString());
//order of operations
loadStringToCalc("10+.5*4=", calc);
assertEquals("12", calc.toString());
//try adding to expression
loadStringToCalc("-4=", calc);
assertEquals("8", calc.toString());
//try typing a number now
loadStringToCalc("4", calc);
assertEquals("4", calc.toString());
//try adding just a . make sure it does't break
loadStringToCalc("1+.+2=", calc);
assertEquals("41.2", calc.toString());
//try adding just a .E and E. make sure it does't break
loadStringToCalc(".1E.*/0E.E.-3=", calc);
assertEquals("-2.9", calc.toString());
//try to break it some more
loadStringToCalc("4.E=1+.+E=.=", calc);
//this had problems before...
loadStringToCalc("0-5-5-5=", calc);
//this had problems before...
loadStringToCalc("1+E+1=", calc);
loadStringToCalc("b-1+4=", calc);
assertEquals("3", calc.toString());
loadStringToCalc("3-1*-1=", calc);
assertEquals("4", calc.toString());
loadStringToCalc("b-3*-1*-1=", calc);
assertEquals("-3", calc.toString());
loadStringToCalc("3-(2-4)*-5=", calc);
assertEquals("-7", calc.toString());
loadStringToCalc("2+-2*-3=", calc);
assertEquals("8", calc.toString());
loadStringToCalc("(30+3%", calc);
calc.setSelection(2, 2);
loadStringToCalc("=", calc);
assertEquals("30.03", calc.toString());
}
public void testNumberAccuracy() {
Calculator calc = getTestCalc();
loadStringToCalc("4", calc);
//make sure 2.2 is represented properly
loadStringToCalc("c2.2*3=", calc);
assertEquals("6.6", calc.toString());
//make sure 1/3= then *3 is 1
loadStringToCalc("1/3=*3=", calc);
assertEquals("1", calc.toString());
//make #E+# and #E-# are parsed correctly (save time with constructor)
calc = getTestCalc();
loadStringToCalc("10000000000*10000000000+10=", calc);
//be sure the exponent at the end is a 20 (other part of the string might be rounded differently
assertTrue(calc.toString().matches(".*E20$"));
}
public void testErrors() {
Calculator calc = getTestCalc();
//divide by zero error
loadStringToCalc("1/0=", calc);
assertEquals(Solver.strDivideZeroError, calc.toString());
//make sure num clears the error
loadStringToCalc("+1=", calc);
assertEquals("1", calc.toString());
//overflow
loadStringToCalc("9E9999999999=", calc);
}
public void testCleaning() {
Calculator calc = getTestCalc();
//make sure we're cleaning properly
loadStringToCalc("6.10000=", calc);
assertEquals("6.1", calc.toString());
loadStringToCalc("0.00800=", calc);
assertEquals("0.008", calc.toString());
loadStringToCalc("6.000=", calc);
assertEquals("6", calc.toString());
loadStringToCalc("800=", calc);
assertEquals("800", calc.toString());
loadStringToCalc(".080800=", calc);
assertEquals("0.0808", calc.toString());
}
public void testExponents() {
Calculator calc = getTestCalc();
//first try to break it
loadStringToCalc("E6EE*/bE++--*2=", calc);
assertEquals("0.06", calc.toString());
//try some random math
loadStringToCalc("30E2-2E10*=", calc);
assertEquals("-19999997000", calc.toString());
//tests to make sure that after a #.#E# expression, we can put a .
loadStringToCalc("3.2E2*.5=", calc);
assertEquals("160", calc.toString());
//test conversion of long numbers into and out of E
calc.parseKeyPressed("6");
for (int i = 0; i < Calculator.DISPLAY_PRECISION; i++)
calc.parseKeyPressed("0");
calc.parseKeyPressed("=");
//not sure if we'll be keeping the . after the 6, both will pass for now
assertTrue(calc.toString().matches("6\\.?E" + Calculator.DISPLAY_PRECISION));
//make sure the number one less than the precision is display as plain text
String tester = "6";
calc.parseKeyPressed(tester);
for (int i = 0; i < Calculator.DISPLAY_PRECISION - 1; i++) {
calc.parseKeyPressed("0");
tester = tester + "0";
}
calc.parseKeyPressed("=");
assertTrue(calc.toString().equals(tester));
//0E8 should reduce to 0 not "E8"
loadStringToCalc("0E8==", calc);
//catch the potentail problem of "532E+-"
loadStringToCalc("--5232E+-0=", calc);
assertEquals("-5232", calc.toString());
//catch problem where this would hang
loadStringToCalc("1E9999999+1=", calc);
assertEquals("Number Too Large", calc.toString());
//catch problem where this would hang
loadStringToCalc("1E9999999+1E999999=", calc);
assertEquals("Number Too Large", calc.toString());
loadStringToCalc("2E-2E-2=", calc);
assertEquals("-1.98", calc.toString());
}
public void testPower() {
Calculator calc = getTestCalc();
//test basic functionality
loadStringToCalc("4^3=", calc);
assertEquals("64", calc.toString());
//test sqrt
loadStringToCalc("64^.5=", calc);
assertEquals("8", calc.toString());
//test order of operations
loadStringToCalc("2*3^(1+3)=", calc);
assertEquals("162", calc.toString());
//test lots of decimals
loadStringToCalc("4.3^.3=", calc);
BigDecimal bd = new BigDecimal(1.5489611908722423119058589800223, mcDisp);
assertTrue(calc.toString().matches(bd.toString()));
//test large numbers
loadStringToCalc("9.1^500=", calc);
assertEquals("Number Too Large", calc.toString());
//test mixed exponents and powers
loadStringToCalc("2.1E2^1.1E2=", calc);
assertEquals("2.78049693531908E255", calc.toString());
loadStringToCalc("3-3^2=", calc);
assertEquals("-6", calc.toString());
loadStringToCalc("b-2*-4^2=", calc);
assertEquals("32", calc.toString());
loadStringToCalc("(-5)^2.0=", calc);
assertEquals("25", calc.toString());
loadStringToCalc("b-(6)^(.9+(1.1))=", calc);
assertEquals("-36", calc.toString());
loadStringToCalc("(-2+1)^2=", calc);
assertEquals("1", calc.toString());
loadStringToCalc("3*-((-2)+(1^0))^2=", calc);
assertEquals("-3", calc.toString());
loadStringToCalc("3*-2.E-3^-2.E-3=", calc);
assertEquals("-3.0375203397704", calc.toString());
loadStringToCalc("2+-1^2*-9^((.5)^1+.1+-.1^1)=", calc);
assertEquals("5", calc.toString());
//TODO do we really wanna fix this?
//loadStringToCalc("2^3^2=", calc);
//assertEquals("512", calc.toString());
}
public void testSelection() {
Calculator calc = getTestCalc();
loadStringToCalc("342+-23523*3532", calc);
assertEquals("342+-23523*3532", calc.toString());
//this is reversed intentionally, this can happen if user drags end before start
calc.setSelection(10, 5);
loadStringToCalc("15", calc);
assertEquals("342+-15*3532", calc.toString());
calc.setSelection(5, 7);
loadStringToCalc("-*1)", calc);
calc.setSelection(0, 0);
loadStringToCalc("(", calc);
assertEquals("(342*1)*3532", calc.toString());
calc.setSelection(7, 7);
loadStringToCalc(".7", calc);
assertEquals("(342*1)*.7*3532", calc.toString());
calc.setSelection(11, 11);
loadStringToCalc("^", calc);
assertEquals("(342*1)*.7^3532", calc.toString());
calc.setSelection(4, 11);
loadStringToCalc("(", calc);
assertEquals("(342*(3532", calc.toString());
loadStringToCalc("=", calc);
assertEquals("1207944", calc.toString());
calc.setSelection(4, 4);
loadStringToCalc("EE^*/-", calc);
assertEquals("1207E-944", calc.toString());
calc.setSelection(0, 9);
loadStringToCalc("-8^3=", calc);
assertEquals("-512", calc.toString());
//TODO add this test to android test since this problem is fixed, it's just
//fixed using an android specific method
calc.setSelection(2, 2);
calc.setSolved(false);
loadStringToCalc(".", calc);
assertEquals("-5.12", calc.toString());
}
public void testNegateOperator() {
Calculator calc = getTestCalc();
loadStringToCalc("-1+2+23+63n=", calc);
assertEquals("-39", calc.toString());
loadStringToCalc("5-7n=", calc);
assertEquals("12", calc.toString());
loadStringToCalc("n=", calc);
assertEquals("-12", calc.toString());
loadStringToCalc("n=", calc);
assertEquals("12", calc.toString());
loadStringToCalc("(45-67)n1=", calc);
assertEquals("-23", calc.toString());
loadStringToCalc("43*n=", calc);
assertEquals("43", calc.toString());
loadStringToCalc("43E-30n=", calc);
assertEquals("-4.3E-29", calc.toString());
loadStringToCalc("(-45n)=", calc);
assertEquals("45", calc.toString());
}
public void testInvertOperator() {
Calculator calc = getTestCalc();
loadStringToCalc("-4i=", calc);
assertEquals("-0.25", calc.toString());
loadStringToCalc("i", calc);
assertEquals("-4", calc.toString());
loadStringToCalc("15+100+32", calc);
calc.setSelection(3, 3);
loadStringToCalc("i=", calc);
assertEquals("47.01", calc.toString());
loadStringToCalc("15+100+32", calc);
calc.setSelection(6, 6);
loadStringToCalc("i=", calc);
assertEquals("47.01", calc.toString());
loadStringToCalc("15+100+32", calc);
calc.setSelection(4, 5);
loadStringToCalc("i=", calc);
assertEquals("47.01", calc.toString());
loadStringToCalc("ci16=", calc);
assertEquals("0.0625", calc.toString());
}
public void testPara() {
Calculator calc = getTestCalc();
loadStringToCalc("(2+3)*3+1*(3-1*(1))=", calc);
assertEquals("17", calc.toString());
loadStringToCalc("1+2*(2+3.3)=", calc);
assertEquals("11.6", calc.toString());
//test for adding multiplies between num and (
loadStringToCalc("6(.1+.4)=", calc);
assertEquals("3", calc.toString());
//test for adding multiplies between . and (
loadStringToCalc("2.(3)=", calc);
assertEquals("6", calc.toString());
//test for adding multiplies between E and (
loadStringToCalc("5E(3*2)=", calc);
assertEquals("5000000", calc.toString());
//test for adding multiplies between E and (
loadStringToCalc("5E(-3*2)=", calc);
assertEquals("0.000005", calc.toString());
//test for adding multiplies between E and (
loadStringToCalc("(1-7)(2+1)=", calc);
assertEquals("-18", calc.toString());
//test for adding multiplies number and )
loadStringToCalc("(2/4)10=", calc);
assertEquals("5", calc.toString());
// //test auto add opening para
// loadStringToCalc("1+2+3)=", calc);
// assertEquals("6", calc.toString());
//test auto add closing para; also test para followed by invalid op
loadStringToCalc("(*3=", calc);
assertEquals("3", calc.toString());
//test auto add closing para; also test para followed by invalid op
loadStringToCalc("(3(.2=", calc);
assertEquals("0.6", calc.toString());
//test auto adding multiplies for paras
loadStringToCalc("2((5)6)(3)7(3)(4).2+8.(0)=", calc);
assertEquals("3024", calc.toString());
}
public void testPercent() {
Calculator calc = getTestCalc();
loadStringToCalc("200+5%=", calc);
assertEquals("210", calc.toString());
loadStringToCalc("200-5%=", calc);
assertEquals("190", calc.toString());
loadStringToCalc("200+-5%=", calc);
assertEquals("190", calc.toString());
loadStringToCalc("5%=", calc);
assertEquals("0.05", calc.toString());
loadStringToCalc("b-5%=", calc);
assertEquals("-0.05", calc.toString());
loadStringToCalc("200*5%=", calc);
assertEquals("10", calc.toString());
loadStringToCalc("200/5%=", calc);
assertEquals("4000", calc.toString());
loadStringToCalc("200*-5%=", calc);
assertEquals("-10", calc.toString());
loadStringToCalc("200/-5%=", calc);
assertEquals("-4000", calc.toString());
loadStringToCalc("1+200+5%=", calc);
assertEquals("211.05", calc.toString());
loadStringToCalc("1+200+5%*/^+-4%=", calc);
assertEquals("202.608", calc.toString());
loadStringToCalc("5%*%6=", calc);
assertEquals("0.3", calc.toString());
//test 88 percent of 5
loadStringToCalc("88%5=", calc);
assertEquals("4.4", calc.toString());
//TODO, simplified broken version is 1+2%3
loadStringToCalc(".1+2.%3.%47.+200%.5=", calc);
assertEquals("1.1282", calc.toString());
}
// public void testUnits(){
// Calculator calc = getTestCalc();
//
// clickConvKey(Const.TEMP, Const.F, calc);
// loadStringToCalc("212", calc);
// clickConvKey(Const.TEMP, Const.C, calc);
// assertEquals("100", calc.toString());
// clickConvKey(Const.TEMP, Const.F, calc);
// assertEquals("212", calc.toString());
// clickConvKey(Const.TEMP, Const.K, calc);
// assertEquals("373.15", calc.toString());
// clickConvKey(Const.TEMP, Const.C, calc);
// assertEquals("100", calc.toString());
//
// //1E900 yard to mm to yard should not hang
// loadStringToCalc("c1E900", calc);
// clickConvKey(Const.LENGTH, Const.YARD, calc);
// clickConvKey(Const.LENGTH, Const.MM, calc);
// assertEquals("9.144E902", calc.toString());
//
// //501 in F to K, check 533.70556, back to F should be 501
// loadStringToCalc("c501", calc);
// clickConvKey(Const.TEMP, Const.F, calc);
// clickConvKey(Const.TEMP, Const.K, calc);
// clickConvKey(Const.TEMP, Const.F, calc);
// assertEquals("501", calc.toString());
//
// loadStringToCalc("c456+3+6", calc);
// calc.setSelection(5,5);
// loadStringToCalc("b", calc);
// clickConvKey(Const.TEMP, Const.F, calc);
// clickConvKey(Const.TEMP, Const.K, calc);
// assertEquals(Solver.strSyntaxError, calc.toString());
// }
private void clickConvKey(int unitTypePos, int convKeyPos, Calculator calc) {
calc.setCurrentUnitTypePos(unitTypePos);
boolean requestConvert = calc.getCurrUnitType().selectUnit(convKeyPos);
//this is normally performed in the convert key fragment, have to do this manually here
if (requestConvert){
calc.convertFromTo(calc.getCurrUnitType().getPrevUnit(), calc.getCurrUnitType().getCurrUnit());
}
}
/**
* Helper function to type in keys to calc and return result
*
* @param str is input key presses
*/
private void loadStringToCalc(String str, Calculator calc) {
for (int i = 0; i < str.length(); i++) {
calc.parseKeyPressed(String.valueOf(str.charAt(i)));
//be sure to update where keys are going
// calc.setSelection(calc.toString().length(), calc.toString().length());
}
}
private Calculator bruteCalc;
public String[] allKeyArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-", "*", "/", "b", "E", "="};
private String[] someKeyArray = {"0", "9", ".", "+", "-", "*", "/", "b", "E", "="};
//these configure the testing
private String[] testKeyArray = someKeyArray;
//run the brute force test
public void testBrute() {
bruteCalc = getTestCalc();
int numRuns = 4;
bruteForceTest(numRuns, "");
}
//this will cycle through all combinations of keys
private void bruteForceTest(int numTimes, String startSting) {
if (numTimes == 0)
return;
numTimes--;
for (int i = 0; i < testKeyArray.length; i++) {
if (numTimes == 0){
for (int s = 0; s < startSting.length(); s++) {
String str = String.valueOf(startSting.charAt(s));
//System.out.print(str);
//System.out.println("Expression= " + bruteCalc.toString());
bruteCalc.parseKeyPressed(str);
}
try {
bruteCalc.parseKeyPressed("=");
} catch (Exception e) {
//System.out.println("Error input: \"");
//System.out.print(startSting);
//System.out.println("=" + "\"");
e.printStackTrace();
throw new IllegalStateException();
}
//boolean clearAfterEach = true;
//if(clearAfterEach)
bruteCalc.parseKeyPressed("c");
//System.out.println("=");
break;
} else
bruteForceTest(numTimes, startSting + testKeyArray[i]);
}
}
}