1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #ifndef SC_QA_HELPER_HXX
11 #define SC_QA_HELPER_HXX
13 #include <test/bootstrapfixture.hxx>
14 #define __ORCUS_STATIC_LIB
15 #include "helper/csv_handler.hxx"
16 #include "helper/debughelper.hxx"
17 #include "orcus/csv_parser.hpp"
22 #include <comphelper/documentconstants.hxx>
24 #include <osl/detail/android-bootstrap.h>
26 #include <unotools/tempfile.hxx>
27 #include <comphelper/storagehelper.hxx>
28 #include <sfx2/docfilt.hxx>
30 #define ODS_FORMAT_TYPE 50331943
31 #define XLS_FORMAT_TYPE 318767171
32 #define XLSX_FORMAT_TYPE 268959811
33 #define LOTUS123_FORMAT_TYPE 268435649
34 #define CSV_FORMAT_TYPE (SFX_FILTER_IMPORT | SFX_FILTER_EXPORT | SFX_FILTER_ALIEN | SFX_FILTER_USESOPTIONS)
35 #define HTML_FORMAT_TYPE (SFX_FILTER_IMPORT | SFX_FILTER_EXPORT | SFX_FILTER_ALIEN | SFX_FILTER_USESOPTIONS)
44 bool testEqualsWithTolerance( long nVal1
, long nVal2
, long nTol
)
46 return ( labs( nVal1
- nVal2
) <= nTol
);
50 const char* pName
; const char* pFilterName
; const char* pTypeName
; unsigned int nFormatType
;
53 #define CHECK_OPTIMAL 0x1
55 // data format for row height tests
63 int nExpectedHeight
; // -1 for default height
64 int nCheck
; // currently only CHECK_OPTIMAL ( we could add CHECK_MANUAL etc.)
69 int nExportType
; // -1 for import test, otherwise this is an export test
74 FileFormat aFileFormats
[] = {
75 { "ods" , "calc8", "", ODS_FORMAT_TYPE
},
76 { "xls" , "MS Excel 97", "calc_MS_EXCEL_97", XLS_FORMAT_TYPE
},
77 { "xlsx", "Calc MS Excel 2007 XML" , "MS Excel 2007 XML", XLSX_FORMAT_TYPE
},
78 { "csv" , "Text - txt - csv (StarCalc)", "generic_Text", CSV_FORMAT_TYPE
},
79 { "html" , "calc_HTML_WebQuery", "generic_HTML", HTML_FORMAT_TYPE
},
80 { "123" , "Lotus", "calc_Lotus", LOTUS123_FORMAT_TYPE
},
83 // Why is this here and not in osl, and using the already existing file
84 // handling APIs? Do we really want to add arbitrary new file handling
85 // wrappers here and there (and then having to handle the Android (and
86 // eventually perhaps iOS) special cases here, too)? Please move this to osl,
87 // it sure looks gemerally useful. Or am I missing something?
89 void loadFile(const OUString
& aFileName
, std::string
& aContent
)
91 OString aOFileName
= OUStringToOString(aFileName
, RTL_TEXTENCODING_UTF8
);
95 if (strncmp(aOFileName
.getStr(), "/assets/", sizeof("/assets/")-1) == 0) {
96 const char *contents
= (const char *) lo_apkentry(aOFileName
.getStr(), &size
);
98 aContent
= std::string(contents
, size
);
104 std::ifstream
aFile(aOFileName
.getStr());
106 OStringBuffer
aErrorMsg("Could not open csv file: ");
107 aErrorMsg
.append(aOFileName
);
108 CPPUNIT_ASSERT_MESSAGE(aErrorMsg
.getStr(), aFile
);
109 std::ostringstream aOStream
;
110 aOStream
<< aFile
.rdbuf();
112 aContent
= aOStream
.str();
115 class ScBootstrapFixture
: public test::BootstrapFixture
118 OUString m_aBaseString
;
119 ScDocShellRef
load( bool bReadWrite
,
120 const OUString
& rURL
, const OUString
& rFilter
, const OUString
&rUserData
,
121 const OUString
& rTypeName
, unsigned int nFilterFlags
, unsigned int nClipboardID
, sal_uIntPtr nFilterVersion
= SOFFICE_FILEFORMAT_CURRENT
, const OUString
* pPassword
= NULL
)
123 SfxFilter
* pFilter
= new SfxFilter(
125 OUString(), nFilterFlags
, nClipboardID
, rTypeName
, 0, OUString(),
126 rUserData
, OUString("private:factory/scalc*"));
127 pFilter
->SetVersion(nFilterVersion
);
129 ScDocShellRef xDocShRef
= new ScDocShell
;
130 xDocShRef
->GetDocument()->EnableUserInteraction(false);
131 SfxMedium
* pSrcMed
= new SfxMedium(rURL
, bReadWrite
? STREAM_STD_READWRITE
: STREAM_STD_READ
);
132 pSrcMed
->SetFilter(pFilter
);
133 pSrcMed
->UseInteractionHandler(false);
136 SfxItemSet
* pSet
= pSrcMed
->GetItemSet();
137 pSet
->Put(SfxStringItem(SID_PASSWORD
, *pPassword
));
139 printf("about to load %s\n", OUStringToOString( rURL
, RTL_TEXTENCODING_UTF8
).getStr() );
140 if (!xDocShRef
->DoLoad(pSrcMed
))
142 xDocShRef
->DoClose();
151 const OUString
& rURL
, const OUString
& rFilter
, const OUString
&rUserData
,
152 const OUString
& rTypeName
, unsigned int nFilterFlags
, unsigned int nClipboardID
, sal_uIntPtr nFilterVersion
= SOFFICE_FILEFORMAT_CURRENT
, const OUString
* pPassword
= NULL
)
154 return load( false, rURL
, rFilter
, rUserData
, rTypeName
, nFilterFlags
, nClipboardID
, nFilterVersion
, pPassword
);
157 ScDocShellRef
loadDoc(const OUString
& rFileName
, sal_Int32 nFormat
, bool bReadWrite
= false )
159 OUString
aFileExtension(aFileFormats
[nFormat
].pName
, strlen(aFileFormats
[nFormat
].pName
), RTL_TEXTENCODING_UTF8
);
160 OUString
aFilterName(aFileFormats
[nFormat
].pFilterName
, strlen(aFileFormats
[nFormat
].pFilterName
), RTL_TEXTENCODING_UTF8
) ;
162 createFileURL( rFileName
, aFileExtension
, aFileName
);
163 OUString
aFilterType(aFileFormats
[nFormat
].pTypeName
, strlen(aFileFormats
[nFormat
].pTypeName
), RTL_TEXTENCODING_UTF8
);
164 unsigned int nFormatType
= aFileFormats
[nFormat
].nFormatType
;
165 unsigned int nClipboardId
= nFormatType
? SFX_FILTER_IMPORT
| SFX_FILTER_USESOPTIONS
: 0;
167 return load(bReadWrite
, aFileName
, aFilterName
, OUString(), aFilterType
, nFormatType
, nClipboardId
, nFormatType
);
172 ScBootstrapFixture( const OUString
& rsBaseString
) : m_aBaseString( rsBaseString
) {}
173 void createFileURL(const OUString
& aFileBase
, const OUString
& aFileExtension
, OUString
& rFilePath
)
176 OUStringBuffer
aBuffer( getSrcRootURL() );
177 aBuffer
.append(m_aBaseString
).append(aSep
).append(aFileExtension
);
178 aBuffer
.append(aSep
).append(aFileBase
).append(aFileExtension
);
179 rFilePath
= aBuffer
.makeStringAndClear();
182 void createCSVPath(const OUString
& aFileBase
, OUString
& rCSVPath
)
184 OUStringBuffer
aBuffer( getSrcRootPath());
185 aBuffer
.append(m_aBaseString
).append(OUString("/contentCSV/"));
186 aBuffer
.append(aFileBase
).append(OUString("csv"));
187 rCSVPath
= aBuffer
.makeStringAndClear();
190 ScDocShellRef
saveAndReload(ScDocShell
* pShell
, const OUString
&rFilter
,
191 const OUString
&rUserData
, const OUString
& rTypeName
, sal_uLong nFormatType
)
194 utl::TempFile aTempFile
;
195 aTempFile
.EnableKillingFile();
196 SfxMedium
aStoreMedium( aTempFile
.GetURL(), STREAM_STD_WRITE
);
197 sal_uInt32 nExportFormat
= 0;
198 if (nFormatType
== ODS_FORMAT_TYPE
)
199 nExportFormat
= SFX_FILTER_EXPORT
| SFX_FILTER_USESOPTIONS
;
200 SfxFilter
* pExportFilter
= new SfxFilter(
202 OUString(), nFormatType
, nExportFormat
, rTypeName
, 0, OUString(),
203 rUserData
, OUString("private:factory/scalc*") );
204 pExportFilter
->SetVersion(SOFFICE_FILEFORMAT_CURRENT
);
205 aStoreMedium
.SetFilter(pExportFilter
);
206 pShell
->DoSaveAs( aStoreMedium
);
209 //std::cout << "File: " << aTempFile.GetURL() << std::endl;
211 sal_uInt32 nFormat
= 0;
212 if (nFormatType
== ODS_FORMAT_TYPE
)
213 nFormat
= SFX_FILTER_IMPORT
| SFX_FILTER_USESOPTIONS
;
215 return load(aTempFile
.GetURL(), rFilter
, rUserData
, rTypeName
, nFormatType
, nFormat
);
217 ScDocShellRef
saveAndReload( ScDocShell
* pShell
, sal_Int32 nFormat
)
219 OUString
aFilterName(aFileFormats
[nFormat
].pFilterName
, strlen(aFileFormats
[nFormat
].pFilterName
), RTL_TEXTENCODING_UTF8
) ;
220 OUString
aFilterType(aFileFormats
[nFormat
].pTypeName
, strlen(aFileFormats
[nFormat
].pTypeName
), RTL_TEXTENCODING_UTF8
);
221 ScDocShellRef xDocSh
= saveAndReload(pShell
, aFilterName
, OUString(), aFilterType
, aFileFormats
[nFormat
].nFormatType
);
223 CPPUNIT_ASSERT(xDocSh
.Is());
227 void miscRowHeightsTest( TestParam
* aTestValues
, unsigned int numElems
)
229 for ( unsigned int index
=0; index
<numElems
; ++index
)
231 OUString sFileName
= OUString::createFromAscii( aTestValues
[ index
].sTestDoc
);
232 printf("aTestValues[%u] %s\n", index
, OUStringToOString( sFileName
, RTL_TEXTENCODING_UTF8
).getStr() );
233 int nImportType
= aTestValues
[ index
].nImportType
;
234 int nExportType
= aTestValues
[ index
].nExportType
;
235 ScDocShellRef xShell
= loadDoc( sFileName
, nImportType
);
236 CPPUNIT_ASSERT(xShell
.Is());
238 if ( nExportType
!= -1 )
239 xShell
= saveAndReload(&(*xShell
), nExportType
);
241 CPPUNIT_ASSERT(xShell
.Is());
243 ScDocument
* pDoc
= xShell
->GetDocument();
245 for (int i
=0; i
<aTestValues
[ index
].nRowData
; ++i
)
247 SCROW nRow
= aTestValues
[ index
].pData
[ i
].nStartRow
;
248 SCROW nEndRow
= aTestValues
[ index
].pData
[ i
].nEndRow
;
249 SCTAB nTab
= aTestValues
[ index
].pData
[ i
].nTab
;
250 int nExpectedHeight
= aTestValues
[ index
].pData
[ i
].nExpectedHeight
;
251 if ( nExpectedHeight
== -1 )
252 nExpectedHeight
= sc::TwipsToHMM( ScGlobal::nStdRowHeight
);
253 bool bCheckOpt
= ( ( aTestValues
[ index
].pData
[ i
].nCheck
& CHECK_OPTIMAL
) == CHECK_OPTIMAL
);
254 for ( ; nRow
<= nEndRow
; ++nRow
)
256 printf("\t checking row %" SAL_PRIdINT32
" for height %d\n", nRow
, nExpectedHeight
);
257 int nHeight
= sc::TwipsToHMM( pDoc
->GetRowHeight(nRow
, nTab
, false) );
260 bool bOpt
= !(pDoc
->GetRowFlags( nRow
, nTab
) & CR_MANUALSIZE
);
261 CPPUNIT_ASSERT_EQUAL(aTestValues
[ index
].pData
[ i
].bOptimal
, bOpt
);
263 CPPUNIT_ASSERT_EQUAL(nExpectedHeight
, nHeight
);
271 void testFile(OUString
& aFileName
, ScDocument
* pDoc
, SCTAB nTab
, StringType aStringFormat
= StringValue
)
273 csv_handler
aHandler(pDoc
, nTab
, aStringFormat
);
274 orcus::csv_parser_config aConfig
;
275 aConfig
.delimiters
.push_back(',');
276 aConfig
.delimiters
.push_back(';');
277 aConfig
.text_qualifier
= '"';
278 aConfig
.trim_cell_value
= false;
281 std::string aContent
;
282 loadFile(aFileName
, aContent
);
283 orcus::csv_parser
<csv_handler
> parser ( &aContent
[0], aContent
.size() , aHandler
, aConfig
);
288 catch (const orcus::csv_parse_error
& e
)
290 std::cout
<< "reading csv content file failed: " << e
.what() << std::endl
;
291 OStringBuffer
aErrorMsg("csv parser error: ");
292 aErrorMsg
.append(e
.what());
293 CPPUNIT_ASSERT_MESSAGE(aErrorMsg
.getStr(), false);
297 //need own handler because conditional formatting strings must be generated
298 void testCondFile(OUString
& aFileName
, ScDocument
* pDoc
, SCTAB nTab
)
300 conditional_format_handler
aHandler(pDoc
, nTab
);
301 orcus::csv_parser_config aConfig
;
302 aConfig
.delimiters
.push_back(',');
303 aConfig
.delimiters
.push_back(';');
304 aConfig
.text_qualifier
= '"';
305 std::string aContent
;
306 loadFile(aFileName
, aContent
);
307 orcus::csv_parser
<conditional_format_handler
> parser ( &aContent
[0], aContent
.size() , aHandler
, aConfig
);
312 catch (const orcus::csv_parse_error
& e
)
314 std::cout
<< "reading csv content file failed: " << e
.what() << std::endl
;
315 OStringBuffer
aErrorMsg("csv parser error: ");
316 aErrorMsg
.append(e
.what());
317 CPPUNIT_ASSERT_MESSAGE(aErrorMsg
.getStr(), false);
322 #define ASSERT_DOUBLES_EQUAL( expected, result ) \
323 CPPUNIT_ASSERT_DOUBLES_EQUAL( (expected), (result), 1e-14 )
325 #define ASSERT_DOUBLES_EQUAL_MESSAGE( message, expected, result ) \
326 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( (message), (expected), (result), 1e-14 )
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */