summaryrefslogtreecommitdiffstats
path: root/oox/qa
diff options
context:
space:
mode:
Diffstat (limited to 'oox/qa')
-rw-r--r--oox/qa/token/tokenmap-test.cxx54
-rw-r--r--oox/qa/unit/CryptoTest.cxx426
-rw-r--r--oox/qa/unit/data/chart-data-label-char-color.docxbin0 -> 26014 bytes
-rw-r--r--oox/qa/unit/data/customshape-position.docxbin0 -> 42054 bytes
-rw-r--r--oox/qa/unit/data/gradient-multistep-transparency.pptxbin0 -> 34042 bytes
-rw-r--r--oox/qa/unit/data/graphic-stroke.pptxbin0 -> 29396 bytes
-rw-r--r--oox/qa/unit/data/group-spt202.docxbin0 -> 28238 bytes
-rw-r--r--oox/qa/unit/data/import-characters.pptxbin0 -> 33620 bytes
-rw-r--r--oox/qa/unit/data/import-mce.pptxbin0 -> 33763 bytes
-rw-r--r--oox/qa/unit/data/layout-flow-alt-alone.docxbin0 -> 7669 bytes
-rw-r--r--oox/qa/unit/data/multiple-group-shapes.docxbin0 -> 29653 bytes
-rw-r--r--oox/qa/unit/data/preset-adjust-value.pptxbin0 -> 33233 bytes
-rw-r--r--oox/qa/unit/data/shape-non-autosize-with-text.docxbin0 -> 35448 bytes
-rw-r--r--oox/qa/unit/data/shape-text-adjust-left.pptxbin0 -> 59199 bytes
-rw-r--r--oox/qa/unit/data/shape-text-alignment.pptxbin0 -> 30844 bytes
-rw-r--r--oox/qa/unit/data/tdf131082.pptxbin0 -> 25881 bytes
-rw-r--r--oox/qa/unit/data/transparent-text.pptxbin0 -> 32797 bytes
-rw-r--r--oox/qa/unit/data/vba/complex1.binbin0 -> 1086 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/complex1.binbin0 -> 579 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/simple1.binbin0 -> 18 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/simple2.binbin0 -> 13 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/simple3.bin1
-rw-r--r--oox/qa/unit/data/vba/reference/spec321.binbin0 -> 29 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/spec322.binbin0 -> 51 bytes
-rw-r--r--oox/qa/unit/data/vba/reference/spec323.binbin0 -> 7 bytes
-rw-r--r--oox/qa/unit/data/vba/simple1.binbin0 -> 13 bytes
-rw-r--r--oox/qa/unit/data/vba/simple2.binbin0 -> 11 bytes
-rw-r--r--oox/qa/unit/data/vba/simple3.bin1
-rw-r--r--oox/qa/unit/data/vba/spec321.bin1
-rw-r--r--oox/qa/unit/data/vba/spec322.bin1
-rw-r--r--oox/qa/unit/data/vba/spec323.bin1
-rw-r--r--oox/qa/unit/drawingml.cxx270
-rw-r--r--oox/qa/unit/mathml.cxx72
-rw-r--r--oox/qa/unit/shape.cxx93
-rw-r--r--oox/qa/unit/vba_compression.cxx255
-rw-r--r--oox/qa/unit/vba_encryption.cxx85
-rw-r--r--oox/qa/unit/vml.cxx146
37 files changed, 1406 insertions, 0 deletions
diff --git a/oox/qa/token/tokenmap-test.cxx b/oox/qa/token/tokenmap-test.cxx
new file mode 100644
index 000000000..4f617189b
--- /dev/null
+++ b/oox/qa/token/tokenmap-test.cxx
@@ -0,0 +1,54 @@
+/* -*- 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 <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <oox/token/tokenmap.hxx>
+#include <oox/token/tokens.hxx>
+
+using namespace std;
+using namespace com::sun::star::uno;
+
+namespace oox {
+
+class TokenmapTest: public CppUnit::TestFixture
+{
+public:
+ void test_roundTrip();
+
+ CPPUNIT_TEST_SUITE(TokenmapTest);
+
+ CPPUNIT_TEST(test_roundTrip);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ TokenMap tokenMap;
+};
+
+void TokenmapTest::test_roundTrip()
+{
+ for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken )
+ {
+ // check that the getIdentifier <-> getToken roundtrip works
+ Sequence< sal_Int8 > rUtf8Name = tokenMap.getUtf8TokenName(nToken);
+ sal_Int32 ret = tokenMap.getTokenFromUTF8(
+ reinterpret_cast< const char * >(rUtf8Name.getConstArray()),
+ rUtf8Name.getLength() );
+ CPPUNIT_ASSERT_EQUAL(ret, nToken);
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TokenmapTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/oox/qa/unit/CryptoTest.cxx b/oox/qa/unit/CryptoTest.cxx
new file mode 100644
index 000000000..c4058619e
--- /dev/null
+++ b/oox/qa/unit/CryptoTest.cxx
@@ -0,0 +1,426 @@
+/* -*- 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 <cppunit/plugin/TestPlugIn.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+
+#include <algorithm>
+#include <tools/stream.hxx>
+#include <unotools/streamwrap.hxx>
+
+#include <oox/crypto/Standard2007Engine.hxx>
+#include <oox/crypto/AgileEngine.hxx>
+#include <oox/helper/binaryinputstream.hxx>
+#include <oox/helper/binaryoutputstream.hxx>
+
+using namespace css;
+
+class CryptoTest : public CppUnit::TestFixture
+{
+public:
+ void testCryptoHash();
+ void testRoundUp();
+ void testStandard2007();
+ void testAgileEncryptionVerifier();
+ void testAgileEncrpytionInfoWritingAndParsing();
+ void testAgileDataIntegrityHmacKey();
+ void testAgileEncryptingAndDecrypting();
+
+ CPPUNIT_TEST_SUITE(CryptoTest);
+ CPPUNIT_TEST(testCryptoHash);
+ CPPUNIT_TEST(testRoundUp);
+ CPPUNIT_TEST(testStandard2007);
+ CPPUNIT_TEST(testAgileEncryptionVerifier);
+ CPPUNIT_TEST(testAgileEncrpytionInfoWritingAndParsing);
+ CPPUNIT_TEST(testAgileDataIntegrityHmacKey);
+ CPPUNIT_TEST(testAgileEncryptingAndDecrypting);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+namespace
+{
+std::string toString(std::vector<sal_uInt8> const& aInput)
+{
+ std::stringstream aStream;
+ for (auto const& aValue : aInput)
+ {
+ aStream << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(aValue);
+ }
+
+ return aStream.str();
+}
+}
+
+void CryptoTest::testCryptoHash()
+{
+ // Check examples from Wikipedia (https://en.wikipedia.org/wiki/HMAC)
+ OString aContentString("The quick brown fox jumps over the lazy dog");
+ std::vector<sal_uInt8> aContent(aContentString.getStr(),
+ aContentString.getStr() + aContentString.getLength());
+ std::vector<sal_uInt8> aKey = { 'k', 'e', 'y' };
+ {
+ oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA1);
+ aCryptoHash.update(aContent);
+ std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+ CPPUNIT_ASSERT_EQUAL(std::string("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"),
+ toString(aHash));
+ }
+
+ {
+ oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA256);
+ aCryptoHash.update(aContent);
+ std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"),
+ toString(aHash));
+ }
+
+ {
+ oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA512);
+ aCryptoHash.update(aContent);
+ std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549"
+ "f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a"),
+ toString(aHash));
+ }
+}
+
+void CryptoTest::testRoundUp()
+{
+ CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(16, 16));
+ CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(32, 16));
+ CPPUNIT_ASSERT_EQUAL(64, oox::crypto::roundUp(64, 16));
+
+ CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(01, 16));
+ CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(17, 16));
+ CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(31, 16));
+}
+
+void CryptoTest::testStandard2007()
+{
+ oox::crypto::Standard2007Engine aEngine;
+ {
+ aEngine.setupEncryption("Password");
+
+ SvMemoryStream aEncryptionInfo;
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), false);
+
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(224), aEncryptionInfo.GetSize());
+ }
+
+ SvMemoryStream aUnencryptedInput;
+ SvMemoryStream aEncryptedStream;
+
+ OString aTestString = OUStringToOString("1234567890ABCDEFG", RTL_TEXTENCODING_UTF8);
+
+ aUnencryptedInput.WriteBytes(aTestString.getStr(), aTestString.getLength() + 1);
+ aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
+ uno::Reference<io::XOutputStream> xOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
+
+ aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
+
+ xOutputStream->flush();
+
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>(aEncryptedStream.GetData());
+ sal_uInt64 nSize = aEncryptedStream.GetSize();
+
+ std::vector<sal_uInt8> aData(nSize);
+ std::copy(pData, pData + nSize, aData.data());
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(40), nSize);
+ }
+
+ aEncryptedStream.Seek(STREAM_SEEK_TO_BEGIN);
+ SvMemoryStream aUnencryptedOutput;
+
+ {
+ oox::BinaryXInputStream aBinaryInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptedStream), true);
+ oox::BinaryXOutputStream aBinaryOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aUnencryptedOutput), true);
+
+ aEngine.decrypt(aBinaryInputStream, aBinaryOutputStream);
+ aBinaryOutputStream.close();
+ aBinaryInputStream.close();
+
+ const char* pData = static_cast<const char*>(aUnencryptedOutput.GetData());
+ sal_uInt64 nSize = aUnencryptedOutput.GetSize();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(18), nSize);
+
+ OString aString(pData);
+
+ CPPUNIT_ASSERT_EQUAL(aTestString, aString);
+ }
+}
+
+void CryptoTest::testAgileEncryptionVerifier()
+{
+ oox::crypto::AgileEngine aEngine;
+
+ OUString aPassword("Password");
+
+ aEngine.setupEncryptionParameters({ 100000, 16, 128, 20, 16, OUString("AES"),
+ OUString("ChainingModeCBC"), OUString("SHA1") });
+
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+
+ aEngine.setupEncryptionParameters({ 100000, 16, 256, 64, 16, OUString("AES"),
+ OUString("ChainingModeCBC"), OUString("SHA512") });
+
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+}
+
+void CryptoTest::testAgileEncrpytionInfoWritingAndParsing()
+{
+ OUString aPassword("Password");
+ std::vector<sal_uInt8> aKeyDataSalt;
+
+ { // Preset AES128 - SHA1
+ SvMemoryStream aEncryptionInfo;
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_128_SHA1);
+ aEngine.setupEncryption(aPassword);
+ aKeyDataSalt = aEngine.getInfo().keyDataSalt;
+
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(996), aEncryptionInfo.GetSize());
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+
+ oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(128), rInfo.keyBits);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(20), rInfo.hashSize);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
+ CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
+ CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), rInfo.cipherChaining);
+ CPPUNIT_ASSERT_EQUAL(OUString("SHA1"), rInfo.hashAlgorithm);
+ CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
+
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+ }
+ }
+
+ { // Preset AES256 - SHA512
+ SvMemoryStream aEncryptionInfo;
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_256_SHA512);
+ aEngine.setupEncryption(aPassword);
+ aKeyDataSalt = aEngine.getInfo().keyDataSalt;
+
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(1112), aEncryptionInfo.GetSize());
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+
+ oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(256), rInfo.keyBits);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(64), rInfo.hashSize);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
+ CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
+ CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), rInfo.cipherChaining);
+ CPPUNIT_ASSERT_EQUAL(OUString("SHA512"), rInfo.hashAlgorithm);
+ CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
+
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+ }
+ }
+}
+
+void CryptoTest::testAgileDataIntegrityHmacKey()
+{
+ OUString aPassword("Password");
+
+ std::vector<sal_uInt8> aKeyDataSalt;
+
+ std::vector<sal_uInt8> aHmacKey;
+ std::vector<sal_uInt8> aHmacEncryptedKey;
+
+ SvMemoryStream aEncryptionInfo;
+ {
+ oox::crypto::AgileEngine aEngine;
+ aEngine.setupEncryption(aPassword);
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+
+ aHmacKey = aEngine.getInfo().hmacKey;
+ aKeyDataSalt = aEngine.getInfo().keyDataSalt;
+ aHmacEncryptedKey = aEngine.getInfo().hmacEncryptedKey;
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+ CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
+
+ CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(aEngine.getInfo().keyDataSalt));
+
+ CPPUNIT_ASSERT_EQUAL(toString(aHmacEncryptedKey),
+ toString(aEngine.getInfo().hmacEncryptedKey));
+
+ CPPUNIT_ASSERT_EQUAL(size_t(64), aHmacKey.size());
+ CPPUNIT_ASSERT_EQUAL(toString(aHmacKey), toString(aEngine.getInfo().hmacKey));
+ }
+}
+
+void CryptoTest::testAgileEncryptingAndDecrypting()
+{
+ OUString aPassword("Password");
+
+ SvMemoryStream aEncryptionInfo;
+ SvMemoryStream aEncryptedStream;
+
+ OString aTestString = OUStringToOString("1234567890ABCDEFGH", RTL_TEXTENCODING_UTF8);
+
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ // Setup input
+ SvMemoryStream aUnencryptedInput;
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
+
+ aUnencryptedInput.WriteBytes(aTestString.getStr(), aTestString.getLength() + 1);
+ aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
+
+ // Setup output
+ uno::Reference<io::XOutputStream> xOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
+
+ // Write content
+ aEngine.setupEncryption(aPassword);
+ aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
+ xOutputStream->flush();
+
+ // Check content
+ sal_uInt64 nSize = aEncryptedStream.GetSize();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(40), nSize);
+
+ // Setup and write encryption info
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+ }
+
+ aEncryptedStream.Seek(STREAM_SEEK_TO_BEGIN);
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::crypto::AgileEngine aEngine;
+
+ // Read encryption info
+ uno::Reference<io::XInputStream> xEncryptionInfo(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xEncryptionInfo->skipBytes(4); // Encryption type -> Agile
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xEncryptionInfo));
+
+ // Setup password
+ CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
+
+ // Setup encrypted input stream
+ oox::BinaryXInputStream aBinaryInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptedStream), true);
+
+ // Setup output stream
+ SvMemoryStream aUnencryptedOutput;
+ oox::BinaryXOutputStream aBinaryOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aUnencryptedOutput), true);
+
+ // Decrypt
+ aEngine.decrypt(aBinaryInputStream, aBinaryOutputStream);
+ aBinaryOutputStream.close();
+ aBinaryInputStream.close();
+
+ // Check decrypted output
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(19), aUnencryptedOutput.GetSize());
+
+ OString aString(static_cast<const char*>(aUnencryptedOutput.GetData()));
+ CPPUNIT_ASSERT_EQUAL(aTestString, aString);
+
+ // Check data integrity
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.checkDataIntegrity());
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/data/chart-data-label-char-color.docx b/oox/qa/unit/data/chart-data-label-char-color.docx
new file mode 100644
index 000000000..0e389f923
--- /dev/null
+++ b/oox/qa/unit/data/chart-data-label-char-color.docx
Binary files differ
diff --git a/oox/qa/unit/data/customshape-position.docx b/oox/qa/unit/data/customshape-position.docx
new file mode 100644
index 000000000..227928f20
--- /dev/null
+++ b/oox/qa/unit/data/customshape-position.docx
Binary files differ
diff --git a/oox/qa/unit/data/gradient-multistep-transparency.pptx b/oox/qa/unit/data/gradient-multistep-transparency.pptx
new file mode 100644
index 000000000..83946c71b
--- /dev/null
+++ b/oox/qa/unit/data/gradient-multistep-transparency.pptx
Binary files differ
diff --git a/oox/qa/unit/data/graphic-stroke.pptx b/oox/qa/unit/data/graphic-stroke.pptx
new file mode 100644
index 000000000..f4465476f
--- /dev/null
+++ b/oox/qa/unit/data/graphic-stroke.pptx
Binary files differ
diff --git a/oox/qa/unit/data/group-spt202.docx b/oox/qa/unit/data/group-spt202.docx
new file mode 100644
index 000000000..14bf00b50
--- /dev/null
+++ b/oox/qa/unit/data/group-spt202.docx
Binary files differ
diff --git a/oox/qa/unit/data/import-characters.pptx b/oox/qa/unit/data/import-characters.pptx
new file mode 100644
index 000000000..293380236
--- /dev/null
+++ b/oox/qa/unit/data/import-characters.pptx
Binary files differ
diff --git a/oox/qa/unit/data/import-mce.pptx b/oox/qa/unit/data/import-mce.pptx
new file mode 100644
index 000000000..65cf1cbab
--- /dev/null
+++ b/oox/qa/unit/data/import-mce.pptx
Binary files differ
diff --git a/oox/qa/unit/data/layout-flow-alt-alone.docx b/oox/qa/unit/data/layout-flow-alt-alone.docx
new file mode 100644
index 000000000..59c2db23d
--- /dev/null
+++ b/oox/qa/unit/data/layout-flow-alt-alone.docx
Binary files differ
diff --git a/oox/qa/unit/data/multiple-group-shapes.docx b/oox/qa/unit/data/multiple-group-shapes.docx
new file mode 100644
index 000000000..c751bcdf6
--- /dev/null
+++ b/oox/qa/unit/data/multiple-group-shapes.docx
Binary files differ
diff --git a/oox/qa/unit/data/preset-adjust-value.pptx b/oox/qa/unit/data/preset-adjust-value.pptx
new file mode 100644
index 000000000..d1d570a19
--- /dev/null
+++ b/oox/qa/unit/data/preset-adjust-value.pptx
Binary files differ
diff --git a/oox/qa/unit/data/shape-non-autosize-with-text.docx b/oox/qa/unit/data/shape-non-autosize-with-text.docx
new file mode 100644
index 000000000..b9ae501f4
--- /dev/null
+++ b/oox/qa/unit/data/shape-non-autosize-with-text.docx
Binary files differ
diff --git a/oox/qa/unit/data/shape-text-adjust-left.pptx b/oox/qa/unit/data/shape-text-adjust-left.pptx
new file mode 100644
index 000000000..d197425b9
--- /dev/null
+++ b/oox/qa/unit/data/shape-text-adjust-left.pptx
Binary files differ
diff --git a/oox/qa/unit/data/shape-text-alignment.pptx b/oox/qa/unit/data/shape-text-alignment.pptx
new file mode 100644
index 000000000..ff4ff06f2
--- /dev/null
+++ b/oox/qa/unit/data/shape-text-alignment.pptx
Binary files differ
diff --git a/oox/qa/unit/data/tdf131082.pptx b/oox/qa/unit/data/tdf131082.pptx
new file mode 100644
index 000000000..dbe88126f
--- /dev/null
+++ b/oox/qa/unit/data/tdf131082.pptx
Binary files differ
diff --git a/oox/qa/unit/data/transparent-text.pptx b/oox/qa/unit/data/transparent-text.pptx
new file mode 100644
index 000000000..b7b3ede4d
--- /dev/null
+++ b/oox/qa/unit/data/transparent-text.pptx
Binary files differ
diff --git a/oox/qa/unit/data/vba/complex1.bin b/oox/qa/unit/data/vba/complex1.bin
new file mode 100644
index 000000000..390208290
--- /dev/null
+++ b/oox/qa/unit/data/vba/complex1.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/complex1.bin b/oox/qa/unit/data/vba/reference/complex1.bin
new file mode 100644
index 000000000..335b8e808
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/complex1.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/simple1.bin b/oox/qa/unit/data/vba/reference/simple1.bin
new file mode 100644
index 000000000..a4644fbb7
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/simple1.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/simple2.bin b/oox/qa/unit/data/vba/reference/simple2.bin
new file mode 100644
index 000000000..5de3f5ae0
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/simple2.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/simple3.bin b/oox/qa/unit/data/vba/reference/simple3.bin
new file mode 100644
index 000000000..a38e8a868
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/simple3.bin
@@ -0,0 +1 @@
+°
diff --git a/oox/qa/unit/data/vba/reference/spec321.bin b/oox/qa/unit/data/vba/reference/spec321.bin
new file mode 100644
index 000000000..3120c7f50
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/spec321.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/spec322.bin b/oox/qa/unit/data/vba/reference/spec322.bin
new file mode 100644
index 000000000..7724b62a4
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/spec322.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/reference/spec323.bin b/oox/qa/unit/data/vba/reference/spec323.bin
new file mode 100644
index 000000000..51104ee0b
--- /dev/null
+++ b/oox/qa/unit/data/vba/reference/spec323.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/simple1.bin b/oox/qa/unit/data/vba/simple1.bin
new file mode 100644
index 000000000..d59c1d5ef
--- /dev/null
+++ b/oox/qa/unit/data/vba/simple1.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/simple2.bin b/oox/qa/unit/data/vba/simple2.bin
new file mode 100644
index 000000000..1b9b88b16
--- /dev/null
+++ b/oox/qa/unit/data/vba/simple2.bin
Binary files differ
diff --git a/oox/qa/unit/data/vba/simple3.bin b/oox/qa/unit/data/vba/simple3.bin
new file mode 100644
index 000000000..72060e8a2
--- /dev/null
+++ b/oox/qa/unit/data/vba/simple3.bin
@@ -0,0 +1 @@
+
diff --git a/oox/qa/unit/data/vba/spec321.bin b/oox/qa/unit/data/vba/spec321.bin
new file mode 100644
index 000000000..c5d48c9fc
--- /dev/null
+++ b/oox/qa/unit/data/vba/spec321.bin
@@ -0,0 +1 @@
+abcdefghijklmnopqrstuv. \ No newline at end of file
diff --git a/oox/qa/unit/data/vba/spec322.bin b/oox/qa/unit/data/vba/spec322.bin
new file mode 100644
index 000000000..781c426c0
--- /dev/null
+++ b/oox/qa/unit/data/vba/spec322.bin
@@ -0,0 +1 @@
+#aaabcdefaaaaghijaaaaaklaaamnopqaaaaaaaaaaaarstuvwxyzaaa \ No newline at end of file
diff --git a/oox/qa/unit/data/vba/spec323.bin b/oox/qa/unit/data/vba/spec323.bin
new file mode 100644
index 000000000..9ca58b98a
--- /dev/null
+++ b/oox/qa/unit/data/vba/spec323.bin
@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ No newline at end of file
diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx
new file mode 100644
index 000000000..7fcee1756
--- /dev/null
+++ b/oox/qa/unit/drawingml.cxx
@@ -0,0 +1,270 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/tempfile.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Gets one child of xShape, which one is specified by nIndex.
+uno::Reference<drawing::XShape> getChildShape(const uno::Reference<drawing::XShape>& xShape,
+ sal_Int32 nIndex)
+{
+ uno::Reference<container::XIndexAccess> xGroup(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xGroup.is());
+
+ CPPUNIT_ASSERT(xGroup->getCount() > nIndex);
+
+ uno::Reference<drawing::XShape> xRet(xGroup->getByIndex(nIndex), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xRet.is());
+
+ return xRet;
+}
+}
+
+/// oox drawingml tests.
+class OoxDrawingmlTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+ void load(const OUString& rURL);
+ void loadAndReload(const OUString& rURL, const OUString& rFilterName);
+};
+
+void OoxDrawingmlTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void OoxDrawingmlTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+void OoxDrawingmlTest::load(const OUString& rURL) { mxComponent = loadFromDesktop(rURL); }
+
+void OoxDrawingmlTest::loadAndReload(const OUString& rURL, const OUString& rFilterName)
+{
+ load(rURL);
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= rFilterName;
+ utl::TempFile aTempFile;
+ xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ mxComponent->dispose();
+ validate(aTempFile.GetFileName(), test::OOXML);
+ mxComponent = loadFromDesktop(aTempFile.GetURL());
+}
+
+char const DATA_DIRECTORY[] = "/oox/qa/unit/data/";
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTransparentText)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "transparent-text.pptx";
+ loadAndReload(aURL, "Impress Office Open XML");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParagraph(
+ xShape->createEnumeration()->nextElement(), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPortion(xParagraph->createEnumeration()->nextElement(),
+ uno::UNO_QUERY);
+
+ sal_Int16 nTransparency = 0;
+ xPortion->getPropertyValue("CharTransparence") >>= nTransparency;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 75
+ // - Actual : 0
+ // i.e. the transparency of the character color was lost on import/export.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(75), nTransparency);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf131082)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf131082.pptx";
+ loadAndReload(aURL, "Impress Office Open XML");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> XPropSet(getChildShape(getChildShape(xShape, 0), 0),
+ uno::UNO_QUERY);
+
+ drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
+ XPropSet->getPropertyValue("FillStyle") >>= eFillStyle;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // with drawing::FillStyle_NONE - 0
+ CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, eFillStyle);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testPresetAdjustValue)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "preset-adjust-value.pptx";
+
+ load(aURL);
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aGeoPropSeq;
+ xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeoPropSeq;
+ comphelper::SequenceAsHashMap aGeoPropMap(aGeoPropSeq);
+ uno::Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentSeq;
+ aGeoPropMap.getValue("AdjustmentValues") >>= aAdjustmentSeq;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aAdjustmentSeq.getLength());
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 11587
+ // - Actual : 10813
+ // i.e. the adjust value was set from the placeholder, not from the shape.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11587), aAdjustmentSeq[0].Value.get<sal_Int32>());
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testChartDataLabelCharColor)
+{
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "chart-data-label-char-color.docx";
+ load(aURL);
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<chart2::XChartDocument> xModel(xShape->getPropertyValue("Model"),
+ uno::UNO_QUERY);
+ uno::Reference<chart2::XCoordinateSystemContainer> xDiagram(xModel->getFirstDiagram(),
+ uno::UNO_QUERY);
+
+ uno::Reference<chart2::XChartTypeContainer> xCoordinateSystem(
+ xDiagram->getCoordinateSystems()[0], uno::UNO_QUERY);
+
+ uno::Reference<chart2::XDataSeriesContainer> xChartType(xCoordinateSystem->getChartTypes()[0],
+ uno::UNO_QUERY);
+
+ uno::Reference<chart2::XDataSeries> xDataSeries = xChartType->getDataSeries()[0];
+
+ uno::Reference<beans::XPropertySet> xDataPoint = xDataSeries->getDataPointByIndex(0);
+
+ uno::Sequence<uno::Reference<chart2::XDataPointCustomLabelField>> aLabels;
+ xDataPoint->getPropertyValue("CustomLabelFields") >>= aLabels;
+ uno::Reference<beans::XPropertySet> xLabel = aLabels[0];
+
+ sal_Int32 nCharColor = 0;
+ xLabel->getPropertyValue("CharColor") >>= nCharColor;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 16777215
+ // - Actual : -1
+ // i.e. the data label had no explicit (white) color.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xffffff), nCharColor);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testGradientMultiStepTransparency)
+{
+ // Load a document with a multi-step gradient.
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "gradient-multistep-transparency.pptx";
+ load(aURL);
+
+ // Check the end transparency of the gradient.
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Rectangle 4"), xShape->getName());
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ awt::Gradient aTransparence;
+ xShapeProps->getPropertyValue("FillTransparenceGradient") >>= aTransparence;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 16777215 (0xffffff)
+ // - Actual : 3487029 (0x353535)
+ // i.e. the end transparency was not 100%, but was 21%, leading to an unexpected visible line on
+ // the right of this shape.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xffffff), aTransparence.EndColor);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testShapeTextAlignment)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "shape-text-alignment.pptx";
+ load(aURL);
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nParaAdjust = -1;
+ CPPUNIT_ASSERT(xShape->getPropertyValue("ParaAdjust") >>= nParaAdjust);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 3
+ // i.e. text which is meant to be left-aligned was centered at a paragraph level.
+ CPPUNIT_ASSERT_EQUAL(style::ParagraphAdjust_LEFT,
+ static_cast<style::ParagraphAdjust>(nParaAdjust));
+}
+
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testShapeTextAdjustLeft)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "shape-text-adjust-left.pptx";
+ load(aURL);
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ drawing::TextHorizontalAdjust eAdjust;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 3 (center)
+ // - Actual : 1 (block)
+ // i.e. text was center-adjusted, not default-adjusted (~left).
+ CPPUNIT_ASSERT(xShape->getPropertyValue("TextHorizontalAdjust") >>= eAdjust);
+ CPPUNIT_ASSERT_EQUAL(drawing::TextHorizontalAdjust_BLOCK, eAdjust);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/mathml.cxx b/oox/qa/unit/mathml.cxx
new file mode 100644
index 000000000..bb629ccc9
--- /dev/null
+++ b/oox/qa/unit/mathml.cxx
@@ -0,0 +1,72 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+using namespace ::com::sun::star;
+
+/// oox mathml tests.
+class OoxMathmlTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void OoxMathmlTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void OoxMathmlTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+char const DATA_DIRECTORY[] = "/oox/qa/unit/data/";
+
+CPPUNIT_TEST_FIXTURE(OoxMathmlTest, testImportCharacters)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "import-characters.pptx";
+ // Without the accompanying fix in place, this failed with an assertion failure on import.
+ getComponent() = loadFromDesktop(aURL);
+ CPPUNIT_ASSERT(getComponent().is());
+}
+
+CPPUNIT_TEST_FIXTURE(OoxMathmlTest, testImportMce)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "import-mce.pptx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+
+ // Without the accompanying fix in place, this failed with:
+ // - Expected: 1
+ // - Actual : 2
+ // i.e. both the math object and its replacement image was imported, as two separate objects.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xDrawPage->getCount());
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/shape.cxx b/oox/qa/unit/shape.cxx
new file mode 100644
index 000000000..a57c779d0
--- /dev/null
+++ b/oox/qa/unit/shape.cxx
@@ -0,0 +1,93 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <rtl/math.hxx>
+
+using namespace ::com::sun::star;
+
+char const DATA_DIRECTORY[] = "/oox/qa/unit/data/";
+
+/// oox shape tests.
+class OoxShapeTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+ void load(const OUString& rURL);
+};
+
+void OoxShapeTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void OoxShapeTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+void OoxShapeTest::load(const OUString& rFileName)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName;
+ mxComponent = loadFromDesktop(aURL);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxShapeTest, testMultipleGroupShapes)
+{
+ load("multiple-group-shapes.docx");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 1
+ // i.e. the 2 group shapes from the document were imported as a single one.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xDrawPage->getCount());
+}
+
+CPPUNIT_TEST_FIXTURE(OoxShapeTest, testCustomshapePosition)
+{
+ load("customshape-position.docx");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+
+ sal_Int32 nY{};
+ xShape->getPropertyValue("VertOrientPosition") >>= nY;
+ // <wp:posOffset>581025</wp:posOffset> in the document.
+ sal_Int32 nExpected = rtl::math::round(581025.0 / 360);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1614
+ // - Actual : 0
+ // i.e. the position of the shape was lost on import due to the rounded corners.
+ CPPUNIT_ASSERT_EQUAL(nExpected, nY);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/vba_compression.cxx b/oox/qa/unit/vba_compression.cxx
new file mode 100644
index 000000000..bfe241c59
--- /dev/null
+++ b/oox/qa/unit/vba_compression.cxx
@@ -0,0 +1,255 @@
+/* -*- 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 <cppunit/plugin/TestPlugIn.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <osl/file.hxx>
+#include <oox/ole/vbaexport.hxx>
+#include <rtl/bootstrap.hxx>
+#include <tools/stream.hxx>
+#include <unotest/directories.hxx>
+#include <algorithm>
+
+class TestVbaCompression : public CppUnit::TestFixture
+{
+public:
+ // just a sequence of bytes that should not be compressed at all
+ void testSimple1();
+
+ // a sequence containing one subsequence that can be compressed
+ void testSimple2();
+
+ void testSimple3();
+
+ // real stream from a document
+ void testComplex1();
+
+ // tests taken from the VBA specification
+ // section 3.2
+
+ // section 3.2.1
+ void testSpec321();
+ // section 3.2.2
+ void testSpec322();
+ // section 3.2.3
+ void testSpec323();
+
+ CPPUNIT_TEST_SUITE(TestVbaCompression);
+ CPPUNIT_TEST(testSimple1);
+ CPPUNIT_TEST(testSimple2);
+ CPPUNIT_TEST(testSimple3);
+ CPPUNIT_TEST(testComplex1);
+ CPPUNIT_TEST(testSpec321);
+ CPPUNIT_TEST(testSpec322);
+ CPPUNIT_TEST(testSpec323);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ static OUString const & getDebugDirUrl() {
+ struct DebugDirUrl {
+ DebugDirUrl() : url("$UserInstallation/debug/") {
+ rtl::Bootstrap::expandMacros(url);
+ //TODO: provide an OUString -> OUString expansion function, and which throws on
+ // failure
+ auto e = osl::Directory::create(url);
+ CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e);
+ }
+ OUString url;
+ };
+ static DebugDirUrl url;
+ return url.url;
+ }
+
+ test::Directories m_directories;
+};
+
+namespace {
+
+void ReadFiles(const OUString& rTestFile, const OUString& rReference,
+ SvMemoryStream& rOutputMemoryStream, SvMemoryStream& rReferenceMemoryStream,
+ const OUString& rDebugPath)
+{
+ SvFileStream aInputStream(rTestFile, StreamMode::READ);
+ SvMemoryStream aInputMemoryStream(4096, 4096);
+ aInputMemoryStream.WriteStream(aInputStream);
+
+ VBACompression aCompression(rOutputMemoryStream, aInputMemoryStream);
+ aCompression.write();
+
+ SvFileStream aReferenceStream(rReference, StreamMode::READ);
+ rReferenceMemoryStream.WriteStream(aReferenceStream);
+
+ rOutputMemoryStream.Seek(0);
+ SvFileStream aDebugStream(rDebugPath, StreamMode::WRITE);
+ aDebugStream.WriteStream(rOutputMemoryStream);
+}
+
+}
+
+void TestVbaCompression::testSimple1()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/simple1.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/simple1.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream,
+ aReferenceMemoryStream, getDebugDirUrl() + "vba_debug.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testSimple2()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/simple2.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/simple2.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug2.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testSimple3()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/simple3.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/simple3.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug3.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testComplex1()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/complex1.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/complex1.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug_complex1.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testSpec321()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/spec321.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/spec321.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug_spec321.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testSpec322()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/spec322.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/spec322.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug_spec322.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+void TestVbaCompression::testSpec323()
+{
+ OUString aTestFile = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/spec323.bin");
+ OUString aReference = m_directories.getPathFromSrc("/oox/qa/unit/data/vba/reference/spec323.bin");
+
+ SvMemoryStream aOutputMemoryStream(4096, 4096);
+ SvMemoryStream aReferenceMemoryStream(4096, 4096);
+ ReadFiles(aTestFile, aReference, aOutputMemoryStream, aReferenceMemoryStream, getDebugDirUrl() + "vba_debug_spec323.bin");
+
+ CPPUNIT_ASSERT_EQUAL(aReferenceMemoryStream.GetSize(), aOutputMemoryStream.GetSize());
+
+ const sal_uInt8* pReferenceData = static_cast<const sal_uInt8*>( aReferenceMemoryStream.GetData() );
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>( aOutputMemoryStream.GetData() );
+
+ const sal_uInt64 nSize = std::min(aReferenceMemoryStream.GetSize(),
+ aOutputMemoryStream.GetSize());
+ for (sal_uInt64 i = 0; i < nSize; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(pReferenceData[i]), static_cast<int>(pData[i]));
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestVbaCompression);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/vba_encryption.cxx b/oox/qa/unit/vba_encryption.cxx
new file mode 100644
index 000000000..7e8a44cd9
--- /dev/null
+++ b/oox/qa/unit/vba_encryption.cxx
@@ -0,0 +1,85 @@
+/* -*- 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 <cppunit/plugin/TestPlugIn.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+
+#include <oox/ole/vbaexport.hxx>
+#include <algorithm>
+
+class TestVbaEncryption : public CppUnit::TestFixture
+{
+public:
+
+#if 0
+ // an initial test for the encryption taken from the spec
+ void testSimple1();
+
+ void testSimple2();
+#endif
+
+ void testProjKey1();
+
+ CPPUNIT_TEST_SUITE(TestVbaEncryption);
+ // CPPUNIT_TEST(testSimple1);
+ // CPPUNIT_TEST(testSimple2);
+ CPPUNIT_TEST(testProjKey1);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+#if 0
+void TestVbaEncryption::testSimple1()
+{
+ sal_uInt8 nSeed = 0x07;
+ sal_uInt8 nProjKey = 0xDF;
+ sal_uInt16 nLength = 0x04;
+ sal_uInt8 pData[] = { 0x00, 0x00, 0x00, 0x00 };
+
+ SvMemoryStream aEncryptedStream(4096, 4096);
+ VBAEncryption aEncryption(pData, nLength, aEncryptedStream,
+ &nSeed, nProjKey);
+ aEncryption.write();
+}
+
+void TestVbaEncryption::testSimple2()
+{
+ sal_uInt8 nSeed = 0x15;
+ sal_uInt8 nProjKey = 0xDF;
+ sal_uInt16 nLength = 0x01;
+ sal_uInt8 pData[] = { 0xFF };
+
+ SvMemoryStream aEncryptedStream(4096, 4096);
+ VBAEncryption aEncryption(pData, nLength, aEncryptedStream,
+ &nSeed, nProjKey);
+ aEncryption.write();
+ sal_uInt8 pExpectedData[] = "1517CAF1D6F9D7F9D706";
+ size_t length = sizeof(pExpectedData);
+ aEncryptedStream.Seek(0);
+ for (size_t i = 0; i < length; ++i)
+ {
+ unsigned char val = 0;
+ aEncryptedStream.ReadUChar(val);
+ CPPUNIT_ASSERT_EQUAL((int)pExpectedData[i], (int)sal_uInt8(val));
+ }
+}
+#endif
+
+void TestVbaEncryption::testProjKey1()
+{
+ OUString const aProjectID("{917DED54-440B-4FD1-A5C1-74ACF261E600}");
+ sal_uInt8 nProjKey = VBAEncryption::calculateProjKey(aProjectID);
+ CPPUNIT_ASSERT_EQUAL(int(0xdf), static_cast<int>(nProjKey));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestVbaEncryption);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/qa/unit/vml.cxx b/oox/qa/unit/vml.cxx
new file mode 100644
index 000000000..d43d2d564
--- /dev/null
+++ b/oox/qa/unit/vml.cxx
@@ -0,0 +1,146 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+
+using namespace ::com::sun::star;
+
+char const DATA_DIRECTORY[] = "/oox/qa/unit/data/";
+
+/// oox vml tests.
+class OoxVmlTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+ void load(const OUString& rURL);
+};
+
+void OoxVmlTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void OoxVmlTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+void OoxVmlTest::load(const OUString& rFileName)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName;
+ mxComponent = loadFromDesktop(aURL);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxVmlTest, testLayoutFlowAltAlone)
+{
+ // mso-layout-flow-alt:bottom-to-top without a matching layout-flow:vertical.
+ load("layout-flow-alt-alone.docx");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nWritingMode = 0;
+ xShape->getPropertyValue("WritingMode") >>= nWritingMode;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 5 [ BTLR ]
+ // - Actual : 4 [ PAGE ]
+ // i.e. in case layout-flow:vertical was missing, the text was not vertical.
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR, nWritingMode);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxVmlTest, testSpt202ShapeType)
+{
+ // Load a document with a groupshape, 2nd child is a <v:shape>, its type has o:spt set to 202
+ // (TextBox).
+ load("group-spt202.docx");
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xGroup(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(xGroup->getByIndex(1), uno::UNO_QUERY);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: com.sun.star.drawing.TextShape
+ // - Actual : com.sun.star.drawing.CustomShape
+ // and then the size of the group shape was incorrect, e.g. its right edge was outside the page
+ // boundaries.
+ CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.drawing.TextShape"), xShape->getShapeType());
+}
+
+CPPUNIT_TEST_FIXTURE(OoxVmlTest, testShapeNonAutosizeWithText)
+{
+ // Load a document which has a group shape, containing a single child.
+ // 17.78 cm is the full group shape width, 19431/64008 is the child shape's relative width inside
+ // that, so 5.3975 cm should be the shape width.
+ load("shape-non-autosize-with-text.docx");
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xGroup(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(xGroup->getByIndex(0), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Actual : 1115
+ // - Expected: 5398
+ // because the width was determined using its text size, not using the explicit size.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5398), xShape->getSize().Width);
+}
+
+CPPUNIT_TEST_FIXTURE(OoxVmlTest, testGraphicStroke)
+{
+ load("graphic-stroke.pptx");
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+
+ uno::Reference<beans::XPropertySet> xShape;
+ for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i)
+ {
+ uno::Reference<lang::XServiceInfo> xInfo(xDrawPage->getByIndex(i), uno::UNO_QUERY);
+ if (!xInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ continue;
+ }
+
+ xShape.set(xInfo, uno::UNO_QUERY);
+ break;
+ }
+ CPPUNIT_ASSERT(xShape.is());
+
+ drawing::LineStyle eLineStyle{};
+ xShape->getPropertyValue("LineStyle") >>= eLineStyle;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. line style was NONE, not SOLID.
+ CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_SOLID, eLineStyle);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */