diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /starmath/qa | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
22 files changed, 2530 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..ee17cf6f8 --- /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( SmAttributeNode* pNode ) override { + CPPUNIT_ASSERT_EQUAL_MESSAGE("SmAttributeNode should have type SmNodeType::Attribute", + SmNodeType::Attribute, 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..56c673c1b --- /dev/null +++ b/starmath/qa/cppunit/test_cursor.cxx @@ -0,0 +1,169 @@ +/* -*- 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 <parse5.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->DoClose(); + xDocShRef.clear(); + BootstrapFixture::tearDown(); +} + +void Test::testCopyPaste() +{ + auto xTree = SmParser5().Parse("a * b + c"); + 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() +{ + auto xTree = SmParser5().Parse("a * b + c"); + 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() +{ + auto xTree = SmParser5().Parse("a * b + c"); + 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() +{ + auto xTree = SmParser5().Parse("a * b + c"); + 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..f16f195aa --- /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 <parse5.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() +{ + SmParser5 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); + tools::Long nWidthA = pNodeA->GetRect().GetWidth(); + tools::Long nWidthC = pNodeC->GetRect().GetWidth(); + tools::Long nWidthL = pNodeL->GetRect().GetWidth(); + tools::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..6f714321d --- /dev/null +++ b/starmath/qa/cppunit/test_nodetotextvisitors.cxx @@ -0,0 +1,666 @@ +/* -*- 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 <parse5.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->DoClose(); + 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 = SmParser5().ParseExpression(input); + pNode1->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode1.get(), output1); + + // parse 2 + auto pNode2 = SmParser5().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 = SmParser5().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 = SmParser5().ParseExpression(sInput1); + pNode1->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode1.get(), sOutput1); + + // parse formula2 + OUString sInput2(formula2, strlen(formula2), RTL_TEXTENCODING_UTF8); + auto pNode2 = SmParser5().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 = SmParser5().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 = SmParser5().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 = SmParser5().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"); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("BinHor in SubSup", OUString("{ a ^ { b + c } + d }"), + xDocShRef->GetText()); +} + +void Test::testUnaryInMixedNumberAsNumerator() +{ + // set up a unary operator + auto pTree = SmParser5().Parse("- 1"); + 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"); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary in mixed number as Numerator", + OUString("{ 2 { - 1 over 2 } + 4 }"), 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; + auto pNode = SmParser5().ParseExpression(u"{ \U0001D44E }"); // non-BMP Unicode + pNode->Prepare(xDocShRef->GetFormat(), *xDocShRef, 0); + SmNodeToTextVisitor(pNode.get(), sOutput); + CPPUNIT_ASSERT_EQUAL(OUString(u"\U0001D44E"), 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..2171cde80 --- /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 <parse5.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 = SmParser5().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 = SmParser5().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..60eb85944 --- /dev/null +++ b/starmath/qa/cppunit/test_starmath.cxx @@ -0,0 +1,569 @@ +/* -*- 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_fonts.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; + 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_pViewShell = m_pSmCmdBoxWindow->GetView(); + CPPUNIT_ASSERT_MESSAGE("Should have a SmViewShell", m_pViewShell); +} + +void Test::tearDown() +{ + m_pSmCmdBoxWindow.disposeAndClear(); + m_pDispatcher.reset(); + m_xDocShRef->DoClose(); + m_xDocShRef.clear(); + + BootstrapFixture::tearDown(); +} + +#if HAVE_MORE_FONTS +void Test::testSmTmpDeviceRestoreFont() +{ + ScopedVclPtrInstance<Printer> pPrinter; + + 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; + + { + bool bUseMap100th_mm = true; + 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() +{ + SmEditWindow& rEditWindow = m_pSmCmdBoxWindow->GetEditWindow(); + { + OUString sMarkedText("<?> under <?> under <?>"); + rEditWindow.SetText(sMarkedText); + rEditWindow.Flush(); + OUString sFinalText = rEditWindow.GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be equal text", sMarkedText, sFinalText); + } + + { + ESelection aSelection; + + rEditWindow.SelNextMark(); + rEditWindow.Delete(); + rEditWindow.InsertText("a"); + + rEditWindow.SelNextMark(); + rEditWindow.SelNextMark(); + rEditWindow.Delete(); + rEditWindow.InsertText("c"); + + // should be safe i.e. do nothing + rEditWindow.SelNextMark(); + aSelection = rEditWindow.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); + + rEditWindow.SelPrevMark(); + rEditWindow.Delete(); + rEditWindow.InsertText("b"); + + // tdf#106116: should be safe i.e. do nothing + rEditWindow.SelPrevMark(); + aSelection = rEditWindow.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); + + rEditWindow.Flush(); + OUString sFinalText = rEditWindow.GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be a under b under c", OUString("a under b under c"), sFinalText); + } + + { + rEditWindow.SetText(OUString()); + rEditWindow.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); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be a SmParseError::ColorExpected", + SmParseError::ColorExpected, pErrorDesc->m_eType); + + pErrorDesc = m_xDocShRef->GetParser()->PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be a SmParseError::UnexpectedChar", + pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be a SmParseError::UnexpectedChar", + SmParseError::UnexpectedChar, pErrorDesc->m_eType); + + pErrorDesc = m_xDocShRef->GetParser()->PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be a SmParseError::RgroupExpected", + pErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be a SmParseError::RgroupExpected", + SmParseError::RgroupExpected, pErrorDesc->m_eType); + + const SmErrorDesc *pLastErrorDesc = m_xDocShRef->GetParser()->PrevError(); + + CPPUNIT_ASSERT_MESSAGE("Should be three syntax errors", + pLastErrorDesc); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be three syntax errors", + pErrorDesc, pLastErrorDesc); +} + +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() +{ + SmEditWindow& rEditWindow = m_pSmCmdBoxWindow->GetEditWindow(); + // Test the placeholder replacement. In this case, testing 'a + b', it + // should return '+a + b' when selecting '+<?>' in ElementsDock + rEditWindow.SetText("a + b"); + rEditWindow.SelectAll(); + rEditWindow.InsertText("+<?>"); + OUString sFinalText = rEditWindow.GetText(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be '+a + b'", OUString("+a + b"), sFinalText); +} + +void Test::viewZoom() +{ + sal_uInt16 nOrigZoom, 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); + sal_uInt16 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: */ diff --git a/starmath/qa/extras/data/color.mml b/starmath/qa/extras/data/color.mml new file mode 100644 index 000000000..41294eff8 --- /dev/null +++ b/starmath/qa/extras/data/color.mml @@ -0,0 +1,24 @@ +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <mrow> + <mi mathcolor="black">b</mi> + <mi mathcolor="white">w</mi> + <mi mathcolor="red">r</mi> + <mi mathcolor="green">g</mi> + <mi mathcolor="blue">b</mi> + <mi mathcolor="yellow">y</mi> + <mi mathcolor="silver">s</mi> + <mi mathcolor="gray">g</mi> + <mi mathcolor="maroon">m</mi> + <mi mathcolor="purple">p</mi> + <mi mathcolor="lime">l</mi> + <mi mathcolor="olive">o</mi> + <mi mathcolor="navy">n</mi> + <mi mathcolor="teal">t</mi> + <mi mathcolor="aqua">a</mi> + <mi mathcolor="fuchsia">f</mi> + <mi mathcolor="#DC143C">c</mi> + <mi mathcolor="#FFB781">a</mi> + <mi mathcolor="#FF0">y</mi> + <mi mathcolor="#DC143D">x</mi> + </mrow> +</math> diff --git a/starmath/qa/extras/data/maction.mml b/starmath/qa/extras/data/maction.mml new file mode 100644 index 000000000..365008799 --- /dev/null +++ b/starmath/qa/extras/data/maction.mml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <mrow> + <mtable> + <mtr><maction actiontype="toggle"><mn>1</mn><mn>0</mn><mn>0</mn></maction></mtr> + <mtr><maction actiontype="toggle" selection="2"><mn>0</mn><mn>2</mn><mn>0</mn></maction></mtr> + <mtr><maction actiontype="toggle" selection="3"><mn>0</mn><mn>0</mn><mn>3</mn></maction></mtr> + </mtable> + </mrow> +</math> diff --git a/starmath/qa/extras/data/mspace.mml b/starmath/qa/extras/data/mspace.mml new file mode 100644 index 000000000..190651094 --- /dev/null +++ b/starmath/qa/extras/data/mspace.mml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <mrow> + <mi>a</mi> + <mspace /> + <mi>b</mi> + <mspace width="2em" /> + <mi>c</mi> + <mspace width="5.5em" /> + <mi>d</mi> + </mrow> +</math> diff --git a/starmath/qa/extras/data/mthmlentities.mml b/starmath/qa/extras/data/mthmlentities.mml new file mode 100644 index 000000000..328d689ce --- /dev/null +++ b/starmath/qa/extras/data/mthmlentities.mml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> + <semantics> + <mi>σ</mi> + <mi>∞</mi> + <mi>∞</mi> + <mi>σ</mi> + </semantics> +</math> diff --git a/starmath/qa/extras/data/ns-prefix-math.mml b/starmath/qa/extras/data/ns-prefix-math.mml new file mode 100644 index 000000000..c4c961223 --- /dev/null +++ b/starmath/qa/extras/data/ns-prefix-math.mml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<math:math xmlns:math="http://www.w3.org/1998/Math/MathML"> + <math:msup> + <math:mfenced> + <math:mrow> + <math:mi>a</math:mi> + <math:mo>+</math:mo> + <math:mi>b</math:mi> + </math:mrow> + </math:mfenced> + <math:mn>2</math:mn> + </math:msup> +</math:math> diff --git a/starmath/qa/extras/data/simple.mml b/starmath/qa/extras/data/simple.mml new file mode 100644 index 000000000..822d1a709 --- /dev/null +++ b/starmath/qa/extras/data/simple.mml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <msup> + <mfenced> + <mrow> + <mi>a</mi> + <mo>+</mo> + <mi>b</mi> + </mrow> + </mfenced> + <mn>2</mn> + </msup> +</math> diff --git a/starmath/qa/extras/data/tdf103430.mml b/starmath/qa/extras/data/tdf103430.mml new file mode 100644 index 000000000..f8ea8f8d2 --- /dev/null +++ b/starmath/qa/extras/data/tdf103430.mml @@ -0,0 +1,17 @@ +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <mfrac> + <mrow> + <msup> + <mo form="prefix" rspace="0">d</mo> + <mn>2</mn> + </msup> + <mi mathvariant="normal" mathcolor="blue">y</mi> + </mrow> + <mrow> + <mstyle mathcolor="#ffb781"> + <mo fontstyle="italic" fontweight="bold" mathvariant="normal" form="prefix" rspace="0">d</mo> + </mstyle> + <mi fontfamily="serif" mathvariant="sans-serif-bold-italic" mathcolor="red">x</mi> + </mrow> + </mfrac> +</math> diff --git a/starmath/qa/extras/data/tdf103500.mml b/starmath/qa/extras/data/tdf103500.mml new file mode 100644 index 000000000..7c4966985 --- /dev/null +++ b/starmath/qa/extras/data/tdf103500.mml @@ -0,0 +1,41 @@ +<math xmlns="http://www.w3.org/1998/Math/MathML"> + <mrow> + <mrow> + <munderover> + <mo stretchy="false">∫</mo> + <mi>a</mi> + <mi>b</mi> + </munderover> + <mrow> + <mfrac> + <mn>1</mn> + <mi>x</mi> + </mfrac> + <mspace width="0.5em"/> + <mstyle mathvariant="normal"> + <mi mathvariant="normal">d</mi> + </mstyle> + <mi>x</mi> + </mrow> + </mrow> + <mo stretchy="false">=</mo> + <mrow> + <munderover> + <mo stretchy="true">∫</mo> + <mi>a</mi> + <mi>b</mi> + </munderover> + <mrow> + <mfrac> + <mn>1</mn> + <mi>y</mi> + </mfrac> + <mspace width="0.5em"/> + <mstyle mathvariant="normal"> + <mi mathvariant="normal">d</mi> + </mstyle> + <mi>y</mi> + </mrow> + </mrow> + </mrow> +</math> diff --git a/starmath/qa/extras/data/tdf137008.mml b/starmath/qa/extras/data/tdf137008.mml new file mode 100644 index 000000000..bc6ee25db --- /dev/null +++ b/starmath/qa/extras/data/tdf137008.mml @@ -0,0 +1 @@ +<math xmlns='http://www.w3.org/1998/Math/MathML'><mtable><mtr><mtd></mtd></mtr><mtr></mtr></mtable></math>
\ No newline at end of file diff --git a/starmath/qa/extras/data/tdf99556-1.mml b/starmath/qa/extras/data/tdf99556-1.mml new file mode 100644 index 000000000..0eae8b2df --- /dev/null +++ b/starmath/qa/extras/data/tdf99556-1.mml @@ -0,0 +1,3 @@ +<math xmlns="http://www.w3.org/1998/Math/MathML"> +<msqrt/> +</math> diff --git a/starmath/qa/extras/mmlexport-test.cxx b/starmath/qa/extras/mmlexport-test.cxx new file mode 100644 index 000000000..d41ba41e6 --- /dev/null +++ b/starmath/qa/extras/mmlexport-test.cxx @@ -0,0 +1,155 @@ +/* -*- 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 <o3tl/cppunittraitshelper.hxx> +#include <test/bootstrapfixture.hxx> +#include <test/xmltesttools.hxx> +#include <unotools/tempfile.hxx> + +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/sfxmodelfactory.hxx> + +#include <document.hxx> +#include <smdll.hxx> + +#include <memory> + +namespace +{ +using namespace ::com::sun::star; + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +class MathMLExportTest : public test::BootstrapFixture, public XmlTestTools +{ +public: + virtual void setUp() override; + virtual void tearDown() override; + + void testBlank(); + void testTdf97049(); + void testTdf101022(); + + CPPUNIT_TEST_SUITE(MathMLExportTest); + CPPUNIT_TEST(testBlank); + CPPUNIT_TEST(testTdf97049); + CPPUNIT_TEST(testTdf101022); + CPPUNIT_TEST_SUITE_END(); + +protected: + virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override; + +private: + xmlDocUniquePtr exportAndParse(); + + SmDocShellRef mxDocShell; +}; + +void MathMLExportTest::setUp() +{ + BootstrapFixture::setUp(); + SmGlobals::ensure(); + mxDocShell + = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS + | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); +} + +void MathMLExportTest::tearDown() +{ + if (mxDocShell.is()) + mxDocShell->DoClose(); + BootstrapFixture::tearDown(); +} + +void MathMLExportTest::registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) +{ + xmlXPathRegisterNs(pXmlXPathCtx, BAD_CAST("m"), BAD_CAST("http://www.w3.org/1998/Math/MathML")); +} + +xmlDocUniquePtr MathMLExportTest::exportAndParse() +{ + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + SfxMedium aStoreMedium(aTempFile.GetURL(), StreamMode::STD_WRITE); + std::shared_ptr<const SfxFilter> pExportFilter = SfxFilter::GetFilterByName(MATHML_XML); + aStoreMedium.SetFilter(pExportFilter); + CPPUNIT_ASSERT(mxDocShell->ConvertTo(aStoreMedium)); + aStoreMedium.Commit(); + xmlDocUniquePtr pDoc = parseXml(aTempFile); + CPPUNIT_ASSERT(pDoc); + return pDoc; +} + +void MathMLExportTest::testBlank() +{ + mxDocShell->SetText("x`y~~z"); + xmlDocUniquePtr pDoc = exportAndParse(); + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mspace[1]", "width", "0.5em"); + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mspace[2]", "width", "4em"); +} + +void MathMLExportTest::testTdf97049() +{ + mxDocShell->SetText("intd {{1 over x} dx}"); + xmlDocUniquePtr pDoc = exportAndParse(); + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mo[1]", "stretchy", "true"); + auto aContent = getXPathContent(pDoc, "/m:math/m:semantics/m:mrow/m:mo[1]"); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aContent.getLength()); + CPPUNIT_ASSERT_EQUAL(u'\x222B', aContent[0]); +} + +void MathMLExportTest::testTdf101022() +{ +#define CHECK_MATHVARIANT(capital, small) \ + do \ + { \ + mxDocShell->SetText("%GAMMA %iGAMMA {ital %GAMMA} {nitalic %iGAMMA} " \ + "%gamma %igamma {ital %gamma} {nitalic %igamma}"); \ + xmlDocUniquePtr pDoc = exportAndParse(); \ + if (capital) \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mi[1]", "mathvariant"); \ + else \ + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mi[1]", "mathvariant", "normal"); \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mstyle[1]/m:mi[1]", \ + "mathvariant"); \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mi[2]", "mathvariant"); \ + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mstyle[2]/m:mi[1]", "mathvariant", \ + "normal"); \ + if (small) \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mi[3]", "mathvariant"); \ + else \ + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mi[3]", "mathvariant", "normal"); \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mstyle[3]/m:mi[1]", \ + "mathvariant"); \ + assertXPathNoAttribute(pDoc, "/m:math/m:semantics/m:mrow/m:mi[4]", "mathvariant"); \ + assertXPath(pDoc, "/m:math/m:semantics/m:mrow/m:mstyle[4]/m:mi[1]", "mathvariant", \ + "normal"); \ + mxDocShell->SetText(""); \ + } while (false) + + CHECK_MATHVARIANT(false, true); // default mode 2 + + mxDocShell->SetGreekCharStyle(1); // mode 1 + CHECK_MATHVARIANT(true, true); + + mxDocShell->SetGreekCharStyle(0); // mode 0 + CHECK_MATHVARIANT(false, false); + +#undef CHECK_MATHVARIANT +} + +CPPUNIT_TEST_SUITE_REGISTRATION(MathMLExportTest); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/extras/mmlimport-test.cxx b/starmath/qa/extras/mmlimport-test.cxx new file mode 100644 index 000000000..323b0e0fb --- /dev/null +++ b/starmath/qa/extras/mmlimport-test.cxx @@ -0,0 +1,191 @@ +/* -*- 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 <comphelper/fileformat.h> + +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/sfxmodelfactory.hxx> + +#include <document.hxx> +#include <smdll.hxx> + +namespace +{ +using namespace ::com::sun::star; + +typedef tools::SvRef<SmDocShell> SmDocShellRef; + +class Test : public test::BootstrapFixture +{ +public: + virtual void setUp() override; + virtual void tearDown() override; + + void testColor(); + void testSimple(); + void testNsPrefixMath(); + void testMaction(); + void testMspace(); + void testtdf99556(); + void testTdf103430(); + void testTdf103500(); + void testTdf137008(); + void testMathmlEntities(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testColor); + CPPUNIT_TEST(testSimple); + CPPUNIT_TEST(testNsPrefixMath); + CPPUNIT_TEST(testMaction); + CPPUNIT_TEST(testMspace); + CPPUNIT_TEST(testtdf99556); + CPPUNIT_TEST(testTdf103430); + CPPUNIT_TEST(testTdf103500); + CPPUNIT_TEST(testTdf137008); + CPPUNIT_TEST(testMathmlEntities); + CPPUNIT_TEST_SUITE_END(); + +private: + void loadURL(const OUString& rURL) + { + // Cf. + // filter/source/config/fragments/filters/MathML_XML__Math_.xcu + auto pFilter = std::make_shared<SfxFilter>( + MATHML_XML, OUString(), + SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::TEMPLATE, + SotClipboardFormatId::STARCALC_8, "MathML 2.0", OUString(), OUString(), + "private:factory/smath*"); + pFilter->SetVersion(SOFFICE_FILEFORMAT_60); + + mxDocShell = new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT + | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS + | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); + + SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ); + pSrcMed->SetFilter(pFilter); + pSrcMed->UseInteractionHandler(false); + bool bLoaded = mxDocShell->DoLoad(pSrcMed); + CPPUNIT_ASSERT_MESSAGE( + OString("failed to load " + OUStringToOString(rURL, RTL_TEXTENCODING_UTF8)).getStr(), + bLoaded); + } + + SmDocShellRef mxDocShell; +}; + +void Test::setUp() +{ + BootstrapFixture::setUp(); + SmGlobals::ensure(); +} + +void Test::tearDown() +{ + if (mxDocShell.is()) + mxDocShell->DoClose(); + BootstrapFixture::tearDown(); +} + +void Test::testColor() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/color.mml")); + CPPUNIT_ASSERT_EQUAL(OUString("{ color black b" + " color white w" + " color red r" + " color green g" + " color blue b" + " color yellow y" + " color silver s" + " color gray g" + " color maroon m" + " color purple p" + " color lime l" + " color olive o" + " color navy n" + " color teal t" + " color aqua a" + " color fuchsia f" + " color crimson c" + " color dvip apricot" + " a color yellow y" + " color rgb 220 20 61 x }"), + mxDocShell->GetText()); +} + +void Test::testSimple() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/simple.mml")); + CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( { a + b } right ) ^ 2"), + mxDocShell->GetText()); +} + +void Test::testNsPrefixMath() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/ns-prefix-math.mml")); + CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( { a + b } right ) ^ 2"), + mxDocShell->GetText()); +} + +void Test::testMaction() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/maction.mml")); + CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("matrix{ 1 ## 2 ## 3 }"), + mxDocShell->GetText()); +} + +void Test::testMspace() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/mspace.mml")); + CPPUNIT_ASSERT_EQUAL(OUString("{ a b ~ c ~~``` d }"), mxDocShell->GetText()); +} + +void Test::testtdf99556() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/tdf99556-1.mml")); + CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("sqrt { }"), mxDocShell->GetText()); +} + +void Test::testTdf103430() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/tdf103430.mml")); + CPPUNIT_ASSERT_EQUAL(OUString("frac { { nitalic d ^ 2 nitalic color blue y } } { { color dvip " + "apricot nitalic d font sans bold italic color red x } }"), + mxDocShell->GetText()); +} + +void Test::testTdf103500() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/tdf103500.mml")); + CPPUNIT_ASSERT_EQUAL(OUString("{ { int csup b csub a { frac { 1 } { x } ` nitalic d x } } = { " + "intd csup b csub a { frac { 1 } { y } ` nitalic d y } } }"), + mxDocShell->GetText()); +} + +void Test::testTdf137008() +{ + // Without the fix in place, this test would have crashed + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/tdf137008.mml")); + CPPUNIT_ASSERT_EQUAL(OUString("matrix{ { } # ## # }"), mxDocShell->GetText()); +} +void Test::testMathmlEntities() +{ + loadURL(m_directories.getURLFromSrc(u"starmath/qa/extras/data/mthmlentities.mml")); + CPPUNIT_ASSERT_EQUAL(OUString(u"{ \u03C3 \u221E \u221E \u03C3 }"), mxDocShell->GetText()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/unit/data/starmath-dialogs-test.txt b/starmath/qa/unit/data/starmath-dialogs-test.txt new file mode 100644 index 000000000..70529fbad --- /dev/null +++ b/starmath/qa/unit/data/starmath-dialogs-test.txt @@ -0,0 +1,47 @@ +# -*- 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/. +# + +# This file contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in starmath for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on weld::Builder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work + +modules/smath/ui/printeroptions.ui +modules/smath/ui/smathsettings.ui +modules/smath/ui/fontdialog.ui +modules/smath/ui/fontsizedialog.ui +modules/smath/ui/fonttypedialog.ui +modules/smath/ui/spacingdialog.ui +modules/smath/ui/alignmentdialog.ui +modules/smath/ui/catalogdialog.ui +modules/smath/ui/symdefinedialog.ui +modules/smath/ui/savedefaultsdialog.ui +modules/smath/ui/dockingelements.ui diff --git a/starmath/qa/unit/starmath-dialogs-test.cxx b/starmath/qa/unit/starmath-dialogs-test.cxx new file mode 100644 index 000000000..11bcb1dd9 --- /dev/null +++ b/starmath/qa/unit/starmath-dialogs-test.cxx @@ -0,0 +1,61 @@ +/* -*- 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/screenshot_test.hxx> +#include <vcl/abstdlg.hxx> + +using namespace ::com::sun::star; + +/// Test opening a dialog in starmath +class StarmathDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override; + +public: + StarmathDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(StarmathDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +StarmathDialogsTest::StarmathDialogsTest() {} + +void StarmathDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr<VclAbstractDialog> StarmathDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void StarmathDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile(u"starmath/qa/unit/data/starmath-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(StarmathDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/qa/unoapi/knownissues.xcl b/starmath/qa/unoapi/knownissues.xcl new file mode 100644 index 000000000..2fedc6e55 --- /dev/null +++ b/starmath/qa/unoapi/knownissues.xcl @@ -0,0 +1,39 @@ +# +# 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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +### i23394 ### +sm.XMLImporter::com::sun::star::xml::sax::XDocumentHandler +sm.XMLMetaImporter::com::sun::star::xml::sax::XDocumentHandler + +### i88645 ### +sm.XMLExporter::com::sun::star::document::XFilter + +### i94322 ### +sm.SmEditAccessible::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### i94320 ### +sm.SmGraphicAccessible::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### i94275 ### +sm.SmGraphicAccessible::com::sun::star::accessibility::XAccessibleText + +### i111220 ### +sm.XMLMetaExporter::com::sun::star::document::XFilter + +### i112743 ### +sm.XMLSettingsExporter::com::sun::star::document::XFilter diff --git a/starmath/qa/unoapi/sm.sce b/starmath/qa/unoapi/sm.sce new file mode 100644 index 000000000..4e7b278a7 --- /dev/null +++ b/starmath/qa/unoapi/sm.sce @@ -0,0 +1,26 @@ +# +# 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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +-o sm.SmEditAccessible +-o sm.SmGraphicAccessible +-o sm.SmModel +-o sm.XMLExporter +-o sm.XMLImporter +-o sm.XMLMetaExporter +-o sm.XMLMetaImporter +-o sm.XMLSettingsExporter +-o sm.XMLSettingsImporter |