diff options
Diffstat (limited to '')
-rw-r--r-- | starmath/qa/cppunit/mock-visitor.hxx | 192 | ||||
-rw-r--r-- | starmath/qa/cppunit/test_cursor.cxx | 172 | ||||
-rw-r--r-- | starmath/qa/cppunit/test_node.cxx | 144 | ||||
-rw-r--r-- | starmath/qa/cppunit/test_nodetotextvisitors.cxx | 665 | ||||
-rw-r--r-- | starmath/qa/cppunit/test_parse.cxx | 128 | ||||
-rw-r--r-- | starmath/qa/cppunit/test_starmath.cxx | 563 |
6 files changed, 1864 insertions, 0 deletions
diff --git a/starmath/qa/cppunit/mock-visitor.hxx b/starmath/qa/cppunit/mock-visitor.hxx new file mode 100644 index 000000000..8dab85336 --- /dev/null +++ b/starmath/qa/cppunit/mock-visitor.hxx @@ -0,0 +1,192 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_STARMATH_QA_CPPUNIT_MOCK_VISITOR_HXX +#define INCLUDED_STARMATH_QA_CPPUNIT_MOCK_VISITOR_HXX + +#include <cppunit/TestAssert.h> +#include <visitors.hxx> + +/** Simple visitor for testing SmVisitor */ +class MockVisitor : public SmVisitor +{ +public: + virtual ~MockVisitor() {} + + void Visit( SmTableNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmTableNode should have type SmNodeType::Table", + SmNodeType::Table, pNode->GetType()); + auto eTT = pNode->GetToken().eType; + CPPUNIT_ASSERT_MESSAGE("The type of SmTableNode's token should be either TEND, TBINOM, or TSTACK", + eTT == TEND || eTT == TBINOM || eTT == TSTACK); + VisitChildren( pNode ); + } + + void Visit( SmBraceNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBraceNode should have type SmNodeType::Brace", + SmNodeType::Brace, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmBracebodyNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBracebodyNode should have type SmNodeType::Bracebody", + SmNodeType::Bracebody, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmOperNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmOperNode should have type SmNodeType::Oper", + SmNodeType::Oper, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmAlignNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmAlignNode should have type SmNodeType::Align", + SmNodeType::Align, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmAttributNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmAttributNode should have type SmNodeType::Attribut", + SmNodeType::Attribut, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmFontNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmFontNode should have type SmNodeType::Font", + SmNodeType::Font, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmUnHorNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmUnHorNode should have type SmNodeType::UnHor", + SmNodeType::UnHor, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmBinHorNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBinHorNode should have type SmNodeType::BinHor", + SmNodeType::BinHor, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmBinVerNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBinVerNode should have type SmNodeType::BinVer", + SmNodeType::BinVer, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmBinDiagonalNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBinDiagonalNode should have type SmNodeType::BinDiagonal", + SmNodeType::BinDiagonal, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmSubSupNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmSubSupNode should have type SmNodeType::SubSup", + SmNodeType::SubSup, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmMatrixNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmMatrixNode should have type SmNodeType::Matrix", + SmNodeType::Matrix, pNode->GetType()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmMatrixNode's token should be of type TMATRIX", + TMATRIX, pNode->GetToken().eType); + VisitChildren( pNode ); + } + + void Visit( SmPlaceNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmPlaceNode should have type SmNodeType::Place", + SmNodeType::Place, pNode->GetType()); + } + + void Visit( SmTextNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmTextNode should have type SmNodeType::Text", + SmNodeType::Text, pNode->GetType()); + } + + void Visit( SmSpecialNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmSpecialNode should have type SmNodeType::Special", + SmNodeType::Special, pNode->GetType()); + } + + void Visit( SmGlyphSpecialNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmGlyphSpecialNode should have type SmNodeType::GlyphSpecial", + SmNodeType::GlyphSpecial, pNode->GetType()); + } + + void Visit( SmMathSymbolNode* pNode ) override { + CPPUNIT_ASSERT_MESSAGE("SmMathSymbolNode should have type SmNodeType::Math or SmNodeType::MathIdent", + pNode->GetType() == SmNodeType::Math || pNode->GetType() == SmNodeType::MathIdent); + } + + void Visit( SmBlankNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmBlankNode should have type SmNodeType::Blank", + SmNodeType::Blank, pNode->GetType()); + } + + void Visit( SmErrorNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmErrorNode should have type SmNodeType::Error", + SmNodeType::Error, pNode->GetType()); + } + + void Visit( SmLineNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmLineNode should have type SmNodeType::Line", + SmNodeType::Line, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmExpressionNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmExpressionNode should have type SmNodeType::Expression", + SmNodeType::Expression, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmPolyLineNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmPolyLineNode should have type SmNodeType::PolyLine", + SmNodeType::PolyLine, pNode->GetType()); + } + + void Visit( SmRootNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmRootNode should have type SmNodeType::Root", + SmNodeType::Root, pNode->GetType()); + VisitChildren( pNode ); + } + + void Visit( SmRootSymbolNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmRootSymbolNode should have type SmNodeType::RootSymbol", + SmNodeType::RootSymbol, pNode->GetType()); + } + + void Visit( SmRectangleNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmRectangleNode should have type SmNodeType::Rectangle", + SmNodeType::Rectangle, pNode->GetType()); + } + + void Visit( SmVerticalBraceNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmVerticalBraceNode should have type SmNodeType::VerticalBrace", + SmNodeType::VerticalBrace, pNode->GetType()); + VisitChildren( pNode ); + } + +private: + /** Auxiliary method for visiting the children of a pNode */ + void VisitChildren( SmStructureNode* pNode ) { + for (auto pChild : *pNode) + { + if (pChild) + pChild->Accept(this); + } + } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/cppunit/test_cursor.cxx b/starmath/qa/cppunit/test_cursor.cxx new file mode 100644 index 000000000..080e7a274 --- /dev/null +++ b/starmath/qa/cppunit/test_cursor.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <sal/config.h> +#include <test/bootstrapfixture.hxx> + +#include <vcl/virdev.hxx> +#include <sfx2/sfxmodelfactory.hxx> +#include <smdll.hxx> + +#include <document.hxx> +#include <node.hxx> +#include <cursor.hxx> + +#include <memory> + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +using namespace ::com::sun::star; + +namespace { + +class Test : public test::BootstrapFixture { + +public: + // init + virtual void setUp() override; + virtual void tearDown() override; + + // tests + void testCopyPaste(); + void testCopySelectPaste(); + void testCutPaste(); + void testCutSelectPaste(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testCopyPaste); + CPPUNIT_TEST(testCopySelectPaste); + CPPUNIT_TEST(testCutPaste); + CPPUNIT_TEST(testCutSelectPaste); + CPPUNIT_TEST_SUITE_END(); + +private: + SmDocShellRef xDocShRef; +}; + +void Test::setUp() +{ + BootstrapFixture::setUp(); + + SmGlobals::ensure(); + + xDocShRef = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT); +} + +void Test::tearDown() +{ + xDocShRef.clear(); + BootstrapFixture::tearDown(); +} + +void Test::testCopyPaste() +{ + OUString const sInput("a * b + c"); + auto xTree = SmParser().Parse(sInput); + xTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(xTree.get(), xDocShRef.get()); + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + + // go to the position at "*" + aCursor.Move(pOutputDevice, MoveRight); + // select "* b" and then copy + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Copy(); + // go to the right end and then paste + aCursor.Move(pOutputDevice, MoveRight); + aCursor.Move(pOutputDevice, MoveRight); + aCursor.Paste(); + + CPPUNIT_ASSERT_EQUAL(OUString(" { a * b + c * b } "), xDocShRef->GetText()); +} + +void Test::testCopySelectPaste() +{ + OUString const sInput("a * b + c"); + auto xTree = SmParser().Parse(sInput); + xTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(xTree.get(), xDocShRef.get()); + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + + // go to the right end + for (int i=0;i<5;i++) + aCursor.Move(pOutputDevice, MoveRight); + // select "b + c" and then copy + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Copy(); + // go to the left end + aCursor.Move(pOutputDevice, MoveLeft); + aCursor.Move(pOutputDevice, MoveLeft); + // select "a" and then paste + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Paste(); + + CPPUNIT_ASSERT_EQUAL(OUString(" { b + c * b + c } "), xDocShRef->GetText()); +} + +void Test::testCutPaste() +{ + OUString const sInput("a * b + c"); + auto xTree = SmParser().Parse(sInput); + xTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(xTree.get(), xDocShRef.get()); + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + + // go to the position at "*" + aCursor.Move(pOutputDevice, MoveRight); + // select "* b" and then cut + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Cut(); + // go to the left end and then paste + aCursor.Move(pOutputDevice, MoveRight); + aCursor.Move(pOutputDevice, MoveRight); + aCursor.Paste(); + + CPPUNIT_ASSERT_EQUAL(OUString(" { a + c * b } "), xDocShRef->GetText()); +} + +void Test::testCutSelectPaste() +{ + OUString const sInput("a * b + c"); + auto xTree = SmParser().Parse(sInput); + xTree->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + + SmCursor aCursor(xTree.get(), xDocShRef.get()); + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + + // go to the right end + for (int i=0;i<5;i++) + aCursor.Move(pOutputDevice, MoveRight); + // select "b + c" and then cut + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Move(pOutputDevice, MoveLeft, false); + aCursor.Cut(); + // go to the left end + aCursor.Move(pOutputDevice, MoveLeft); + aCursor.Move(pOutputDevice, MoveLeft); + // select "a" and then paste + aCursor.Move(pOutputDevice, MoveRight, false); + aCursor.Paste(); + + CPPUNIT_ASSERT_EQUAL(OUString(" { b + c * } "), xDocShRef->GetText()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/cppunit/test_node.cxx b/starmath/qa/cppunit/test_node.cxx new file mode 100644 index 000000000..dba0b9ff3 --- /dev/null +++ b/starmath/qa/cppunit/test_node.cxx @@ -0,0 +1,144 @@ +/* -*- 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 <sal/config.h> +#include <test/bootstrapfixture.hxx> + +#include <o3tl/cppunittraitshelper.hxx> +#include <sfx2/sfxmodelfactory.hxx> +#include <vcl/virdev.hxx> + +#include <document.hxx> +#include <smdll.hxx> +#include <node.hxx> +#include <parse.hxx> +#include <utility.hxx> + +#include <memory> + +namespace { + +using namespace ::com::sun::star; + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +class NodeTest : public test::BootstrapFixture +{ +public: + virtual void setUp() override; + virtual void tearDown() override; + +private: + void testTdf47813(); + void testTdf52225(); + + CPPUNIT_TEST_SUITE(NodeTest); + CPPUNIT_TEST(testTdf47813); + CPPUNIT_TEST(testTdf52225); + CPPUNIT_TEST_SUITE_END(); + + SmDocShellRef mxDocShell; +}; + +void NodeTest::setUp() +{ + BootstrapFixture::setUp(); + SmGlobals::ensure(); + mxDocShell = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT | + SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | + SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); +} + +void NodeTest::tearDown() +{ + if (mxDocShell.is()) + mxDocShell->DoClose(); + BootstrapFixture::tearDown(); +} + +void NodeTest::testTdf47813() +{ + SmParser aParser; +#define MATRIX "matrix {-2#33##4#-5##6,0#7}" + auto pNodeA = aParser.Parse(MATRIX); + auto pNodeC = aParser.Parse("alignc " MATRIX); + auto pNodeL = aParser.Parse("alignl " MATRIX); + auto pNodeR = aParser.Parse("alignr " MATRIX); +#undef MATRIX + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + SmFormat aFmt; + pNodeA->Prepare(aFmt, *mxDocShell, 0); + pNodeA->Arrange(*pOutputDevice, aFmt); + pNodeC->Prepare(aFmt, *mxDocShell, 0); + pNodeC->Arrange(*pOutputDevice, aFmt); + pNodeL->Prepare(aFmt, *mxDocShell, 0); + pNodeL->Arrange(*pOutputDevice, aFmt); + pNodeR->Prepare(aFmt, *mxDocShell, 0); + pNodeR->Arrange(*pOutputDevice, aFmt); + long nWidthA = pNodeA->GetRect().GetWidth(); + long nWidthC = pNodeC->GetRect().GetWidth(); + long nWidthL = pNodeL->GetRect().GetWidth(); + long nWidthR = pNodeR->GetRect().GetWidth(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, nWidthC/static_cast<double>(nWidthA), 0.01); + // these values appear to change slightly with display scaling + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, nWidthL/static_cast<double>(nWidthA), 0.03); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, nWidthR/static_cast<double>(nWidthA), 0.03); +} + +void NodeTest::testTdf52225() +{ +#define CHECK_GREEK_SYMBOL(text, code, bItalic) do { \ + mxDocShell->SetText(text); \ + const SmTableNode *pTree= mxDocShell->GetFormulaTree(); \ + CPPUNIT_ASSERT_EQUAL(size_t(1), pTree->GetNumSubNodes()); \ + const SmNode *pLine = pTree->GetSubNode(0); \ + CPPUNIT_ASSERT(pLine); \ + CPPUNIT_ASSERT_EQUAL(SmNodeType::Line, pLine->GetType()); \ + CPPUNIT_ASSERT_EQUAL(size_t(1), pLine->GetNumSubNodes()); \ + const SmNode *pNode = pLine->GetSubNode(0); \ + CPPUNIT_ASSERT(pNode); \ + CPPUNIT_ASSERT_EQUAL(SmNodeType::Special, pNode->GetType()); \ + const SmSpecialNode *pSn = static_cast<const SmSpecialNode *>(pNode); \ + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pSn->GetText().getLength()); \ + CPPUNIT_ASSERT_EQUAL(code, pSn->GetText()[0]); \ + CPPUNIT_ASSERT_EQUAL(OUString(text), pSn->GetToken().aText); \ + CPPUNIT_ASSERT_EQUAL(bItalic, IsItalic(pSn->GetFont())); \ + } while (false) + + SmFormat aFormat = mxDocShell->GetFormat(); + CPPUNIT_ASSERT_EQUAL(sal_Int16(2), aFormat.GetGreekCharStyle()); // default format = 2 + CHECK_GREEK_SYMBOL("%ALPHA", u'\x0391', false); + CHECK_GREEK_SYMBOL("%iALPHA", u'\x0391', true); + CHECK_GREEK_SYMBOL("%alpha", u'\x03b1', true); + CHECK_GREEK_SYMBOL("%ialpha", u'\x03b1', true); + + // mode 1 + aFormat.SetGreekCharStyle(1); + mxDocShell->SetFormat(aFormat); + CHECK_GREEK_SYMBOL("%BETA", u'\x0392', true); + CHECK_GREEK_SYMBOL("%iBETA", u'\x0392', true); + CHECK_GREEK_SYMBOL("%beta", u'\x03b2', true); + CHECK_GREEK_SYMBOL("%ibeta", u'\x03b2', true); + + // mode 0 + aFormat.SetGreekCharStyle(0); + mxDocShell->SetFormat(aFormat); + CHECK_GREEK_SYMBOL("%GAMMA", u'\x0393', false); + CHECK_GREEK_SYMBOL("%iGAMMA", u'\x0393', true); + CHECK_GREEK_SYMBOL("%gamma", u'\x03b3', false); + CHECK_GREEK_SYMBOL("%igamma", u'\x03b3', true); + +#undef CHECK_GREEK_SYMBOL +} + +CPPUNIT_TEST_SUITE_REGISTRATION(NodeTest); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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 <sal/config.h> +#include <test/bootstrapfixture.hxx> + +#include <vcl/virdev.hxx> +#include <sfx2/sfxmodelfactory.hxx> +#include <smdll.hxx> + +#include <document.hxx> +#include <node.hxx> +#include <visitors.hxx> +#include <cursor.hxx> + +#include "mock-visitor.hxx" +#include <memory> + +typedef tools::SvRef<SmDocShell> 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<MockVisitor> 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<MockVisitor> 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<MockVisitor> 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: */ diff --git a/starmath/qa/cppunit/test_parse.cxx b/starmath/qa/cppunit/test_parse.cxx new file mode 100644 index 000000000..ccc0f5478 --- /dev/null +++ b/starmath/qa/cppunit/test_parse.cxx @@ -0,0 +1,128 @@ +/* -*- 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 <sal/config.h> +#include <test/bootstrapfixture.hxx> + +#include <sfx2/sfxmodelfactory.hxx> + +#include <document.hxx> +#include <smdll.hxx> +#include <node.hxx> +#include <parse.hxx> + +#include <memory> + +namespace { + +using namespace ::com::sun::star; + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +class ParseTest : public test::BootstrapFixture +{ +public: + virtual void setUp() override; + virtual void tearDown() override; + +private: + void testMinus(); + void testNospace(); + + CPPUNIT_TEST_SUITE(ParseTest); + CPPUNIT_TEST(testMinus); + CPPUNIT_TEST(testNospace); + CPPUNIT_TEST_SUITE_END(); + + SmDocShellRef mxDocShell; +}; + +void ParseTest::setUp() +{ + BootstrapFixture::setUp(); + SmGlobals::ensure(); + mxDocShell = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT | + SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | + SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); +} + +void ParseTest::tearDown() +{ + if (mxDocShell.is()) + mxDocShell->DoClose(); + BootstrapFixture::tearDown(); +} + +/* + * This shows that input "-" is recognized as a separate token even when + * it is immediately followed by a number. + */ +void ParseTest::testMinus() +{ + auto pNode = SmParser().Parse("-1.2"); + CPPUNIT_ASSERT_EQUAL(size_t(1), pNode->GetNumSubNodes()); + const SmNode *pNode0 = pNode->GetSubNode(0); + CPPUNIT_ASSERT(pNode0); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Line, pNode0->GetType()); + CPPUNIT_ASSERT_EQUAL(size_t(1), pNode0->GetNumSubNodes()); + const SmNode *pNode00 = pNode0->GetSubNode(0); + CPPUNIT_ASSERT(pNode00); + CPPUNIT_ASSERT_EQUAL(SmNodeType::UnHor, pNode00->GetType()); + CPPUNIT_ASSERT_EQUAL(size_t(2), pNode00->GetNumSubNodes()); + const SmNode *pNode000 = pNode00->GetSubNode(0); + CPPUNIT_ASSERT(pNode000); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Math, pNode000->GetType()); + // GetText() vs GetToken().aText + CPPUNIT_ASSERT_EQUAL(OUString(MS_MINUS), + static_cast<const SmMathSymbolNode *>(pNode000)->GetText()); + CPPUNIT_ASSERT_EQUAL(OUString("-"), + static_cast<const SmMathSymbolNode *>(pNode000)->GetToken().aText); + const SmNode *pNode001 = pNode00->GetSubNode(1); + CPPUNIT_ASSERT(pNode001); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Text, pNode001->GetType()); + // GetText() vs GetToken().aText + CPPUNIT_ASSERT(static_cast<const SmTextNode *>(pNode001)->GetText().isEmpty()); + CPPUNIT_ASSERT_EQUAL(OUString("1.2"), + static_cast<const SmTextNode *>(pNode001)->GetToken().aText); +} + +/* + * This shows that "nospace" turns off the expression's IsUseExtraSpaces(), + * but leaves its descendants' flag on. + */ +void ParseTest::testNospace() +{ + auto pNode = SmParser().Parse("nospace{ nitalic d {F(x) G(x)} }"); + CPPUNIT_ASSERT_EQUAL(size_t(1), pNode->GetNumSubNodes()); + const SmNode *pNode0 = pNode->GetSubNode(0); + CPPUNIT_ASSERT(pNode0); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Line, pNode0->GetType()); + CPPUNIT_ASSERT_EQUAL(size_t(1), pNode0->GetNumSubNodes()); + const SmNode *pNode00 = pNode0->GetSubNode(0); + CPPUNIT_ASSERT(pNode00); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Expression, pNode00->GetType()); + CPPUNIT_ASSERT(!static_cast<const SmExpressionNode *>(pNode00)->IsUseExtraSpaces()); + CPPUNIT_ASSERT_EQUAL(size_t(2), pNode00->GetNumSubNodes()); + const SmNode *pNode000 = pNode00->GetSubNode(0); + CPPUNIT_ASSERT(pNode000); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Font, pNode000->GetType()); + CPPUNIT_ASSERT_EQUAL(OUString("nitalic"), + static_cast<const SmFontNode *>(pNode000)->GetToken().aText); + const SmNode *pNode001 = pNode00->GetSubNode(1); + CPPUNIT_ASSERT(pNode001); + CPPUNIT_ASSERT_EQUAL(SmNodeType::Expression, pNode001->GetType()); + CPPUNIT_ASSERT(static_cast<const SmExpressionNode *>(pNode001)->IsUseExtraSpaces()); + CPPUNIT_ASSERT_EQUAL(size_t(2), pNode00->GetNumSubNodes()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ParseTest); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/cppunit/test_starmath.cxx b/starmath/qa/cppunit/test_starmath.cxx new file mode 100644 index 000000000..e26bcd31b --- /dev/null +++ b/starmath/qa/cppunit/test_starmath.cxx @@ -0,0 +1,563 @@ +/* -*- 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 <sal/config.h> + +#include <config_features.h> +#include <vcl/print.hxx> + +#include <test/bootstrapfixture.hxx> + +#include <smdll.hxx> +#include <document.hxx> +#include <view.hxx> + +#include <tmpdevice.hxx> + +#include <sfx2/sfxmodelfactory.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> + +#include <editeng/editeng.hxx> + +#include <sfx2/zoomitem.hxx> +#include <starmath.hrc> +#include <memory> + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +using namespace ::com::sun::star; + +namespace { + +class Test : public test::BootstrapFixture +{ +public: + Test(); + + // init + virtual void setUp() override; + virtual void tearDown() override; + + // tests + void editUndoRedo(); + void editMarker(); + void editFailure(); + void ParseErrorUnexpectedToken(); + void ParseErrorPoundExpected(); + void ParseErrorColorExpected(); + void ParseErrorLgroupExpected(); + void ParseErrorRgroupExpected(); + void ParseErrorLbraceExpected(); + void ParseErrorRbraceExpected(); + void ParseErrorParentMismatch(); + void ParseErrorRightExpected(); + void ParseErrorFontExpected(); + void ParseErrorSizeExpected(); + void ParseErrorDoubleAlign(); + void ParseErrorDoubleSubsupscript(); + + void replacePlaceholder(); + void viewZoom(); + +#if HAVE_MORE_FONTS + void testSmTmpDeviceRestoreFont(); +#endif + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(editUndoRedo); + CPPUNIT_TEST(editMarker); + CPPUNIT_TEST(editFailure); + CPPUNIT_TEST(ParseErrorUnexpectedToken); + CPPUNIT_TEST(ParseErrorPoundExpected); + CPPUNIT_TEST(ParseErrorColorExpected); + CPPUNIT_TEST(ParseErrorLgroupExpected); + CPPUNIT_TEST(ParseErrorRgroupExpected); + CPPUNIT_TEST(ParseErrorLbraceExpected); + CPPUNIT_TEST(ParseErrorRbraceExpected); + CPPUNIT_TEST(ParseErrorParentMismatch); + CPPUNIT_TEST(ParseErrorRightExpected); + CPPUNIT_TEST(ParseErrorFontExpected); + CPPUNIT_TEST(ParseErrorSizeExpected); + CPPUNIT_TEST(ParseErrorDoubleAlign); + CPPUNIT_TEST(ParseErrorDoubleSubsupscript); + CPPUNIT_TEST(replacePlaceholder); + CPPUNIT_TEST(viewZoom); +#if HAVE_MORE_FONTS + CPPUNIT_TEST(testSmTmpDeviceRestoreFont); +#endif + CPPUNIT_TEST_SUITE_END(); + +private: + SfxBindings m_aBindings; + std::unique_ptr<SfxDispatcher> m_pDispatcher; + VclPtr<SmCmdBoxWindow> m_pSmCmdBoxWindow; + VclPtr<SmEditWindow> m_pEditWindow; + SmDocShellRef m_xDocShRef; + SmViewShell *m_pViewShell; +}; + +Test::Test() + : m_pViewShell(nullptr) +{ +} + +void Test::setUp() +{ + BootstrapFixture::setUp(); + + SmGlobals::ensure(); + + m_xDocShRef = new SmDocShell( + SfxModelFlags::EMBEDDED_OBJECT | + SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | + SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); + m_xDocShRef->DoInitNew(); + + SfxViewFrame *pViewFrame = SfxViewFrame::LoadHiddenDocument(*m_xDocShRef, SFX_INTERFACE_NONE); + + CPPUNIT_ASSERT_MESSAGE("Should have a SfxViewFrame", pViewFrame); + + m_pDispatcher.reset(new SfxDispatcher(pViewFrame)); + m_aBindings.SetDispatcher(m_pDispatcher.get()); + m_aBindings.EnterRegistrations(); + m_pSmCmdBoxWindow.reset(VclPtr<SmCmdBoxWindow>::Create(&m_aBindings, nullptr, nullptr)); + m_aBindings.LeaveRegistrations(); + m_pEditWindow = VclPtr<SmEditWindow>::Create(*m_pSmCmdBoxWindow); + m_pViewShell = m_pEditWindow->GetView(); + CPPUNIT_ASSERT_MESSAGE("Should have a SmViewShell", m_pViewShell); +} + +void Test::tearDown() +{ + m_pEditWindow.disposeAndClear(); + m_pSmCmdBoxWindow.disposeAndClear(); + m_pDispatcher.reset(); + m_xDocShRef->DoClose(); + m_xDocShRef.clear(); + + BootstrapFixture::tearDown(); +} + +#if HAVE_MORE_FONTS +void Test::testSmTmpDeviceRestoreFont() +{ + ScopedVclPtrInstance<Printer> pPrinter; + bool bUseMap100th_mm = true; + + OUString aFontName("Linux Libertine G"); + CPPUNIT_ASSERT(pPrinter->IsFontAvailable(aFontName)); + + vcl::Font aOriginalFont = pPrinter->GetFont(); + aOriginalFont.SetColor(COL_RED); + pPrinter->SetTextColor(COL_RED); + + vcl::Font aNewFont; + + { + SmTmpDevice aTmpDev(*pPrinter, bUseMap100th_mm); + + aNewFont = pPrinter->GetFont(); + aNewFont.SetFamilyName(aFontName); + aTmpDev.SetFont(aNewFont); + + CPPUNIT_ASSERT_EQUAL(aFontName, pPrinter->GetFont().GetFamilyName()); + CPPUNIT_ASSERT_EQUAL(COL_BLACK, pPrinter->GetTextColor()); + } + + CPPUNIT_ASSERT(aNewFont != pPrinter->GetFont()); + CPPUNIT_ASSERT_EQUAL(COL_RED, pPrinter->GetTextColor()); +} +#endif + +void Test::editMarker() +{ + { + OUString sMarkedText("<?> under <?> under <?>"); + m_pEditWindow->SetText(sMarkedText); + m_pEditWindow->Flush(); + OUString sFinalText = m_pEditWindow->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be equal text", sMarkedText, sFinalText); + } + + { + OUString const sTargetText("a under b under c"); + ESelection aSelection; + + m_pEditWindow->SelNextMark(); + m_pEditWindow->Delete(); + m_pEditWindow->InsertText("a"); + + m_pEditWindow->SelNextMark(); + m_pEditWindow->SelNextMark(); + m_pEditWindow->Delete(); + m_pEditWindow->InsertText("c"); + + // should be safe i.e. do nothing + m_pEditWindow->SelNextMark(); + aSelection = m_pEditWindow->GetSelection(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSelection.nStartPara); + CPPUNIT_ASSERT_EQUAL(sal_Int32(19), aSelection.nStartPos); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSelection.nEndPara); + CPPUNIT_ASSERT_EQUAL(sal_Int32(19), aSelection.nEndPos); + + m_pEditWindow->SelPrevMark(); + m_pEditWindow->Delete(); + m_pEditWindow->InsertText("b"); + + // tdf#106116: should be safe i.e. do nothing + m_pEditWindow->SelPrevMark(); + aSelection = m_pEditWindow->GetSelection(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSelection.nStartPara); + CPPUNIT_ASSERT_EQUAL(sal_Int32(9), aSelection.nStartPos); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSelection.nEndPara); + CPPUNIT_ASSERT_EQUAL(sal_Int32(9), aSelection.nEndPos); + + m_pEditWindow->Flush(); + OUString sFinalText = m_pEditWindow->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be a under b under c", sTargetText, sFinalText); + } + + { + m_pEditWindow->SetText(OUString()); + m_pEditWindow->Flush(); + } +} + +void Test::editFailure() +{ + m_xDocShRef->SetText("color a b over {a/}"); + + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + + CPPUNIT_ASSERT_MESSAGE("Should be a SmParseError::ColorExpected", + pErrorDesc && pErrorDesc->m_eType == SmParseError::ColorExpected); + + pErrorDesc = m_xDocShRef->GetParser().PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be a SmParseError::UnexpectedChar", + pErrorDesc && pErrorDesc->m_eType == SmParseError::UnexpectedChar); + + pErrorDesc = m_xDocShRef->GetParser().PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be a SmParseError::RgroupExpected", + pErrorDesc && pErrorDesc->m_eType == SmParseError::RgroupExpected); + + const SmErrorDesc *pLastErrorDesc = m_xDocShRef->GetParser().PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be three syntax errors", + pLastErrorDesc && pLastErrorDesc == pErrorDesc); +} + +void Test::ParseErrorUnexpectedToken() +{ + m_xDocShRef->SetText("\\foo"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::UnexpectedToken expected", + SmParseError::UnexpectedToken, pErrorDesc->m_eType); +} + +void Test::ParseErrorPoundExpected() +{ + m_xDocShRef->SetText("matrix {1#2##a##b#c}"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::PoundExpected expected", + SmParseError::PoundExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorColorExpected() +{ + m_xDocShRef->SetText("color 42 x"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::ColorExpected expected", + SmParseError::ColorExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorLgroupExpected() +{ + m_xDocShRef->SetText("stack 42"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::LgroupExpected expected", + SmParseError::LgroupExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorRgroupExpected() +{ + m_xDocShRef->SetText("stack {a#b#c)"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::RgroupExpected expected", + SmParseError::RgroupExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorLbraceExpected() +{ + m_xDocShRef->SetText("left 42"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::LbraceExpected expected", + SmParseError::LbraceExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorRbraceExpected() +{ + m_xDocShRef->SetText("left ( foo right x"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::RbraceExpected expected", + SmParseError::RbraceExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorParentMismatch() +{ + m_xDocShRef->SetText("lbrace foo rceil"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::ParentMismatch expected", + SmParseError::ParentMismatch, pErrorDesc->m_eType); +} + +void Test::ParseErrorRightExpected() +{ + m_xDocShRef->SetText("left ( x mline y )"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::RightExpected expected", + SmParseError::RightExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorFontExpected() +{ + m_xDocShRef->SetText("font small bar"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::FontExpected expected", + SmParseError::FontExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorSizeExpected() +{ + m_xDocShRef->SetText("size small baz"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::SizeExpected expected", + SmParseError::SizeExpected, pErrorDesc->m_eType); +} + +void Test::ParseErrorDoubleAlign() +{ + m_xDocShRef->SetText("alignl alignc x"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::DoubleAlign expected", + SmParseError::DoubleAlign, pErrorDesc->m_eType); +} + +void Test::ParseErrorDoubleSubsupscript() +{ + m_xDocShRef->SetText("x_y_z"); + const SmErrorDesc *pErrorDesc = m_xDocShRef->GetParser().NextError(); + CPPUNIT_ASSERT(pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmParseError::DoubleSubsupscript expected", + SmParseError::DoubleSubsupscript, pErrorDesc->m_eType); +} + +void Test::editUndoRedo() +{ + EditEngine &rEditEngine = m_xDocShRef->GetEditEngine(); + + OUString sStringOne("a under b"); + { + rEditEngine.SetText(0, sStringOne); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Strings must match", sFinalText, sStringOne); + } + + OUString sStringTwo("a over b"); + { + rEditEngine.SetText(0, sStringTwo); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Strings must match", sFinalText, sStringTwo); + } + + SfxRequest aUndo(SID_UNDO, SfxCallMode::SYNCHRON, SmDocShell::GetPool()); + + { + m_xDocShRef->Execute(aUndo); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Strings much match", sFinalText, sStringOne); + } + + { + m_xDocShRef->Execute(aUndo); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_MESSAGE("Must now be empty", sFinalText.isEmpty()); + } + + SfxRequest aRedo(SID_REDO, SfxCallMode::SYNCHRON, SmDocShell::GetPool()); + { + m_xDocShRef->Execute(aRedo); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Strings much match", sFinalText, sStringOne); + } + + { + rEditEngine.SetText(0, OUString()); + m_xDocShRef->UpdateText(); + rEditEngine.ClearModifyFlag(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_MESSAGE("Must be empty", sFinalText.isEmpty()); + } + +} + +void Test::replacePlaceholder() +{ + // Test the placeholder replacement. In this case, testing 'a + b', it + // should return '+a + b' when selecting '+<?>' in ElementsDock + m_pEditWindow->SetText("a + b"); + m_pEditWindow->SelectAll(); + m_pEditWindow->InsertText("+<?>"); + OUString sFinalText = m_pEditWindow->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be '+a + b'", OUString("+a + b"), sFinalText); +} + +void Test::viewZoom() +{ + sal_uInt16 nOrigZoom, nNextZoom, nFinalZoom; + + EditEngine &rEditEngine = m_xDocShRef->GetEditEngine(); + + OUString sStringOne("a under b"); + { + rEditEngine.SetText(0, sStringOne); + m_xDocShRef->UpdateText(); + OUString sFinalText = m_xDocShRef->GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Strings must match", sFinalText, sStringOne); + } + + SmGraphicWindow &rGraphicWindow = m_pViewShell->GetGraphicWindow(); + rGraphicWindow.SetSizePixel(Size(1024, 800)); + nOrigZoom = rGraphicWindow.GetZoom(); + + { + SfxRequest aZoomIn(SID_ZOOMIN, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoomIn); + nNextZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should be bigger", nNextZoom > nOrigZoom); + } + + { + SfxRequest aZoomOut(SID_ZOOMOUT, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoomOut); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be equal", nOrigZoom, nFinalZoom); + } + + sal_uInt16 nOptimalZoom=0; + + { + SfxRequest aZoom(SID_ZOOM_OPTIMAL, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoom); + nOptimalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should be about 800%", nOptimalZoom > nOrigZoom); + } + + { + SfxItemSet aSet(SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{}); + aSet.Put(SvxZoomItem(SvxZoomType::OPTIMAL, 0)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be optimal zoom", nOptimalZoom, nFinalZoom); + } + +//To-Do: investigate GetPrinter logic of SvxZoomType::PAGEWIDTH/SvxZoomType::WHOLEPAGE to ensure +//consistent value regardless of +#if 0 + { + SfxRequest aZoomOut(SID_ZOOMOUT, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoomOut); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should not be optimal zoom", nFinalZoom != nOptimalZoom); + + SfxItemSet aSet(m_xDocShRef->GetPool(), SID_ATTR_ZOOM, SID_ATTR_ZOOM); + aSet.Put(SvxZoomItem(SvxZoomType::PAGEWIDTH, 0)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should be same as optimal zoom", nFinalZoom == nOptimalZoom); + } + + { + SfxRequest aZoomOut(SID_ZOOMOUT, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoomOut); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should not be optimal zoom", nFinalZoom != nOptimalZoom); + + SfxItemSet aSet(m_xDocShRef->GetPool(), SID_ATTR_ZOOM, SID_ATTR_ZOOM); + aSet.Put(SvxZoomItem(SvxZoomType::WHOLEPAGE, 0)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should be same as optimal zoom", nFinalZoom == nOptimalZoom); + } +#endif + + { + SfxRequest aZoomOut(SID_ZOOMOUT, SfxCallMode::SYNCHRON, m_pViewShell->GetPool()); + m_pViewShell->Execute(aZoomOut); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_MESSAGE("Should not be optimal zoom", nFinalZoom != nOptimalZoom); + + SfxItemSet aSet(SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{}); + aSet.Put(SvxZoomItem(SvxZoomType::PERCENT, 50)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be 50%", static_cast<sal_uInt16>(50), nFinalZoom); + } + + { + SfxItemSet aSet(SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{}); + aSet.Put(SvxZoomItem(SvxZoomType::PERCENT, 5)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be Clipped to 25%", static_cast<sal_uInt16>(25), nFinalZoom); + } + + { + SfxItemSet aSet(SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{}); + aSet.Put(SvxZoomItem(SvxZoomType::PERCENT, 1000)); + SfxRequest aZoom(SID_ATTR_ZOOM, SfxCallMode::SYNCHRON, aSet); + m_pViewShell->Execute(aZoom); + nFinalZoom = rGraphicWindow.GetZoom(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be Clipped to 800%", static_cast<sal_uInt16>(800), nFinalZoom); + } + +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |