From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- starmath/qa/cppunit/test_nodetotextvisitors.cxx | 665 ++++++++++++++++++++++++ 1 file changed, 665 insertions(+) create mode 100644 starmath/qa/cppunit/test_nodetotextvisitors.cxx (limited to 'starmath/qa/cppunit/test_nodetotextvisitors.cxx') diff --git a/starmath/qa/cppunit/test_nodetotextvisitors.cxx b/starmath/qa/cppunit/test_nodetotextvisitors.cxx new file mode 100644 index 000000000..c3172ab60 --- /dev/null +++ b/starmath/qa/cppunit/test_nodetotextvisitors.cxx @@ -0,0 +1,665 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "mock-visitor.hxx" +#include + +typedef tools::SvRef SmDocShellRef; + +using namespace ::com::sun::star; + +namespace { + +class Test : public test::BootstrapFixture { + +public: + // init + virtual void setUp() override; + virtual void tearDown() override; + + // tests + void SimpleUnaryOp(); + void SimpleBinaryOp(); + void SimpleRelationalOp(); + void SimpleSetOp(); + void SimpleFunctions(); + void SimpleOperators(); + void SimpleAttributes(); + void SimpleMisc(); + void SimpleBrackets(); + void SimpleFormats(); + void SimpleGreekChars(); + void SimpleSpecialChars(); + void testBinomInBinHor(); + void testBinVerInUnary(); + void testBinHorInSubSup(); + void testUnaryInMixedNumberAsNumerator(); + void testMiscEquivalent(); + void testParser(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(SimpleUnaryOp); + CPPUNIT_TEST(SimpleBinaryOp); + CPPUNIT_TEST(SimpleRelationalOp); + CPPUNIT_TEST(SimpleSetOp); + CPPUNIT_TEST(SimpleFunctions); + CPPUNIT_TEST(SimpleOperators); + CPPUNIT_TEST(SimpleAttributes); + CPPUNIT_TEST(SimpleMisc); + CPPUNIT_TEST(SimpleBrackets); + CPPUNIT_TEST(SimpleFormats); + CPPUNIT_TEST(SimpleGreekChars); + CPPUNIT_TEST(SimpleSpecialChars); + CPPUNIT_TEST(testBinomInBinHor); + CPPUNIT_TEST(testBinVerInUnary); + CPPUNIT_TEST(testBinHorInSubSup); + CPPUNIT_TEST(testUnaryInMixedNumberAsNumerator); + CPPUNIT_TEST(testMiscEquivalent); + CPPUNIT_TEST(testParser); + CPPUNIT_TEST_SUITE_END(); + +private: + SmDocShellRef xDocShRef; + void parseandparseagain(const char *input, const char *test_name); + void ParseAndCheck(const char *input, const char *expected, const char *test_name); + void ParseAndCompare(const char *formula1, const char *formula2, const char *test_name); +}; + +void Test::setUp() +{ + BootstrapFixture::setUp(); + + SmGlobals::ensure(); + + xDocShRef = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT); +} + +void Test::tearDown() +{ + xDocShRef.clear(); + BootstrapFixture::tearDown(); +} + +/* + * Most of the formula commands in this file came from: + * http://wiki.openoffice.org/wiki/Template:Math_commands_reference + * which was licensed with a + * Creative Common Attribution 3.0 license and written by: + * Jeanweber, Weegreenblobbie, Jdpipe, TJFrazier, Ysangkok, B michaelsen, Spellbreaker + */ + +void Test::SimpleUnaryOp() +{ + parseandparseagain("+1", "Positive (plus)"); + parseandparseagain("-2", "Negative (minus)"); + parseandparseagain("+-3", "Plus/minus"); + parseandparseagain("-+4", "Minus/plus"); + parseandparseagain("neg a", "Boolean 'not'"); + parseandparseagain("fact a", "Factorial"); + parseandparseagain(" - { 1 over 2 } ", "BinVer in Unary 1"); + ParseAndCheck(" - { 1 over 2 } ", " - { 1 over 2 } ", "BinVer in Unary 1"); + parseandparseagain(" { - { 1 over 2 } } ", "BinVer in Unary 2"); + parseandparseagain(" - 1 over 2 ", "Unary in BinVer as numerator 1"); + parseandparseagain(" { - 1 } over 2 ", "Unary in BinVer as numerator 2"); + parseandparseagain(" 1 over - 2 ", "Unary in BinVer as denominator 1"); + parseandparseagain(" 1 over { - 2 } ", "Unary in BinVer as denominator 2"); + parseandparseagain(" 2 { - 1 over 2 } ", "Mixed number with Unary in denominator 1"); + parseandparseagain(" 2 { - 1 } over 2 ", "Mixed number with Unary in denominator 2"); + parseandparseagain(" - 1 + 2 ", "Unary in BinHor"); +} + +void Test::SimpleBinaryOp() +{ + parseandparseagain("a + b", "Addition"); + parseandparseagain("a cdot b", "Dot product"); + parseandparseagain("a times b", "Cross product"); + parseandparseagain("a * b", "Multiplication (asterisk)"); + parseandparseagain("a and b", "Boolean 'and'"); + parseandparseagain("a - b", "Subtraction"); + parseandparseagain("a over b", "Division (as a fraction)"); + parseandparseagain("a div b", "Division (as an operator)"); + parseandparseagain("a / b", "Division (with a slash)"); + parseandparseagain("a or b", "Boolean 'or'"); + parseandparseagain("a circ b", "Concatenation"); +} + +void Test::SimpleRelationalOp() +{ + parseandparseagain("a = b", "Is equal"); + parseandparseagain("a <> b", "Is not equal"); + parseandparseagain("a approx 2", "Approximately"); + parseandparseagain("a divides b", "Divides"); + parseandparseagain("a ndivides b", "Does not divide"); + parseandparseagain("a < 2", "Less than"); + parseandparseagain("a > 2", "Greater than"); + parseandparseagain("a simeq b", "Similar to or equal"); + parseandparseagain("a parallel b", "Parallel"); + parseandparseagain("a ortho b", "Orthogonal to"); + parseandparseagain("a leslant b", "Less than or equal to"); + parseandparseagain("a geslant b", "Greater than or equal to"); + parseandparseagain("a sim b", "Similar to"); + parseandparseagain("a equiv b", "Congruent"); + parseandparseagain("a <= b", "Less than or equal to"); + parseandparseagain("a >= b", "Greater than or equal to"); + parseandparseagain("a prop b", "Proportional"); + parseandparseagain("a toward b", "Toward"); + parseandparseagain("a dlarrow b", "Arrow left"); + parseandparseagain("a dlrarrow b", "Double arrow left and right"); + parseandparseagain("drarrow b", "Arrow right"); +} + +void Test::SimpleSetOp() +{ + parseandparseagain("a in B", "Is in"); + parseandparseagain("a notin B", "Is not in"); + parseandparseagain("A owns b", "Owns"); + parseandparseagain("emptyset", "Empty set"); + parseandparseagain("A intersection B", "Intersection"); + parseandparseagain("A union B", "Union"); + parseandparseagain("A setminus B", "Difference"); + parseandparseagain("A slash B", "Quotient"); + parseandparseagain("aleph", "Aleph"); + parseandparseagain("A subset B", "Subset"); + parseandparseagain("A subseteq B", "Subset or equal to"); + parseandparseagain("A supset B", "Superset"); + parseandparseagain("A supseteq B", "Superset or equal to"); + parseandparseagain("A nsubset B", "Not subset"); + parseandparseagain("A nsubseteq B", "Not subset or equal"); + parseandparseagain("A nsupset B", "Not superset"); + parseandparseagain("A nsupseteq B", "Not superset or equal"); + parseandparseagain("setN", "Set of natural numbers"); + parseandparseagain("setZ", "Set of integers"); + parseandparseagain("setQ", "Set of rational numbers"); + parseandparseagain("setR", "Set of real numbers"); + parseandparseagain("setC", "Set of complex numbers"); +} + +void Test::SimpleFunctions() +{ + parseandparseagain("func e^{a}", "Exponential"); + parseandparseagain("ln(a)", "Natural logarithm"); + parseandparseagain("exp(a)", "Exponential function"); + parseandparseagain("log(a)", "Logarithm"); + parseandparseagain("a^{b}", "Power"); + parseandparseagain("sin(a)", "Sine"); + parseandparseagain("cos(a)", "Cosine"); + parseandparseagain("tan(a)", "Tangent"); + parseandparseagain("cot(a)", "Cotangent"); + parseandparseagain("sqrt{a}", "Square root"); + parseandparseagain("arcsin(a)", "Arcsine"); + parseandparseagain("arccos(a)", "Arccosine"); + parseandparseagain("arctan(a)", "Arctangent"); + parseandparseagain("arccot(a)", "Arc cotangent"); + parseandparseagain("nroot{a}{b}", "nth root"); + parseandparseagain("sinh(a)", "Hyperbolic sine"); + parseandparseagain("cosh(a)", "Hyperbolic cosine"); + parseandparseagain("tanh(a)", "Hyperbolic tangent"); + parseandparseagain("coth(a)", "Hyperbolic cotangent"); + parseandparseagain("abs{a}", "Absolute value"); + parseandparseagain("arsinh(a)", "Arc hyperbolic sine"); + parseandparseagain("arcosh(a)", "Arc hyperbolic cosine"); + parseandparseagain("artanh(a)", "Arc hyperbolic tangent"); + parseandparseagain("arcoth(a)", "Arc hyperbolic cotangent"); +} + +void Test::SimpleOperators() +{ + parseandparseagain("lim{a}", "Limit"); + parseandparseagain("sum{a}", "Sum"); + parseandparseagain("prod{a}", "Product"); + parseandparseagain("coprod{a}", "Coproduct"); + parseandparseagain("int from {r_0} to {r_t} a", "Upper and lower bounds shown with integral (from & to)"); + ParseAndCheck("int csup {r_0} csub {r_t} a", "int csup { r _ 0 } csub { r _ t } a ", "Upper and lower bounds shown with integral (csub & csup)"); + ParseAndCheck("sum csup { size 8 { x - 1 } } csub { size 8 a } b ", "sum csup { size 8 { x - 1 } } csub { size 8 a } b ", "Sum with sized upper and lower bounds"); + parseandparseagain("int{a}", "Integral"); + parseandparseagain("intd_{1}^{2}{x dx}", "Dynamically-sized integral"); + parseandparseagain("iint{a}", "Double integral"); + parseandparseagain("iiint{a}", "Triple integral"); + parseandparseagain("sum from{3}b", "Lower bound shown with summation symbol"); + parseandparseagain("lint a", "Contour integral"); + parseandparseagain("llint a", "Double curved integral"); + parseandparseagain("lllint a", "Triple curved integral"); + parseandparseagain("prod from {i=1} to {n} {(i+1)}", "Product with range"); + ParseAndCheck("%Ux2135", "%Ux2135", "fdo#77831"); +} + +void Test::SimpleAttributes() +{ + parseandparseagain("acute a", "Acute accent"); + parseandparseagain("grave a", "Grave accent"); + parseandparseagain("check a", "Reverse circumflex"); + parseandparseagain("breve a", "Breve"); + parseandparseagain("circle a", "Circle"); + parseandparseagain("vec a", "Vector arrow"); + parseandparseagain("harpoon a", "Harpoon"); + parseandparseagain("tilde a", "Tilde"); + parseandparseagain("hat a", "Circumflex"); + parseandparseagain("bar a", "Line above"); + parseandparseagain("dot a", "Dot"); + parseandparseagain("widevec abc", "Wide vector arrow"); + parseandparseagain("wideharpoon abc", "Wide harpoon"); + parseandparseagain("widetilde abc", "Wide tilde"); + parseandparseagain("widehat abc", "Wide circumflex"); + parseandparseagain("ddot a", "Double dot"); + parseandparseagain("overline abc", "Line over"); + parseandparseagain("underline abc", "Line under"); + parseandparseagain("overstrike abc", "Line through"); + parseandparseagain("dddot a", "Triple dot"); + parseandparseagain("phantom a", "Transparent (useful to get a placeholder of a given size)"); + parseandparseagain("bold a", "Bold font"); + parseandparseagain("ital a", "Italic font"); + parseandparseagain("nitalic a", "Roman (non-italic) font 1"); + parseandparseagain("\"a\"", "Roman (non-italic) font 2"); + parseandparseagain("size 16 qv", "Resize font"); + parseandparseagain("font sans qv", "Sans serif font"); + parseandparseagain("font serif qv", "Serif font"); + parseandparseagain("font fixed qv", "Fixed font"); + parseandparseagain("color cyan qv", "Cyan color"); + parseandparseagain("color yellow qv", "Yellow color"); + parseandparseagain("color white qv", "White color"); + parseandparseagain("color green qv", "Green color"); + parseandparseagain("color blue qv", "Blue color"); + parseandparseagain("color red qv", "Red color"); + parseandparseagain("color green X qv", "Green color changes back"); + parseandparseagain("color green {X qv}", "Green color, more than one item"); +} + +void Test::SimpleMisc() +{ + parseandparseagain("infinity", "Infinity"); + parseandparseagain("partial", "Partial"); + parseandparseagain("nabla", "Nabla"); + parseandparseagain("exists", "There exists"); + parseandparseagain("notexists", "There not exists"); + parseandparseagain("forall", "For all"); + parseandparseagain("hbar", "H bar"); + parseandparseagain("lambdabar", "Lambda bar"); + parseandparseagain("re", "Real part"); + parseandparseagain("im", "Imaginary part"); + parseandparseagain("wp", "Weierstrass p"); + parseandparseagain("leftarrow", "Left arrow"); + parseandparseagain("rightarrow", "Right arrow"); + parseandparseagain("uparrow", "Up arrow"); + parseandparseagain("downarrow", "Down arrow"); + parseandparseagain("dotslow", "Dots at bottom"); + parseandparseagain("dotsaxis", "Dots at middle"); + parseandparseagain("dotsvert", "Dots vertical"); + parseandparseagain("dotsup", "Dots diagonal upward"); + parseandparseagain("dotsdown", "Dots diagonal downward"); +} + +void Test::SimpleBrackets() +{ + parseandparseagain("(a)", "Round Brackets"); + parseandparseagain("[b]", "Square Brackets"); + parseandparseagain("ldbracket c rdbracket", "Double Square Brackets"); + parseandparseagain("lline a rline", "Single line or absolute"); + parseandparseagain("abs a", "Single line or absolute 2"); + parseandparseagain("ldline a rdline", "Double line"); + parseandparseagain("lbrace w rbrace", "Braces"); + parseandparseagain("left lbrace stack{0, n <> 0 # 1, n = 1} right none", "Single left brace"); + parseandparseagain("langle d rangle", "Angle Brackets"); + parseandparseagain("langle a mline b rangle", "Operator Brackets"); + parseandparseagain("{a}", "Group brackets (used for program control)"); + parseandparseagain("left ( stack{a # b # z} right )", "Round brackets scalable"); + parseandparseagain("left [ stack{x # y} right ]", "Square brackets scalable"); + parseandparseagain("left ldbracket c right rdbracket", "Double square brackets scalable"); + parseandparseagain("left lline a right rline", "Line scalable"); + parseandparseagain("left ldline d right rdline", "Double line scalable"); + parseandparseagain("left lbrace e right rbrace", "Brace scalable"); + parseandparseagain("left langle f right rangle", "Angle bracket scalable"); + parseandparseagain("left langle g mline h right rangle", "Operator brackets scalable"); + parseandparseagain("{a} overbrace b", "Over brace scalable"); + parseandparseagain("{b} underbrace a", "Under brace scalable"); +} + +void Test::SimpleFormats() +{ + parseandparseagain("a lsup{b}", "Left superscript"); + parseandparseagain("a csup{b}", "Center superscript"); + parseandparseagain("a^{b}", "Right superscript"); + parseandparseagain("a lsub{b}", "Left subscript"); + parseandparseagain("a csub{b}", "Center subscript"); + parseandparseagain("a_{b}", "Right subscript"); + parseandparseagain("stack { Hello world # alignl (a) }", "Align character to left"); + parseandparseagain("stack{Hello world # alignc(a)}", "Align character to center"); + parseandparseagain("stack { Hello world # alignr(a)}", "Align character to right"); + parseandparseagain("binom{a}{b}", "Vertical stack of 2"); + parseandparseagain("stack{a # b # z}", "Vertical stack, more than 2"); + parseandparseagain("matrix{a # b ## c # d}", "Matrix"); + parseandparseagain("matrix{a # \"=\" # alignl{b} ## {} # \"=\" # alignl{c+1}}", "Equations aligned at '=' (using 'matrix') "); + parseandparseagain("stack{alignl{a} = b # alignl{phantom{a} = c+1}}", "Equations aligned at '=' (using 'phantom') "); + parseandparseagain("asldkfjo newline sadkfj", "New line"); + parseandparseagain("stuff `stuff", "Small gap (grave)"); + parseandparseagain("stuff~stuff", "Large gap (tilde)"); +} + +void Test::SimpleGreekChars() +{ + parseandparseagain("%ALPHA", "Capital alpha"); + parseandparseagain("%BETA", "Capital beta"); + parseandparseagain("%CHI", "Capital chi"); + parseandparseagain("%DELTA", "Capital delta"); + parseandparseagain("%EPSILON", "Capital epsilon"); + parseandparseagain("%ETA", "Capital eta"); + parseandparseagain("%GAMMA", "Capital gamma"); + parseandparseagain("%IOTA", "Capital iota"); + parseandparseagain("%LAMBDA", "Capital lambda"); + parseandparseagain("%MU", "Capital mu"); + parseandparseagain("%NU", "Capital nu"); + parseandparseagain("%OMEGA", "Capital omega"); + parseandparseagain("%OMICRON", "Capital omicron"); + parseandparseagain("%PHI", "Capital phi"); + parseandparseagain("%PI", "Capital pi"); + parseandparseagain("%PSI", "Capital psi"); + parseandparseagain("%RHO", "Capital rho"); + parseandparseagain("%SIGMA", "Capital sigma"); + parseandparseagain("%TAU", "Capital tau"); + parseandparseagain("%THETA", "Capital theta"); + parseandparseagain("%UPSILON", "Capital upsilon"); + parseandparseagain("%XI", "Capital xi"); + parseandparseagain("%ZETA", "Capital zeta"); + parseandparseagain("%alpha", "lowercase alpha"); + parseandparseagain("%beta", "lowercase beta"); + parseandparseagain("%chi", "lowercase chi"); + parseandparseagain("%delta", "lowercase delta"); + parseandparseagain("%epsilon", "lowercase epsilon"); + parseandparseagain("%eta", "lowercase eta"); + parseandparseagain("%gamma", "lowercase gamma"); + parseandparseagain("%iota", "lowercase iota"); + parseandparseagain("%kappa", "lowercase kappa"); + parseandparseagain("%lambda", "lowercase lambda"); + parseandparseagain("%mu", "lowercase mu"); + parseandparseagain("%nu", "lowercase nu"); + parseandparseagain("%omega", "lowercase omega"); + parseandparseagain("%omicron", "lowercase omicron"); + parseandparseagain("%phi", "lowercase phi"); + parseandparseagain("%pi", "lowercase pi"); + parseandparseagain("%psi", "lowercase psi"); + parseandparseagain("%rho", "lowercase rho"); + parseandparseagain("%sigma", "lowercase sigma"); + parseandparseagain("%tau", "lowercase tau"); + parseandparseagain("%theta", "lowercase theta"); + parseandparseagain("%upsilon", "lowercase upsilon"); + parseandparseagain("%varepsilon", "Varepsilon"); + parseandparseagain("%varphi", "Varphi"); + parseandparseagain("%varpi", "Varpi"); + parseandparseagain("%varrho", "Varrho"); + parseandparseagain("%varsigma", "Varsigma"); + parseandparseagain("%vartheta", "Vartheta"); + parseandparseagain("%xi", "lowercase xi"); + parseandparseagain("%zeta", "lowercase zeta"); +} + +void Test::SimpleSpecialChars() +{ + parseandparseagain("%and", "And"); + parseandparseagain("%angle", "Angle"); + parseandparseagain("%element", "Element"); + parseandparseagain("%identical", "Identical"); + parseandparseagain("%infinite", "Infinite"); + parseandparseagain("%noelement", "No element"); + parseandparseagain("%notequal", "Not equal"); + parseandparseagain("%or", "Or"); + parseandparseagain("%perthousand", "Per thousand"); + parseandparseagain("%strictlygreaterthan", "Strictly greater than"); + parseandparseagain("%strictlylessthan", "Strictly less than"); + parseandparseagain("%tendto", "Tend to"); +} + +/* This test takes a formula command, parses it, converts the node to text, + * parses it again, converts it to text again, and compares the values. + * Doing this doesn't prove that it is correct, but it should prove that the + * meaning of the original command is not being changed. + */ +void Test::parseandparseagain(const char *formula, const char *test_name) +{ + OUString output1, output2; + + // parse 1 + OUString input = OUString::createFromAscii(formula); + auto pNode1 = SmParser().ParseExpression(input); + pNode1->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode1.get(), output1); + + // parse 2 + auto pNode2 = SmParser().ParseExpression(output1); + pNode2->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode2.get(), output2); + + // compare + CPPUNIT_ASSERT_EQUAL_MESSAGE(test_name, + output1, + output2); + + // auxiliary test for Accept() + std::unique_ptr mv(new MockVisitor); + pNode1->Accept(mv.get()); + pNode2->Accept(mv.get()); +} + +void Test::ParseAndCheck(const char *formula, const char * expected, const char *test_name) +{ + OUString sOutput; + + // parse + OUString sInput = OUString::createFromAscii(formula); + auto pNode = SmParser().ParseExpression(sInput); + pNode->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode.get(), sOutput); + + // compare + OUString sExpected = OUString::createFromAscii(expected); + CPPUNIT_ASSERT_EQUAL_MESSAGE(test_name, + sExpected, + sOutput); + + // auxiliary test for Accept() + std::unique_ptr mv(new MockVisitor); + pNode->Accept(mv.get()); +} + +// Parse two formula commands and verify that they give the same output +void Test::ParseAndCompare(const char *formula1, const char *formula2, const char *test_name) +{ + OUString sOutput1, sOutput2; + + // parse formula1 + OUString sInput1(formula1, strlen(formula1), RTL_TEXTENCODING_UTF8); + auto pNode1 = SmParser().ParseExpression(sInput1); + pNode1->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode1.get(), sOutput1); + + // parse formula2 + OUString sInput2(formula2, strlen(formula2), RTL_TEXTENCODING_UTF8); + auto pNode2 = SmParser().ParseExpression(sInput2); + pNode2->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode2.get(), sOutput2); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(test_name, sOutput1, sOutput2); + + // auxiliary test for Accept() + std::unique_ptr mv(new MockVisitor); + pNode1->Accept(mv.get()); + pNode2->Accept(mv.get()); +} + +void Test::testBinomInBinHor() +{ + OUString sInput, sExpected; + + // set up a binom (table) node + sInput += "binom a b + c"; + auto pTree = SmParser().Parse(sInput); + pTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(pTree.get(), xDocShRef.get()); + ScopedVclPtrInstance< VirtualDevice > pOutputDevice; + + // move forward (more than) enough places to be at the end + int i; + for (i = 0; i < 8; ++i) + aCursor.Move(pOutputDevice, MoveRight); + + // tack +d on the end, which will put the binom into an SmBinHorNode + aCursor.InsertElement(PlusElement); + aCursor.InsertText("d"); + + sExpected += " { { binom a b + c } + d } "; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Binom Node in BinHor Node", sExpected, xDocShRef->GetText()); +} + +void Test::testBinVerInUnary() +{ + OUString sInput, sExpected; + + // set up a unary operator with operand + sInput += "- 1"; + auto pTree = SmParser().Parse(sInput); + pTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(pTree.get(), xDocShRef.get()); + ScopedVclPtrInstance< VirtualDevice > pOutputDevice; + + // move forward (more than) enough places to be at the end + int i; + for (i = 0; i < 3; ++i) + aCursor.Move(pOutputDevice, MoveRight); + + // select the operand + aCursor.Move(pOutputDevice, MoveLeft, false); + // set up a fraction + aCursor.InsertFraction(); + aCursor.Move(pOutputDevice, MoveDown); + aCursor.InsertText("2"); + + sExpected += " - { 1 over 2 } "; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Binary Vertical in Unary Operator", sExpected, xDocShRef->GetText()); +} + +void Test::testBinHorInSubSup() +{ + // set up a blank formula + auto pTree = SmParser().Parse(OUString()); + pTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(pTree.get(), xDocShRef.get()); + ScopedVclPtrInstance< VirtualDevice > pOutputDevice; + + // Insert an RSup expression with a BinHor for the exponent + aCursor.InsertText("a"); + aCursor.InsertSubSup(RSUP); + aCursor.InsertText("b"); + aCursor.InsertElement(PlusElement); + aCursor.InsertText("c"); + + // Move to the end and add d to the expression + aCursor.Move(pOutputDevice, MoveRight); + aCursor.InsertElement(PlusElement); + aCursor.InsertText("d"); + + OUString sExpected = " { a ^ { b + c } + d } "; + CPPUNIT_ASSERT_EQUAL_MESSAGE("BinHor in SubSup", sExpected, xDocShRef->GetText()); +} + +void Test::testUnaryInMixedNumberAsNumerator() +{ + // set up a unary operator + OUString sInput = "- 1"; + auto pTree = SmParser().Parse(sInput); + pTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(pTree.get(), xDocShRef.get()); + ScopedVclPtrInstance< VirtualDevice > pOutputDevice; + + // move forward (more than) enough places to be at the end + for (size_t i = 0; i < 3; ++i) + aCursor.Move(pOutputDevice, MoveRight); + + // Select the whole Unary Horizontal Node + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Move(pOutputDevice, MoveLeft, false); + + // Set up a fraction + aCursor.InsertFraction(); + aCursor.Move(pOutputDevice, MoveDown); + aCursor.InsertText("2"); + + // Move left and turn this into a mixed number + // (bad form, but this could happen right?) + aCursor.Move(pOutputDevice, MoveLeft); + aCursor.Move(pOutputDevice, MoveLeft); + aCursor.InsertText("2"); + + // move forward (more than) enough places to be at the end + for (size_t i = 0; i < 8; ++i) + aCursor.Move(pOutputDevice, MoveRight); + + // add 4 to the end + aCursor.InsertElement(PlusElement); + aCursor.InsertText("4"); + + OUString sExpected = " { 2 { - 1 over 2 } + 4 } "; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary in mixed number as Numerator", sExpected, xDocShRef->GetText()); +} + +void Test::testMiscEquivalent() +{ + // fdo#55853 + ParseAndCompare("2x", "2 x", "Number times variable"); + ParseAndCompare("3x^2", "3 x^2", "Number times power"); + + // i#11752 and fdo#55853 + ParseAndCompare("x_2n", "x_{2 n}", "Number times variable in subscript"); + ParseAndCompare("x^2n", "x^{2 n}", "Number times variable in supscript"); + + // fdo#66081 + ParseAndCompare("{x}", "x", "Variable in brace"); + ParseAndCompare("{{x+{{y}}}}", "x+y", "Nested braces"); + + // check non-BMP Unicode char + ParseAndCompare("{\xf0\x9d\x91\x8e}", "\xf0\x9d\x91\x8e", "non-BMP variable in brace"); + ParseAndCompare("{ \xf0\x9d\x91\x8e }", "\xf0\x9d\x91\x8e", "non-BMP variable in brace"); + + // tdf#88320 + ParseAndCompare("A_1,B_2", "A_{1},B_2", "Comma between a digit and non-digit delimits subscript"); + + //tdf#97164 + ParseAndCompare("100 %", "100\"%\"", "Percent symbol at the end"); +} + +void Test::testParser() +{ + OUString sOutput; + OUString sInput(u"{ \U0001D44E }"); // non-BMP Unicode + OUString sExpected(u"\U0001D44E"); + auto pNode = SmParser().ParseExpression(sInput); + pNode->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode.get(), sOutput); + CPPUNIT_ASSERT_EQUAL(sExpected, sOutput); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3