package org.geogebra.cas;
import static org.geogebra.test.util.IsEqualStringIgnoreWhitespaces.equalToIgnoreWhitespaces;
import static org.junit.Assert.assertThat;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import org.geogebra.cas.logging.CASTestLogger;
import org.geogebra.common.kernel.GeoGebraCasInterface;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.Command;
import org.geogebra.common.kernel.arithmetic.ExpressionValue;
import org.geogebra.common.kernel.arithmetic.MyVecNDNode;
import org.geogebra.common.kernel.arithmetic.Traversing;
import org.geogebra.common.kernel.arithmetic.Traversing.CommandCollector;
import org.geogebra.common.kernel.arithmetic.Variable;
import org.geogebra.common.kernel.geos.GeoCasCell;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.move.ggtapi.models.json.JSONArray;
import org.geogebra.common.move.ggtapi.models.json.JSONObject;
import org.geogebra.common.plugin.Operation;
import org.geogebra.common.util.Charsets;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.main.AppDNoGui;
import org.geogebra.desktop.main.LocalizationD;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class CAStestJSON {
static GeoGebraCasInterface cas;
static Kernel kernel;
static AppDNoGui app;
static CASTestLogger logger;
static class CasTest {
public CasTest(String input, String output, String rounding) {
this.input = input;
this.output = output;
this.rounding = rounding;
}
protected String input;
protected String output;
protected String rounding;
}
static HashMap<String, ArrayList<CasTest>> testcases = new HashMap<String, ArrayList<CasTest>>();
private static String readFileAsString(String filePath) throws IOException {
StringBuffer fileData = new StringBuffer();
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(filePath),
Charsets.UTF_8));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
String[] parts = fileData.toString().split("\n");
StringBuffer noComments = new StringBuffer();
for (int i = 0; i < parts.length; i++) {
if (!parts[i].trim().startsWith("//")) {
noComments.append(parts[i]);
}
}
return noComments.toString();
}
@BeforeClass
public static void setupCas () {
app = new AppDNoGui(new LocalizationD(3), false);
// Set language to something else than English to test automatic translation.
app.setLanguage(Locale.GERMANY);
// app.fillCasCommandDict();
kernel = app.getKernel();
cas = kernel.getGeoGebraCAS();
logger = new CASTestLogger();
// Setting the general timeout to 13 seconds. Feel free to change this.
kernel.getApplication().getSettings().getCasSettings().setTimeoutMilliseconds(13000);
try {
Log.debug("CAS: loading testcases");
String json = readFileAsString("../web/war/__giac.js");
Log.debug("CAS: parsing testcases");
Log.debug("CAS: testcases parsed");
JSONArray testsJSON = new JSONArray(
json.substring("var __giac = ".length()));
Assert.assertNotSame(0, testsJSON.length());
int i = 1;
while (i < testsJSON.length()) {
Object testVal = testsJSON.opt(i);
i++;
if (!(testVal instanceof JSONObject)) {
System.err.println("Invalid JSON:" + testVal);
continue;
}
JSONObject test = (JSONObject) testVal;
String cat = "general";
if(test.has("cat")){
cat = test.getString("cat");
}
if(!testcases.containsKey(cat)){
/*System.out.println("@Test");
System.out.println("public void test"+cat+"(){");
System.out.println(" testCat(\""+cat+"\");");
System.out.println("}\n");*/
testcases.put(cat, new ArrayList<CasTest>());
}
if (test.has("round")) {
testcases.get(cat).add(new CasTest(test.getString("cmd"),
test.getString("round"), null));
} else {
testcases.get(cat).add(new CasTest(test.getString("cmd"),
test.getString("result"),
test.optString("rounding")));
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
private static void ta(boolean tkiontki, String input,
String[] expectedResult, String... validResults) {
String result;
try {
GeoCasCell f = new GeoCasCell(kernel.getConstruction());
kernel.getConstruction().addToConstructionList(f, false);
f.setInput(input);
if (tkiontki) {
f.setEvalCommand("KeepInput");
}
f.computeOutput();
boolean includesNumericCommand = false;
HashSet<Command> commands = new HashSet<Command>();
if(f.getInputVE() == null){
Assert.assertEquals("Input should be parsed", "GEOGEBRAERROR",
expectedResult[0]);
return;
}
f.getInputVE().traverse(CommandCollector.getCollector(commands));
if (!commands.isEmpty()) {
for (Command cmd : commands) {
String cmdName = cmd.getName();
// Numeric used
includesNumericCommand = includesNumericCommand || ("Numeric".equals(cmdName) && cmd.getArgumentNumber() > 1);
}
}
if (f.getOutputValidExpression() == null) {
result = f.getOutput(StringTemplate.testTemplate);
} else if (f.getOutputValidExpression()
.unwrap() instanceof GeoElement) {
result = f.getOutputValidExpression().toValueString(
StringTemplate.testTemplateJSON);
} else {
result = f
.getOutputValidExpression()
.traverse(getGGBVectAdder())
.toString(
includesNumericCommand
? StringTemplate.testNumeric
: StringTemplate.testTemplateJSON);
}
} catch (Throwable t) {
String sts = "";
StackTraceElement[] st = t.getStackTrace();
for (int i = 0; i < 10 && i < st.length; i++) {
StackTraceElement stElement = st[i];
sts += stElement.getClassName() + ":" + stElement.getMethodName() + stElement.getLineNumber() + "\n";
}
result = t.getClass().getName() + ":" + t.getMessage() + sts;
}
for (int i = 0; i < expectedResult.length; i++) {
if ("RANDOM".equals(expectedResult[i])) {
return;
}
try {
result = result.replaceAll("c_[0-9]", "c_0")
.replaceAll("k_[0-9]", "k_0")
.replaceAll("c_\\{[0-9]+\\}", "c_0")
.replaceAll("k_\\{[0-9]+\\}", "k_0")
.replace("arccos", "acos").replace("arctan", "atan")
.replace("Wenn[", "If[")
.replace("arcsin", "asin")
.replace("NteWurzel", "nroot");
assertThat(
result,
equalToIgnoreWhitespaces(logger, input,
expectedResult[i].replaceAll("c_[0-9]+", "c_0")
.replaceAll("n_[0-9]+", "k_0"),
validResults));
return;
} catch (Throwable t) {
// if (!(t instanceof AssertionError)) {
t.printStackTrace();
// }
if (i == expectedResult.length - 1) {
Assert.assertEquals(
(expectedResult[0] == null ? "null"
: expectedResult[0].replaceAll("c_[0-9]+",
"c_0"))
+ " input:"
+ input,
result);
}
}
}
}
private static Traversing getGGBVectAdder() {
return new Traversing() {
@Override
public ExpressionValue process(ExpressionValue ev) {
if (ev.unwrap() instanceof MyVecNDNode
&& ((MyVecNDNode) ev.unwrap()).isCASVector()) {
return new Variable(kernel, "ggbvect").wrap().apply(
Operation.FUNCTION, ev);
}
return ev;
}
};
}
private static void t (String input, String expectedResult) {
String[] validResults = expectedResult.split("\\|OR\\|");
ta(false, input, validResults, validResults);
}
private static void testCat(String name){
kernel.clearConstruction(true);
if (testcases.get(name) == null) {
return;
}
ArrayList<CasTest> cases = testcases.get(name);
Assert.assertNotEquals(0, cases.size());
testcases.remove(name);
for (CasTest cmd : cases) {
if (!StringUtil.empty(cmd.rounding)) {
app.setRounding(cmd.rounding);
} else {
app.setRounding("2");
}
Log.debug(cmd.input);
t(cmd.input, cmd.output);
}
}
@AfterClass
public static void checkAllCatsTested() {
StringBuilder sb = new StringBuilder("");
for (String cat : testcases.keySet()) {
sb.append(cat);
sb.append(',');
}
Assert.assertEquals(sb.toString(), "SLOW,");
}
@Test
public void testgeneral(){
testCat("general");
}
@Test
public void testIntegral(){
testCat("Integral");
}
@Test
public void testFactor(){
testCat("Factor");
}
@Test
public void testCoefficients(){
testCat("Coefficients");
}
@Test
public void testAppend(){
testCat("Append");
}
@Test
public void testBinomialCoefficient(){
testCat("BinomialCoefficient");
}
@Test
public void testBinomialDist(){
testCat("BinomialDist");
}
@Test
public void testCauchy(){
testCat("Cauchy");
}
@Test
public void testCFactor(){
testCat("CFactor");
}
@Test
public void testNumeric(){
testCat("Numeric");
}
@Test
public void testCompleteSquare(){
testCat("CompleteSquare");
}
@Test
public void testCommonDenominator(){
testCat("CommonDenominator");
}
@Test
public void testCovariance(){
testCat("Covariance");
}
@Test
public void testCross(){
testCat("Cross");
}
@Test
public void testComplexRoot(){
testCat("ComplexRoot");
}
@Test
public void testCSolutions(){
testCat("CSolutions");
}
@Test
public void testCSolve(){
testCat("CSolve");
}
@Test
public void testDegree(){
testCat("Degree");
}
@Test
public void testDenominator(){
testCat("Denominator");
}
@Test
public void testDerivative(){
testCat("Derivative");
}
@Test
public void testDeterminant(){
testCat("Determinant");
}
@Test
public void testDimension(){
testCat("Dimension");
}
@Test
public void testDiv(){
testCat("Div");
}
@Test
public void testDivision(){
testCat("Division");
}
@Test
public void testDivisors(){
testCat("Divisors");
}
@Test
public void testDivisorsList(){
testCat("DivisorsList");
}
@Test
public void testDivisorsSum(){
testCat("DivisorsSum");
}
@Test
public void testDot(){
testCat("Dot");
}
@Test
public void testElement(){
testCat("Element");
}
@Test
public void testExpand(){
testCat("Expand");
}
@Test
public void testExponential(){
testCat("Exponential");
}
@Test
public void testFactors(){
testCat("Factors");
}
@Test
public void testFDistribution(){
testCat("FDistribution");
}
@Test
public void testFlatten(){
testCat("Flatten");
}
@Test
public void testFirst(){
testCat("First");
}
@Test
public void testFitExp(){
testCat("FitExp");
}
@Test
public void testFitLog(){
testCat("FitLog");
}
@Test
public void testFitPoly(){
testCat("FitPoly");
}
@Test
public void testFitPow(){
testCat("FitPow");
}
@Test
public void testGamma(){
testCat("Gamma");
}
@Test
public void testGCD(){
testCat("GCD");
}
@Test
public void testHyperGeometric(){
testCat("HyperGeometric");
}
@Test
public void testIdentity(){
testCat("Identity");
}
@Test
public void testIf(){
testCat("If");
}
@Test
public void testImplicitDerivative(){
testCat("ImplicitDerivative");
}
@Test
public void testIntegralBetween(){
testCat("IntegralBetween");
}
@Test
public void testIntersect(){
testCat("Intersect");
}
@Test
public void testIteration(){
testCat("Iteration");
}
@Test
public void testIterationList(){
testCat("IterationList");
}
@Test
public void testPointList(){
testCat("PointList");
}
@Test
public void testRootList(){
testCat("RootList");
}
@Test
public void testInvert(){
testCat("Invert");
}
@Test
public void testInflectionPoint() {
testCat("InflectionPoint");
}
@Test
public void testIsPrime(){
testCat("IsPrime");
}
@Test
public void testJoin(){
testCat("Join");
}
@Test
public void testLine(){
testCat("Line");
}
@Test
public void testLast(){
testCat("Last");
}
@Test
public void testLCM(){
testCat("LCM");
}
@Test
public void testLeftSide(){
testCat("LeftSide");
}
@Test
public void testLength(){
testCat("Length");
}
@Test
public void testLimit(){
testCat("Limit");
}
@Test
public void testLimitBelow(){
testCat("LimitBelow");
}
@Test
public void testLimitAbove(){
testCat("LimitAbove");
}
@Test
public void testMax(){
testCat("Max");
}
@Test
public void testMatrixRank(){
testCat("MatrixRank");
}
@Test
public void testMean(){
testCat("Mean");
}
@Test
public void testMedian(){
testCat("Median");
}
@Test
public void testMin(){
testCat("Min");
}
@Test
public void testMidpoint(){
testCat("Midpoint");
}
@Test
public void testMod(){
testCat("Mod");
}
@Test
public void testNextPrime(){
testCat("NextPrime");
}
@Test
public void testNIntegral(){
testCat("NIntegral");
}
@Test
public void testNormal(){
testCat("Normal");
}
@Test
public void testnPr(){
testCat("nPr");
}
@Test
public void testNSolutions(){
testCat("NSolutions");
}
@Test
public void testNSolve(){
testCat("NSolve");
}
@Test
public void testNSolve1310() {
testCat("NSolve1310");
}
@Test
public void testNumerator(){
testCat("Numerator");
}
@Test
public void testPartialFractions(){
testCat("PartialFractions");
}
@Test
public void testPerpendicularVector(){
testCat("PerpendicularVector");
}
@Test
public void testPoint() {
testCat("Point");
}
@Test
public void testFunction() {
testCat("Function");
}
@Test
public void testSVD() {
testCat("SVD");
}
@Test
public void testSolveODE2() {
testCat("SolveODE2");
}
@Test
public void testOrthogonalVector(){
testCat("OrthogonalVector");
}
@Test
public void testPascal(){
testCat("Pascal");
}
@Test
public void testPoisson(){
testCat("Poisson");
}
@Test
public void testPreviousPrime(){
testCat("PreviousPrime");
}
@Test
public void testPrimeFactors(){
testCat("PrimeFactors");
}
@Test
public void testProduct(){
testCat("Product");
}
@Test
public void testMixedNumber(){
testCat("MixedNumber");
}
@Test
public void testRandomBetween(){
testCat("RandomBetween");
}
@Test
public void testRandomBinomial(){
testCat("RandomBinomial");
}
@Test
public void testRandomElement(){
testCat("RandomElement");
}
@Test
public void testRandomPoisson(){
testCat("RandomPoisson");
}
@Test
public void testRandomNormal(){
testCat("RandomNormal");
}
@Test
public void testRandomPolynomial(){
testCat("RandomPolynomial");
}
@Test
public void testRationalize(){
testCat("Rationalize");
}
@Test
public void testReverse(){
testCat("Reverse");
}
@Test
public void testRightSide(){
testCat("RightSide");
}
@Test
public void testRoot(){
testCat("Root");
}
@Test
public void testReducedRowEchelonForm(){
testCat("ReducedRowEchelonForm");
}
@Test
public void testSample(){
testCat("Sample");
}
@Test
public void testSort(){
testCat("Sort");
}
@Test
public void testSampleVariance(){
testCat("SampleVariance");
}
@Test
public void testSampleSD(){
testCat("SampleSD");
}
@Test
public void testSequence(){
testCat("Sequence");
}
@Test
public void testSD(){
testCat("SD");
}
@Test
public void testShuffle(){
testCat("Shuffle");// TODO
}
@Test
public void testSimplify(){
testCat("Simplify");
}
@Test
public void testSpare() {
testCat("spare");
}
@Test
public void testExtremum() {
testCat("Extremum");
}
@Test
public void testDegreeConst() {
testCat("DegreeConst");
}
@Test
public void testEvaluate2() {
testCat("Evaluate2");
}
@Test
public void testSolveLogic() {
testCat("SolveLogic");
}
@Test
public void testFactorExponential() {
testCat("FactorExponential");
}
@Test
public void testVector() {
testCat("Vector");
}
@Test
public void testTrigCombine(){
testCat("TrigCombine");
}
@Test
public void testSolutions(){
testCat("Solutions");
}
@Test
public void testSolve(){
testCat("Solve");
}
@Test
public void testSolveODE(){
testCat("SolveODE");
}
@Test
public void testSubstitute(){
testCat("Substitute");
}
@Test
public void testSum(){
testCat("Sum");
}
@Test
public void testTangent(){
testCat("Tangent");
}
@Test
public void testTake(){
testCat("Take");
}
@Test
public void testTaylorPolynomial(){
testCat("TaylorPolynomial");
}
@Test
public void testTDistribution(){
testCat("TDistribution");
}
@Test
public void testToComplex(){
testCat("ToComplex");
}
@Test
public void testToExponential(){
testCat("ToExponential");
}
@Test
public void testToPolar(){
testCat("ToPolar");
}
@Test
public void testToPoint(){
testCat("ToPoint");
}
@Test
public void testTranspose(){
testCat("Transpose");
}
@Test
public void testTrigExpand(){
testCat("TrigExpand");
}
@Test
public void testTrigSimplify(){
testCat("TrigSimplify");
}
@Test
public void testUnique(){
testCat("Unique");
}
@Test
public void testUnitPerpendicularVector(){
testCat("UnitPerpendicularVector");
}
@Test
public void testUnitVector(){
testCat("UnitVector");
}
@Test
public void testVariance(){
testCat("Variance");
}
@Test
public void testWeibull(){
testCat("Weibull");
}
@Test
public void testZipf(){
testCat("Zipf");
}
@Test
public void testsin(){
testCat("sin");
}
@Test
public void testassignment(){
testCat("assignment");
}
@Test
public void testEvaluate(){
testCat("Evaluate");
}
@Test
public void testEvaluateLogic() {
testCat("EvaluateLogic");
}
@Test
public void testAbs(){
testCat("Abs");
}
@Test
public void testvecExpr(){
testCat("vec expr");
}
@Test
public void testChiSquared(){
testCat("ChiSquared");
}
@Test
public void testxx(){
testCat("xx");
}
@Test
public void testFractionalPart(){
testCat("FractionalPart");
}
@Test
public void testDelete(){
testCat("Delete");
}
@Test
public void testImaginary(){
testCat("Imaginary");
}
@Test
public void testNRoot(){
testCat("NRoot");
}
@Test
public void testReal(){
testCat("Real");
}
@Test
public void testRound(){
testCat("Round");
}
@Test
public void testFloor(){
testCat("Floor");
}
@Test
public void testCeil(){
testCat("Ceil");
}
@Test
public void testlistExpr(){
testCat("list expr");
}
@Test
public void testexpr(){
testCat("expr");
}
@Test
public void testtan(){
testCat("tan");
}
@Test
public void testcot(){
testCat("cot");
}
@Test
public void testAsymptote(){
testCat("Asymptote");
}
@Test
public void testconjugate(){
testCat("conjugate");
}
@Test
public void testtrig(){
testCat("Trig");
}
@Test
public void testarg(){
testCat("arg");
}
@Test
public void testln(){
testCat("ln");
}
@Test
public void testXXSolve(){
testCat("XXSolve");
}
@Test
public void testXXCFactor(){
testCat("XXCFactor");
}
@Test
public void testCIFactor(){
testCat("CIFactor");
}
@Test
public void testIFactor(){
testCat("IFactor");
}
@Test
public void testCurve(){
testCat("Curve");
}
@Test
public void testRadius(){
testCat("Radius");
}
@Test
public void testCenter(){
testCat("Center");
}
@Test
public void testCircumference(){
testCat("Circumference");
}
@Test
public void testDistance(){
testCat("Distance");
}
@Test
public void testAngle(){
testCat("Angle");
}
@Test
public void testCircle(){
testCat("Circle");
}
@Test
public void testAngularBisector(){
testCat("AngularBisector");
}
@Test
public void testLineBisector(){
testCat("LineBisector");
}
@Test
public void testEllipse(){
testCat("Ellipse");
}
@Test
public void testConic(){
testCat("Conic");
}
@Test
public void testHyperbola(){
testCat("Hyperbola");
}
@Test
public void testIntersection(){
testCat("Intersection");
}
@Test
public void testUnion(){
testCat("Union");
}
@Test
public void testsqrt(){
testCat("sqrt");
}
@Test
public void testexp(){
testCat("exp");
}
@Test
public void testPolynomial(){
testCat("Polynomial");
}
@Test
public void testXXXXNSolve(){
testCat("XXXXNSolve");
}
@Test
public void testabs(){
testCat("abs");
}
@Test
public void testlength(){
testCat("length");
}
@Test
public void testXXEvaluate(){
testCat("XXEvaluate");
}
@Test
public void testSolveAssume() {
testCat("SolveAssume");
}
@Test
public void testNSolve2() {
testCat("NSolve2");
}
@Test
public void testSolveTrig() {
testCat("SolveTrig");
}
@Test
public void testSolveUnderdetermined() {
testCat("SolveUnderdetermined");
}
@Test
public void testSolveIneq() {
testCat("SolveIneq");
}
@Test
public void testZip() {
testCat("Zip");
}
@Test
public void testTranslate() {
testCat("Translate");
}
}