5de73f04f3
Change-Id: Ida1996dfffa106bf95fd064e8191b8033b4002f3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175336 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
864 lines
37 KiB
C++
864 lines
37 KiB
C++
/* -*- 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/unoapixml_test.hxx>
|
|
|
|
#include <string_view>
|
|
|
|
#include <libepubgen/libepubgen.h>
|
|
|
|
#include <com/sun/star/document/XFilter.hpp>
|
|
#include <com/sun/star/frame/XStorable.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
|
|
|
|
#include <comphelper/propertysequence.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <o3tl/safeint.hxx>
|
|
#include <unotools/docinfohelper.hxx>
|
|
#include <unotools/mediadescriptor.hxx>
|
|
#include <unotools/tempfile.hxx>
|
|
#include <unotools/ucbstreamhelper.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
namespace
|
|
{
|
|
/// Tests the EPUB export filter.
|
|
class EPUBExportTest : public UnoApiXmlTest
|
|
{
|
|
protected:
|
|
uno::Reference<packages::zip::XZipFileAccess2> mxZipFile;
|
|
OUString maFilterOptions;
|
|
|
|
public:
|
|
EPUBExportTest()
|
|
: UnoApiXmlTest(u"/writerperfect/qa/unit/data/writer/epubexport/"_ustr)
|
|
{
|
|
}
|
|
|
|
void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
|
|
void createDoc(std::u16string_view rFile,
|
|
const uno::Sequence<beans::PropertyValue>& rFilterData);
|
|
/// Parses a CSS representation of the stream named rName and returns it.
|
|
std::map<OUString, std::vector<OUString>> parseCss(const OUString& rName);
|
|
/// Looks up a key of a class in rCss.
|
|
static OUString getCss(std::map<OUString, std::vector<OUString>>& rCss, const OUString& rClass,
|
|
std::u16string_view rKey);
|
|
};
|
|
|
|
void EPUBExportTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
|
|
{
|
|
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dc"), BAD_CAST("http://purl.org/dc/elements/1.1/"));
|
|
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("opf"), BAD_CAST("http://www.idpf.org/2007/opf"));
|
|
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xhtml"), BAD_CAST("http://www.w3.org/1999/xhtml"));
|
|
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"), BAD_CAST("http://www.w3.org/2000/svg"));
|
|
}
|
|
|
|
void EPUBExportTest::createDoc(std::u16string_view rFile,
|
|
const uno::Sequence<beans::PropertyValue>& rFilterData)
|
|
{
|
|
// Import the bugdoc and export as EPUB.
|
|
loadFromFile(rFile);
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
aMediaDescriptor[u"FilterName"_ustr] <<= u"EPUB"_ustr;
|
|
if (maFilterOptions.isEmpty())
|
|
aMediaDescriptor[u"FilterData"_ustr] <<= rFilterData;
|
|
else
|
|
aMediaDescriptor[u"FilterOptions"_ustr] <<= maFilterOptions;
|
|
xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
mxZipFile = packages::zip::ZipFileAccess::createWithURL(m_xContext, maTempFile.GetURL());
|
|
}
|
|
|
|
std::map<OUString, std::vector<OUString>> EPUBExportTest::parseCss(const OUString& rName)
|
|
{
|
|
std::map<OUString, std::vector<OUString>> aRet;
|
|
|
|
uno::Reference<io::XInputStream> xInputStream(mxZipFile->getByName(rName), uno::UNO_QUERY);
|
|
std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
|
|
|
|
// Minimal CSS handler till orcus is up to our needs.
|
|
OString aLine;
|
|
OUString aRuleName;
|
|
while (!pStream->eof())
|
|
{
|
|
pStream->ReadLine(aLine);
|
|
if (aLine.endsWith("{"))
|
|
// '.name {' -> 'name'
|
|
aRuleName = OUString::fromUtf8(aLine.subView(1, aLine.getLength() - 3));
|
|
else if (aLine.endsWith(";"))
|
|
aRet[aRuleName].push_back(OUString::fromUtf8(aLine));
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
OUString EPUBExportTest::getCss(std::map<OUString, std::vector<OUString>>& rCss,
|
|
const OUString& rClass, std::u16string_view rKey)
|
|
{
|
|
OUString aRet;
|
|
|
|
auto it = rCss.find(rClass);
|
|
CPPUNIT_ASSERT(it != rCss.end());
|
|
|
|
for (const auto& rKeyValue : it->second)
|
|
{
|
|
OUString aKeyValue = rKeyValue.trim();
|
|
std::vector<OUString> aTokens = comphelper::string::split(aKeyValue, ':');
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aTokens.size());
|
|
if (o3tl::trim(aTokens[0]) == rKey)
|
|
{
|
|
aRet = aTokens[1].trim();
|
|
if (aRet.endsWith(";"))
|
|
// Ignore trailing semicolon.
|
|
aRet = aRet.copy(0, aRet.getLength() - 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testOutlineLevel)
|
|
{
|
|
createDoc(u"outline-level.fodt", {});
|
|
|
|
// Make sure that the output is split into two.
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0001.xhtml"_ustr));
|
|
// This failed, output was a single section.
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0002.xhtml"_ustr));
|
|
CPPUNIT_ASSERT(!mxZipFile->hasByName(u"OEBPS/sections/section0003.xhtml"_ustr));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testMimetype)
|
|
{
|
|
createDoc(u"hello.fodt", {});
|
|
|
|
// Check that the mime type is written uncompressed at the expected location.
|
|
SvFileStream aFileStream(maTempFile.GetURL(), StreamMode::READ);
|
|
SvMemoryStream aMemoryStream;
|
|
aMemoryStream.WriteStream(aFileStream);
|
|
OString aExpected("application/epub+zip"_ostr);
|
|
CPPUNIT_ASSERT(aMemoryStream.GetSize() > static_cast<sal_uInt64>(aExpected.getLength()) + 38);
|
|
|
|
OString aActual(static_cast<const char*>(aMemoryStream.GetData()) + 38, aExpected.getLength());
|
|
// This failed: actual data was some garbage, not the uncompressed mime type.
|
|
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
// Default is EPUB3.
|
|
assertXPath(mpXmlDoc, "/opf:package", "version", u"3.0");
|
|
|
|
// This was just "libepubgen/x.y.z", i.e. the LO version was missing.
|
|
OUString aGenerator
|
|
= getXPath(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@name='generator']", "content");
|
|
CPPUNIT_ASSERT(aGenerator.startsWith(utl::DocInfoHelper::GetGeneratorString()));
|
|
|
|
uno::Reference<lang::XMultiServiceFactory> xMSF(m_xContext->getServiceManager(),
|
|
uno::UNO_QUERY);
|
|
static constexpr OUString aServiceName(u"com.sun.star.comp.Writer.EPUBExportFilter"_ustr);
|
|
uno::Reference<document::XFilter> xFilter(xMSF->createInstance(aServiceName), uno::UNO_QUERY);
|
|
// Should result in no errors.
|
|
xFilter->cancel();
|
|
// We got back what we expected.
|
|
uno::Reference<lang::XServiceInfo> xServiceInfo(xFilter, uno::UNO_QUERY);
|
|
CPPUNIT_ASSERT_EQUAL(aServiceName, xServiceInfo->getImplementationName());
|
|
CPPUNIT_ASSERT(xServiceInfo->supportsService(u"com.sun.star.document.ExportFilter"_ustr));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testEPUB2)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ // Explicitly request EPUB2.
|
|
{ "EPUBVersion", uno::Any(static_cast<sal_Int32>(20)) } }));
|
|
createDoc(u"hello.fodt", aFilterData);
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
// This was 3.0, EPUBVersion filter option was ignored and we always emitted EPUB3.
|
|
assertXPath(mpXmlDoc, "/opf:package", "version", u"2.0");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testEPUBFixedLayout)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ // Explicitly request fixed layout.
|
|
{ "EPUBLayoutMethod",
|
|
uno::Any(static_cast<sal_Int32>(libepubgen::EPUB_LAYOUT_METHOD_FIXED)) } }));
|
|
createDoc(u"hello.fodt", aFilterData);
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
// This was missing, EPUBLayoutMethod filter option was ignored and we always emitted reflowable layout.
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='rendition:layout']",
|
|
u"pre-paginated");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testEPUBFixedLayoutOption)
|
|
{
|
|
// Explicitly request fixed layout, this time via FilterOptions.
|
|
maFilterOptions = "layout=fixed";
|
|
createDoc(u"hello.fodt", {});
|
|
|
|
// This failed, fixed layout was only working via the FilterData map.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='rendition:layout']",
|
|
u"pre-paginated");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testEPUBFixedLayoutImplicitBreak)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ // Explicitly request fixed layout.
|
|
{ "EPUBLayoutMethod",
|
|
uno::Any(static_cast<sal_Int32>(libepubgen::EPUB_LAYOUT_METHOD_FIXED)) } }));
|
|
createDoc(u"fxl-2page.fodt", aFilterData);
|
|
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0001.xhtml"_ustr));
|
|
// This was missing, implicit page break (as calculated by the layout) was lost on export.
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0002.xhtml"_ustr));
|
|
CPPUNIT_ASSERT(!mxZipFile->hasByName(u"OEBPS/sections/section0003.xhtml"_ustr));
|
|
|
|
// Make sure that fixed layout has chapter names in the navigation
|
|
// document.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/toc.xhtml"_ustr);
|
|
// This was 'Page 1' instead.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:li[1]/xhtml:a", u"First chapter");
|
|
assertXPathContent(mpXmlDoc, "//xhtml:li[2]/xhtml:a", u"Second chapter");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testPageBreakSplit)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ // Explicitly request split on page break (instead of on heading).
|
|
{ "EPUBSplitMethod",
|
|
uno::Any(static_cast<sal_Int32>(libepubgen::EPUB_SPLIT_METHOD_PAGE_BREAK)) } }));
|
|
createDoc(u"2pages.fodt", aFilterData);
|
|
|
|
// Make sure that the output is split into two.
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0001.xhtml"_ustr));
|
|
// This failed, output was a single section.
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/sections/section0002.xhtml"_ustr));
|
|
CPPUNIT_ASSERT(!mxZipFile->hasByName(u"OEBPS/sections/section0003.xhtml"_ustr));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testSpanAutostyle)
|
|
{
|
|
createDoc(u"span-autostyle.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[1]", "class", u"span0");
|
|
// This failed, it was still span1, i.e. the bold and the italic formatting
|
|
// did not differ.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class", u"span1");
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[3]", "class", u"span2");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testParaAutostyleCharProps)
|
|
{
|
|
createDoc(u"para-autostyle-char-props.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This failed, para-level char props were not exported.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[1]/xhtml:span", "class", u"span0");
|
|
assertXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span", "class", u"span1");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testMeta)
|
|
{
|
|
createDoc(u"meta.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
// This was "Unknown Author", <meta:initial-creator> was not handled.
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:creator", u"A U Thor");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", u"Title");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:language", u"hu");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='dcterms:modified']",
|
|
u"2017-09-27T09:51:19Z");
|
|
|
|
// Make sure that cover image next to the source document is picked up.
|
|
assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']",
|
|
"properties", u"cover-image");
|
|
assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']",
|
|
"media-type", u"image/png");
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/images/image0001.png"_ustr));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testMetaXMP)
|
|
{
|
|
createDoc(u"meta-xmp.fodt", {});
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
|
|
// These were the libepubgen default values, metadata from a matching .xmp file was not picked up.
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:identifier",
|
|
u"deadbeef-e394-4cd6-9b83-7172794612e5");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", u"unknown title from xmp");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:creator",
|
|
u"unknown author from xmp");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:language", u"nl");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='dcterms:modified']",
|
|
u"2016-11-20T17:16:07Z");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testMetaAPI)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ { "RVNGIdentifier", uno::Any(u"deadc0de-e394-4cd6-9b83-7172794612e5"_ustr) },
|
|
{ "RVNGTitle", uno::Any(u"unknown title from api"_ustr) },
|
|
{ "RVNGInitialCreator", uno::Any(u"unknown author from api"_ustr) },
|
|
{ "RVNGLanguage", uno::Any(u"hu"_ustr) },
|
|
{ "RVNGDate", uno::Any(u"2015-11-20T17:16:07Z"_ustr) } }));
|
|
createDoc(u"meta-xmp.fodt", aFilterData);
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
|
|
// These were values from XMP (deadbeef, etc.), not from API.
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:identifier",
|
|
u"deadc0de-e394-4cd6-9b83-7172794612e5");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:title", u"unknown title from api");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:creator",
|
|
u"unknown author from api");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/dc:language", u"hu");
|
|
assertXPathContent(mpXmlDoc, "/opf:package/opf:metadata/opf:meta[@property='dcterms:modified']",
|
|
u"2015-11-20T17:16:07Z");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testCoverImage)
|
|
{
|
|
OUString aCoverURL = createFileURL(u"meta.cover-image.png");
|
|
uno::Sequence<beans::PropertyValue> aFilterData(
|
|
comphelper::InitPropertySequence({ { "RVNGCoverImage", uno::Any(aCoverURL) } }));
|
|
createDoc(u"hello.fodt", aFilterData);
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
|
|
// Make sure that the explicitly set cover image is used.
|
|
// This failed, as the image was not part of the package.
|
|
assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']",
|
|
"properties", u"cover-image");
|
|
assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='images/image0001.png']",
|
|
"media-type", u"image/png");
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/images/image0001.png"_ustr));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testParaNamedstyle)
|
|
{
|
|
createDoc(u"para-namedstyle.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPath(mpXmlDoc, "//xhtml:p[1]", "class", u"para0");
|
|
// This failed, paragraph properties from style were not exported.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[2]", "class", u"para1");
|
|
|
|
// Test character properties from named paragraph style.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[1]/xhtml:span", "class", u"span0");
|
|
// This failed, character properties from paragraph style were not exported.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span", "class", u"span1");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testCharNamedstyle)
|
|
{
|
|
createDoc(u"char-namedstyle.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
|
|
// Test character properties from named text style.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[1]", "class", u"span0");
|
|
// This failed, character properties from text style were not exported.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class", u"span1");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testNamedStyleInheritance)
|
|
{
|
|
createDoc(u"named-style-inheritance.fodt", {});
|
|
|
|
// Find the CSS rule for the blue text.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
OUString aBlue = getXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span[2]", "class");
|
|
|
|
CPPUNIT_ASSERT_EQUAL(u"#0000ff"_ustr, EPUBExportTest::getCss(aCssDoc, aBlue, u"color"));
|
|
// This failed, the span only had the properties from its style, but not
|
|
// from the style's parent(s).
|
|
CPPUNIT_ASSERT_EQUAL(u"'Liberation Mono'"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aBlue, u"font-family"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testNestedSpan)
|
|
{
|
|
createDoc(u"nested-span.fodt", {});
|
|
|
|
// Check textural content of nested span.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
// This crashed, span had no content.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p/xhtml:span[2]", u"red");
|
|
|
|
// Check formatting of nested span.
|
|
OUString aRed = getXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class");
|
|
// This failed, direct formatting on top of named style was lost.
|
|
CPPUNIT_ASSERT_EQUAL(u"#ff0000"_ustr, EPUBExportTest::getCss(aCssDoc, aRed, u"color"));
|
|
CPPUNIT_ASSERT_EQUAL(u"'Liberation Mono'"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aRed, u"font-family"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testLineBreak)
|
|
{
|
|
createDoc(u"line-break.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This was 0, line break was not handled.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[1]/xhtml:span/xhtml:br", 1);
|
|
// This was 0, line break inside span was not handled.
|
|
assertXPath(mpXmlDoc, "//xhtml:p[2]/xhtml:span/xhtml:br", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testEscape)
|
|
{
|
|
createDoc(u"escape.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This was lost.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p[1]/xhtml:span[1]", OUString::fromUtf8("\xc2\xa0"));
|
|
// Make sure escaping happens only once.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p[1]/xhtml:span[2]", u"a&b");
|
|
// This was also lost.
|
|
assertXPathContent(
|
|
mpXmlDoc, "//xhtml:p[1]/xhtml:span[3]",
|
|
OUString::fromUtf8("\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2"
|
|
"\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 "));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testParaCharProps)
|
|
{
|
|
createDoc(u"para-char-props.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
// Check formatting of the middle span.
|
|
OUString aMiddle = getXPath(mpXmlDoc, "//xhtml:p/xhtml:span[2]", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"italic"_ustr, EPUBExportTest::getCss(aCssDoc, aMiddle, u"font-style"));
|
|
// Direct para formatting was lost, only direct char formatting was
|
|
// written, so this failed.
|
|
CPPUNIT_ASSERT_EQUAL(u"bold"_ustr, EPUBExportTest::getCss(aCssDoc, aMiddle, u"font-weight"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testSection)
|
|
{
|
|
createDoc(u"section.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This was "After.", i.e. in-section content was ignored.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p[2]/xhtml:span", u"In section.");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testList)
|
|
{
|
|
createDoc(u"list.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This was "C", i.e. in-list content was ignored.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p[2]/xhtml:span", u"B");
|
|
// Test nested list content.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p[6]/xhtml:span", u"F");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testImage)
|
|
{
|
|
createDoc(u"image.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:img", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testImageBorder)
|
|
{
|
|
createDoc(u"image-border.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:img", "class");
|
|
// This failed, image had no border.
|
|
CPPUNIT_ASSERT_EQUAL(u"0.99pt dashed #ed1c24"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"border"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testImageNospan)
|
|
{
|
|
createDoc(u"image-nospan.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// Image outside a span was lost.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:img", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTable)
|
|
{
|
|
createDoc(u"table.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr/xhtml:td", 4);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTableRowSpan)
|
|
{
|
|
createDoc(u"table-row-span.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This failed, row span wasn't exported.
|
|
assertXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]/xhtml:td[1]", "rowspan", u"2");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTableCellBorder)
|
|
{
|
|
createDoc(u"table-cell-border.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
|
|
OUString aClass
|
|
= getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]/xhtml:td[1]", "class");
|
|
// This failed, cell border wasn't exported.
|
|
CPPUNIT_ASSERT_EQUAL(u"0.05pt solid #000000"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"border-left"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTableCellWidth)
|
|
{
|
|
createDoc(u"table-cell-width.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
OUString aClass1
|
|
= getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]/xhtml:td[1]", "class");
|
|
OUString aClass2
|
|
= getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]/xhtml:td[2]", "class");
|
|
OUString aClass3
|
|
= getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]/xhtml:td[3]", "class");
|
|
// These failed, all widths were 0.
|
|
CPPUNIT_ASSERT_GREATER(EPUBExportTest::getCss(aCssDoc, aClass2, u"width").toDouble(),
|
|
EPUBExportTest::getCss(aCssDoc, aClass1, u"width").toDouble());
|
|
CPPUNIT_ASSERT_GREATER(EPUBExportTest::getCss(aCssDoc, aClass3, u"width").toDouble(),
|
|
EPUBExportTest::getCss(aCssDoc, aClass1, u"width").toDouble());
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTableRowHeight)
|
|
{
|
|
createDoc(u"table-row-height.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
OUString aClass1 = getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[1]", "class");
|
|
OUString aClass2 = getXPath(mpXmlDoc, "//xhtml:table/xhtml:tbody/xhtml:tr[2]", "class");
|
|
// These failed, both heights were 0.
|
|
CPPUNIT_ASSERT_GREATER(EPUBExportTest::getCss(aCssDoc, aClass2, u"height").toDouble(),
|
|
EPUBExportTest::getCss(aCssDoc, aClass1, u"height").toDouble());
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testLink)
|
|
{
|
|
createDoc(u"link.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:span", u"https://libreoffice.org/");
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", "href", u"https://libreoffice.org/");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testLinkInvalid)
|
|
{
|
|
createDoc(u"link-invalid.odt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This was 1, invalid relative link was not filtered out.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", 0);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testLinkCharFormat)
|
|
{
|
|
createDoc(u"link-charformat.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// <span> was lost, link text having a char format was missing.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:span", u"https://libreoffice.org/");
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", "href", u"https://libreoffice.org/");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testLinkNamedCharFormat)
|
|
{
|
|
// Character properties from named character style on hyperlink was lost.
|
|
createDoc(u"link-namedcharformat.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
// This failed, there was no span inside the hyperlink.
|
|
assertXPathContent(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:span", u"http://libreoffice.org");
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", "href", u"http://libreoffice.org/");
|
|
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:span", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"#ff0000"_ustr, EPUBExportTest::getCss(aCssDoc, aClass, u"color"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTableWidth)
|
|
{
|
|
createDoc(u"table-width.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:table", "class");
|
|
// This failed, relative total width of table was lost.
|
|
CPPUNIT_ASSERT_EQUAL(u"50%"_ustr, EPUBExportTest::getCss(aCssDoc, aClass, u"width"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTextBox)
|
|
{
|
|
createDoc(u"text-box.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
|
|
// This failed, image with caption was lost.
|
|
assertXPath(mpXmlDoc, "//xhtml:img", "class", u"frame1");
|
|
// Expected spans:
|
|
// 1) break after the image
|
|
// 2) "Illustration "
|
|
// 3) The sequence field, this was missing (was ": foo" instead).
|
|
assertXPathContent(mpXmlDoc, "//xhtml:div/xhtml:p/xhtml:span[3]", u"1");
|
|
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:div/xhtml:p/xhtml:span[3]", "class");
|
|
// This failed, the 3rd span was not italic.
|
|
CPPUNIT_ASSERT_EQUAL(u"italic"_ustr, EPUBExportTest::getCss(aCssDoc, aClass, u"font-style"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testFontEmbedding)
|
|
{
|
|
#if !defined(MACOSX)
|
|
createDoc(u"font-embedding.fodt", {});
|
|
|
|
// Make sure that the params of defineEmbeddedFont() are all handled.
|
|
// librevenge:name
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
// 'SketchFlow Print' or ''SketchFlow Print1'
|
|
CPPUNIT_ASSERT(EPUBExportTest::getCss(aCssDoc, u"font-face"_ustr, u"font-family")
|
|
.startsWith("'SketchFlow Print"));
|
|
// librevenge:mime-type
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/content.opf"_ustr);
|
|
assertXPath(mpXmlDoc, "/opf:package/opf:manifest/opf:item[@href='fonts/font0001.otf']",
|
|
"media-type", u"application/vnd.ms-opentype");
|
|
// office:binary-data
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/fonts/font0001.otf"_ustr));
|
|
// librevenge:font-style
|
|
CPPUNIT_ASSERT_EQUAL(u"normal"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, u"font-face"_ustr, u"font-style"));
|
|
// librevenge:font-weight
|
|
CPPUNIT_ASSERT_EQUAL(u"normal"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, u"font-face"_ustr, u"font-weight"));
|
|
#endif
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testImageLink)
|
|
{
|
|
createDoc(u"image-link.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// This failed, image was missing.
|
|
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a/xhtml:img", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testFootnote)
|
|
{
|
|
createDoc(u"footnote.fodt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// These were missing, footnote was lost.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:sup/xhtml:a", "type", u"noteref");
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside", "type", u"footnote");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testPopup)
|
|
{
|
|
createDoc(u"popup.odt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// Test image popup anchor.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p[1]/xhtml:a", "type", u"noteref");
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p[1]/xhtml:a/xhtml:img", 1);
|
|
// Test image popup content.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside[1]", "type", u"footnote");
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside[1]/xhtml:img", 1);
|
|
|
|
// Test text popup anchor.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p[2]/xhtml:span/xhtml:a", "type", u"noteref");
|
|
assertXPathContent(mpXmlDoc, "//xhtml:body/xhtml:p[2]/xhtml:span/xhtml:a", u"link");
|
|
// Test text popup content.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside[2]", "type", u"footnote");
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:aside[2]/xhtml:img", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testPopupMedia)
|
|
{
|
|
// This is the same as testPopup(), but the links point to images in the
|
|
// default media directory, not in the document directory.
|
|
createDoc(u"popup-media.odt", {});
|
|
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// Test image popup anchor. This failed, number of XPath nodes was 0.
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p[1]/xhtml:a", "type", u"noteref");
|
|
assertXPath(mpXmlDoc, "//xhtml:body/xhtml:p[1]/xhtml:a/xhtml:img", 1);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testPopupAPI)
|
|
{
|
|
// Make sure that the popup works with data from a media directory.
|
|
OUString aMediaDir = createFileURL(u"popup");
|
|
uno::Sequence<beans::PropertyValue> aFilterData(
|
|
comphelper::InitPropertySequence({ { "RVNGMediaDir", uno::Any(aMediaDir) } }));
|
|
createDoc(u"popup-api.odt", aFilterData);
|
|
|
|
// We have a non-empty anchor image.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
OUString aAnchor = getXPath(mpXmlDoc, "//xhtml:body/xhtml:p[1]/xhtml:a/xhtml:img", "src");
|
|
CPPUNIT_ASSERT(!aAnchor.isEmpty());
|
|
// We have a non-empty popup image.
|
|
OUString aData = getXPath(mpXmlDoc, "//xhtml:body/xhtml:aside[1]/xhtml:img", "src");
|
|
CPPUNIT_ASSERT(!aData.isEmpty());
|
|
// The anchor is different from the popup image.
|
|
CPPUNIT_ASSERT(aAnchor != aData);
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testPageSize)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ { "EPUBLayoutMethod",
|
|
uno::Any(static_cast<sal_Int32>(libepubgen::EPUB_LAYOUT_METHOD_FIXED)) } }));
|
|
createDoc(u"hello.fodt", aFilterData);
|
|
|
|
// This failed, viewport was empty, so page size was lost.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
// 21,59cm x 27.94cm (letter).
|
|
assertXPath(mpXmlDoc, "/xhtml:html/xhtml:head/xhtml:meta[@name='viewport']", "content",
|
|
u"width=816, height=1056");
|
|
|
|
mpXmlDoc = parseExport(u"OEBPS/images/image0001.svg"_ustr);
|
|
// This was 288mm, logic->logic conversion input was a pixel value.
|
|
assertXPath(mpXmlDoc, "/svg:svg", "width", u"216mm");
|
|
assertXPath(mpXmlDoc, "/svg:svg", "height", u"279mm");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testSVG)
|
|
{
|
|
uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
|
|
{ { "EPUBLayoutMethod",
|
|
uno::Any(static_cast<sal_Int32>(libepubgen::EPUB_LAYOUT_METHOD_FIXED)) } }));
|
|
createDoc(u"hello.fodt", aFilterData);
|
|
|
|
CPPUNIT_ASSERT(mxZipFile->hasByName(u"OEBPS/images/image0001.svg"_ustr));
|
|
uno::Reference<io::XInputStream> xInputStream(
|
|
mxZipFile->getByName(u"OEBPS/images/image0001.svg"_ustr), uno::UNO_QUERY);
|
|
std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
|
|
|
|
SvMemoryStream aMemoryStream;
|
|
aMemoryStream.WriteStream(*pStream);
|
|
OString aExpected("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<svg"_ostr);
|
|
CPPUNIT_ASSERT(aMemoryStream.GetSize() > o3tl::make_unsigned(aExpected.getLength()));
|
|
|
|
// This failed, there was a '<!DOCTYPE' line between the xml and the svg
|
|
// one, causing a validation error.
|
|
OString aActual(static_cast<const char*>(aMemoryStream.GetData()), aExpected.getLength());
|
|
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
|
|
|
|
// This failed, we used the xlink attribute namespace, but we did not
|
|
// define its URL.
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/images/image0001.svg"_ustr);
|
|
assertXPathNSDef(mpXmlDoc, "/svg:svg", "xlink", "http://www.w3.org/1999/xlink");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTdf115623SingleWritingMode)
|
|
{
|
|
// Simple page that has single writing mode should work.
|
|
createDoc(u"tdf115623-single-writing-mode.odt", {});
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:body", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"vertical-rl"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"writing-mode"));
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTdf115623SplitByChapter)
|
|
{
|
|
createDoc(u"tdf115623-split-by-chapter.odt", {});
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
{
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:body", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"vertical-rl"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"writing-mode"));
|
|
}
|
|
// Split HTML should keep the same writing-mode.
|
|
{
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0002.xhtml"_ustr);
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:body", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"vertical-rl"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"writing-mode"));
|
|
}
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testTdf115623ManyPageSpans)
|
|
{
|
|
createDoc(u"tdf115623-many-pagespans.odt", {});
|
|
std::map<OUString, std::vector<OUString>> aCssDoc
|
|
= parseCss(u"OEBPS/styles/stylesheet.css"_ustr);
|
|
// Two pages should have different writing modes.
|
|
{
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:body", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"vertical-rl"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"writing-mode"));
|
|
}
|
|
{
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0002.xhtml"_ustr);
|
|
OUString aClass = getXPath(mpXmlDoc, "//xhtml:body", "class");
|
|
CPPUNIT_ASSERT_EQUAL(u"horizontal-tb"_ustr,
|
|
EPUBExportTest::getCss(aCssDoc, aClass, u"writing-mode"));
|
|
}
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testSimpleRuby)
|
|
{
|
|
createDoc(u"simple-ruby.odt", {});
|
|
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
|
|
assertXPathContent(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:ruby/xhtml:span", u"base text");
|
|
assertXPathContent(mpXmlDoc, "//xhtml:body/xhtml:p/xhtml:ruby/xhtml:rt", u"ruby text");
|
|
}
|
|
|
|
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testAbi11105)
|
|
{
|
|
// This crashed because the paragraph style "P5" which had a master-page-name
|
|
// appeared in a table cell messed up page spans.
|
|
createDoc(u"abi11105.abw", {});
|
|
}
|
|
}
|
|
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|