package org.geogebra.io.latex;
import org.geogebra.common.io.latex.BracketsAdapter;
import org.geogebra.common.io.latex.GeoGebraSerializer;
import org.geogebra.common.io.latex.ParseException;
import org.geogebra.common.io.latex.Parser;
import org.geogebra.common.io.latex.TeXAtomSerializer;
import org.geogebra.common.util.lang.Unicode;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.himamis.retex.editor.share.meta.MetaModel;
import com.himamis.retex.editor.share.model.MathFormula;
import com.himamis.retex.editor.share.serializer.TeXSerializer;
import com.himamis.retex.renderer.desktop.FactoryProviderDesktop;
import com.himamis.retex.renderer.share.TeXFormula;
import com.himamis.retex.renderer.share.TeXParser;
import com.himamis.retex.renderer.share.platform.FactoryProvider;
public class SerializeLaTeX {
static Parser parser;
private static GeoGebraSerializer serializer;
@BeforeClass
public static void prepare() {
FactoryProvider.setInstance(new FactoryProviderDesktop());
MetaModel m = new MetaModel();
parser = new Parser(m);
serializer = new GeoGebraSerializer();
}
@Test
public void testAtoms() {
checkCannon("a", "a");
}
@Test
public void testExpr() {
checkCannon("1 * 2", "1*2");
checkCannon("1 == 2", "1==2");
checkCannon("1 = 2", "1=2");
checkCannon("(1 * 2)", "(1*2)");
}
@Test
public void testSqrt() {
checkCannon("sqrt(x + 1)", "sqrt(x+1)");
checkCannon("f(x) = sqrt(x)", "f(x)=sqrt(x)");
checkCannon("nroot(x + 1,3)", "nroot(x+1,3)");
checkCannon("f(x) = nroot(x,3)", "f(x)=nroot(x,3)");
}
@Test
public void testDiv() {
checkCannon("1/2", "(1)/(2)");
checkCannon("1/2+3", "(1)/(2)+3");
checkCannon("1/ ( 2)", "(1)/(2)");
checkCannon("1/ ( 2+3)", "(1)/(2+3)");
checkCannon("1/ ((2+3)+4)", "(1)/((2+3)+4)");
checkCannon("1/(2/3)", "(1)/((2)/(3))");
checkCannon("x^2/ 3", "(x^(2))/(3)");
checkCannon("x^2 / 2", "(x^(2))/(2)");
checkCannon("2/cos(x)", "(2)/(cos(x))");
}
@Test
public void testExponent() {
checkCannon("exp(-30)", "exp(-30)");
checkCannon(Unicode.EULER_STRING + "^-30", Unicode.EULER_STRING
+ "^(-30)");
checkCannon(Unicode.EULER_STRING + "^-30+1", Unicode.EULER_STRING
+ "^(-30)+1");
checkCannon(Unicode.EULER_STRING + Unicode.Superscript_Minus
+ Unicode.Superscript_1 + Unicode.Superscript_0,
Unicode.EULER_STRING + "^(-10)");
}
@Test
public void testFloorCeil() {
checkCannon("floor(x)", "floor(x)");
checkCannon("ceil(x)", "ceil(x)");
checkCannon(Unicode.LFLOOR + "x" + Unicode.RFLOOR, "floor(x)");
checkCannon(Unicode.LCEIL + "x" + Unicode.RCEIL, "ceil(x)");
}
@Test
public void testPower() {
checkCannon("x ^ 2", "x^(2)");
checkCannon("x ^ 2 + 1", "x^(2)+1");
checkCannon("x" + Unicode.Superscript_2 + Unicode.Superscript_3,
"x^(23)");
checkCannon("x" + Unicode.Superscript_Minus + Unicode.Superscript_2
+ Unicode.Superscript_3, "x^(-23)");
checkCannon("1 + x" + Unicode.Superscript_Minus + Unicode.Superscript_2
+ Unicode.Superscript_3, "1+x^(-23)");
checkCannon("e^x*sin(x)", "e^(x)*sin(x)");
checkCannon("e^(-10/x)*sin(x)", "e^(-(10)/(x))*sin(x)");
}
@Test
public void testSubscript() {
checkCannon("x_2", "x_{2}");
checkCannon("x_2 = 7", "x_{2}=7");
checkCannon("x_2 t", "x_{2}*t");
checkCannon("x_2 sin(x)", "x_{2}*sin(x)");
checkCannon("f_2(x)", "f_{2}(x)");
checkCannon("f_2 (x)", "f_{2} (x)");
}
@Test
public void testPoint() {
checkCannon("(1, 2)", "(1,2)");
checkCannon("(1; 2)", "(1;2)");
checkCannon("(1, 2, 3)", "(1,2,3)");
checkCannon("(1; 2; 3)", "(1;2;3)");
}
@Test
public void testMultiply() {
checkCannon("t (1,2)", "t (1,2)");
checkCannon("x x x", "x*x*x");
}
@Test
public void testCommand() {
checkCannon("turtle1=Turtle[]", "turtle1=Turtle[]");
checkCannon("Turtle[]", "Turtle[]");
checkCannon("Turtle[1*3,7]", "Turtle[1*3,7]");
}
@Test
public void testMatrix() {
checkCannon("{{1,2},{3,4}}", "{{1,2},{3,4}}");
checkCannon("{{1 , 2} , { 3 , 4}}", "{{1,2},{3,4}}");
checkCannon("{{1 , 2} , 3}", "{{1,2},3}");
checkCannon("{{1,2},{3,4}}+1", "{{1,2},{3,4}}+1");
checkCannon("{7,{{1,2},{3,4}}+2,4,5,6}", "{7,{{1,2},{3,4}}+2,4,5,6}");
}
@Test
public void testList() {
checkCannon("{x,1}", "{x,1}");
checkCannon("{x, 1}", "{x,1}");
checkCannon("{x ,1}", "{x,1}");
checkCannon("{x , 1}", "{x,1}");
}
@Test
public void testComma() {
checkCannon("If[x<1/x,x/2,sqrt(x/2)]",
"If[x<(1)/(x),(x)/(2),sqrt((x)/(2))]");
checkCannon("(1;sqrt(2))", "(1;sqrt(2))");
checkCannon("(t^n;t)", "(t^(n);t)");
}
@Test
public void testParseLaTeX() {
checkLaTeX("\\frac{x+y}{x-y}", "(x+y)/(x-y)");
checkLaTeX("\\sqrt{x+y}", "sqrt(x+y)");
checkLaTeX("\\sqrt{x}+2", "sqrt(x)+2");
checkLaTeX("1-\\sqrt[3]{x}", "1-nroot(x,3)");
checkLaTeX("X=\\left(x_0+2x_x,y_0+2x_y\\right)",
"X=(x_0+2x_x,y_0+2x_y)");
checkLaTeX("i=\\left[0,\\frac{6\\pi}{p}...24\\pi\\right]",
"i=[0,(6pi)/(p)...24pi]");
checkLaTeX(
"\\left(\\left(1-t\\right)\\left(x_1\\right)+t\\left(x_1+R\\ f\\left(j\\right)\\right),\\left(1-t\\right)\\left(y_1\\right)+t\\left(y_1+Rg\\left(j\\right)\\right)\\right)",
"((1-t)(x_1)+t(x_1+R f(j)),(1-t)(y_1)+t(y_1+Rg(j)))");
checkLaTeX("\\frac{x^2}{m^2}+\\frac{y^2}{n^2}\\ge2",
"(x^(2))/(m^(2))+(y^(2))/(n^(2))>=2");
checkLaTeX("a\\leq b", "a<=b");
checkLaTeX("f\\left(x\\right)=\\sin\\left(x\\right)", "f(x)=sin(x)");
checkLaTeX("r\\ =\\ g^{\\theta}", "r = g^(" + Unicode.thetaStr + ")");
checkLaTeX("7\\cdot 6", "7*6");
checkLaTeX("7\\times 6", "7*6");
}
@Test
public void testParseLaTeXAdapter() {
checkLaTeX("a=\\left[1,...,4\\right]", "a=(1...4)",
new BracketsAdapter());
}
private void checkLaTeX(String string, String string2) {
checkLaTeX(string, string2, null);
}
private void checkLaTeX(String string, String string2, BracketsAdapter ad) {
TeXFormula tf = new TeXFormula();
TeXParser tp = new TeXParser(string, tf);
tp.parse();
Assert.assertEquals(string2,
new TeXAtomSerializer(ad).serialize(tf.root));
}
private static void checkCannon(String input, String output) {
MathFormula mf = null;
try {
mf = parser.parse(input);
checkLaTeXRender(mf);
} catch (ParseException e) {
Assert.assertNull(e);
}
Assert.assertNotNull(mf);
Assert.assertEquals(mf.getRootComponent() + "", output,
serializer.serialize(mf));
try {
mf = parser.parse(output);
checkLaTeXRender(mf);
} catch (ParseException e) {
Assert.assertNull(e);
}
}
private static void checkLaTeXRender(MathFormula mf) {
String tex = TeXSerializer.serialize(mf.getRootComponent(),
new MetaModel());
TeXFormula tf = new TeXFormula();
TeXParser tp = new TeXParser(tex, tf);
tp.parse();
}
}