Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : */
9 :
10 : #include "qahelper.hxx"
11 : #include "csv_handler.hxx"
12 : #include "drwlayer.hxx"
13 : #include "compiler.hxx"
14 : #include "conditio.hxx"
15 : #include "stlsheet.hxx"
16 : #include "formulacell.hxx"
17 : #include <svx/svdpage.hxx>
18 : #include <svx/svdoole2.hxx>
19 : #include <editeng/brushitem.hxx>
20 : #include <editeng/justifyitem.hxx>
21 :
22 : #include <config_orcus.h>
23 :
24 : #if ENABLE_ORCUS
25 : #if defined WNT
26 : #define __ORCUS_STATIC_LIB
27 : #endif
28 : #include <orcus/csv_parser.hpp>
29 : #endif
30 :
31 : #include <fstream>
32 :
33 : #include <com/sun/star/frame/XModel.hpp>
34 : #include <com/sun/star/text/textfield/Type.hpp>
35 : #include <com/sun/star/chart2/XChartDocument.hpp>
36 : #include <com/sun/star/chart2/data/XDataReceiver.hpp>
37 : #include <com/sun/star/document/MacroExecMode.hpp>
38 :
39 : using namespace com::sun::star;
40 : using namespace ::com::sun::star::uno;
41 :
42 : // calc data structure pretty printer
43 0 : std::ostream& operator<<(std::ostream& rStrm, const ScAddress& rAddr)
44 : {
45 0 : rStrm << "Col: " << rAddr.Col() << " Row: " << rAddr.Row() << " Tab: " << rAddr.Tab() << "\n";
46 0 : return rStrm;
47 : }
48 :
49 0 : std::ostream& operator<<(std::ostream& rStrm, const ScRange& rRange)
50 : {
51 0 : rStrm << "ScRange: " << rRange.aStart << rRange.aEnd << "\n";
52 0 : return rStrm;
53 : }
54 :
55 0 : std::ostream& operator<<(std::ostream& rStrm, const ScRangeList& rList)
56 : {
57 0 : rStrm << "ScRangeList: \n";
58 0 : for(size_t i = 0; i < rList.size(); ++i)
59 0 : rStrm << *rList[i];
60 0 : return rStrm;
61 : }
62 :
63 0 : std::ostream& operator<<(std::ostream& rStrm, const Color& rColor)
64 : {
65 0 : rStrm << "Color: R:" << (int)rColor.GetRed() << " G:" << (int)rColor.GetGreen() << " B: " << (int)rColor.GetBlue();
66 0 : return rStrm;
67 : }
68 :
69 0 : std::ostream& operator<<(std::ostream& rStrm, const OpCode& rCode)
70 : {
71 0 : rStrm << static_cast<sal_uInt16>(rCode);
72 0 : return rStrm;
73 : }
74 :
75 : const FileFormat ScBootstrapFixture::aFileFormats[] = {
76 20 : { "ods" , "calc8", "", ODS_FORMAT_TYPE },
77 20 : { "xls" , "MS Excel 97", "calc_MS_EXCEL_97", XLS_FORMAT_TYPE },
78 20 : { "xlsx", "Calc Office Open XML" , "Office Open XML Spreadsheet", XLSX_FORMAT_TYPE },
79 20 : { "xlsm", "Calc Office Open XML" , "Office Open XML Spreadsheet", XLSX_FORMAT_TYPE },
80 20 : { "csv" , "Text - txt - csv (StarCalc)", "generic_Text", CSV_FORMAT_TYPE },
81 20 : { "html" , "calc_HTML_WebQuery", "generic_HTML", HTML_FORMAT_TYPE },
82 20 : { "123" , "Lotus", "calc_Lotus", LOTUS123_FORMAT_TYPE },
83 20 : { "dif", "DIF", "calc_DIF", DIF_FORMAT_TYPE },
84 20 : { "xml", "MS Excel 2003 XML", "calc_MS_Excel_2003_XML", XLS_XML_FORMAT_TYPE },
85 20 : { "xlsb", "Calc MS Excel 2007 Binary", "MS Excel 2007 Binary", XLSB_XML_FORMAT_TYPE }
86 100 : };
87 :
88 26 : bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol )
89 : {
90 26 : return ( labs( nVal1 - nVal2 ) <= nTol );
91 : }
92 :
93 41 : void loadFile(const OUString& aFileName, std::string& aContent)
94 : {
95 41 : OString aOFileName = OUStringToOString(aFileName, RTL_TEXTENCODING_UTF8);
96 :
97 : #ifdef ANDROID
98 : size_t size;
99 : if (strncmp(aOFileName.getStr(), "/assets/", sizeof("/assets/")-1) == 0) {
100 : const char *contents = (const char *) lo_apkentry(aOFileName.getStr(), &size);
101 : if (contents != 0) {
102 : aContent = std::string(contents, size);
103 : return;
104 : }
105 : }
106 : #endif
107 :
108 82 : std::ifstream aFile(aOFileName.getStr());
109 :
110 82 : OStringBuffer aErrorMsg("Could not open csv file: ");
111 41 : aErrorMsg.append(aOFileName);
112 41 : CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), aFile);
113 82 : std::ostringstream aOStream;
114 41 : aOStream << aFile.rdbuf();
115 41 : aFile.close();
116 82 : aContent = aOStream.str();
117 41 : }
118 :
119 : #if ENABLE_ORCUS
120 :
121 34 : void testFile(OUString& aFileName, ScDocument& rDoc, SCTAB nTab, StringType aStringFormat)
122 : {
123 34 : csv_handler aHandler(&rDoc, nTab, aStringFormat);
124 34 : orcus::csv::parser_config aConfig;
125 34 : aConfig.delimiters.push_back(',');
126 34 : aConfig.delimiters.push_back(';');
127 34 : aConfig.text_qualifier = '"';
128 34 : aConfig.trim_cell_value = false;
129 :
130 68 : std::string aContent;
131 34 : loadFile(aFileName, aContent);
132 68 : orcus::csv_parser<csv_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
133 : try
134 : {
135 34 : parser.parse();
136 : }
137 0 : catch (const orcus::csv::parse_error& e)
138 : {
139 0 : std::cout << "reading csv content file failed: " << e.what() << std::endl;
140 0 : OStringBuffer aErrorMsg("csv parser error: ");
141 0 : aErrorMsg.append(e.what());
142 0 : CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
143 34 : }
144 33 : }
145 :
146 7 : void testCondFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab)
147 : {
148 7 : conditional_format_handler aHandler(pDoc, nTab);
149 7 : orcus::csv::parser_config aConfig;
150 7 : aConfig.delimiters.push_back(',');
151 7 : aConfig.delimiters.push_back(';');
152 7 : aConfig.text_qualifier = '"';
153 14 : std::string aContent;
154 7 : loadFile(aFileName, aContent);
155 14 : orcus::csv_parser<conditional_format_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
156 : try
157 : {
158 7 : parser.parse();
159 : }
160 0 : catch (const orcus::csv::parse_error& e)
161 : {
162 0 : std::cout << "reading csv content file failed: " << e.what() << std::endl;
163 0 : OStringBuffer aErrorMsg("csv parser error: ");
164 0 : aErrorMsg.append(e.what());
165 0 : CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
166 7 : }
167 7 : }
168 :
169 : #else
170 :
171 : void testFile(OUString&, ScDocument&, SCTAB, StringType) {}
172 : void testCondFile(OUString&, ScDocument*, SCTAB) {}
173 :
174 : #endif
175 :
176 2 : void testFormats(ScBootstrapFixture* pTest, ScDocument* pDoc, sal_Int32 nFormat)
177 : {
178 : //test Sheet1 with csv file
179 2 : OUString aCSVFileName;
180 2 : pTest->createCSVPath(OUString("numberFormat."), aCSVFileName);
181 2 : testFile(aCSVFileName, *pDoc, 0, PureString);
182 : //need to test the color of B3
183 : //it's not a font color!
184 : //formatting for B5: # ??/100 gets lost during import
185 :
186 : //test Sheet2
187 2 : const ScPatternAttr* pPattern = NULL;
188 2 : pPattern = pDoc->GetPattern(0,0,1);
189 4 : vcl::Font aFont;
190 2 : pPattern->GetFont(aFont,SC_AUTOCOL_RAW);
191 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font size should be 10", 200l, aFont.GetSize().getHeight());
192 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font color should be black", COL_AUTO, aFont.GetColor().GetColor());
193 2 : pPattern = pDoc->GetPattern(0,1,1);
194 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
195 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font size should be 12", 240l, aFont.GetSize().getHeight());
196 2 : pPattern = pDoc->GetPattern(0,2,1);
197 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
198 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be italic", ITALIC_NORMAL, aFont.GetItalic());
199 2 : pPattern = pDoc->GetPattern(0,4,1);
200 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
201 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight());
202 2 : pPattern = pDoc->GetPattern(1,0,1);
203 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
204 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be blue", COL_BLUE, aFont.GetColor().GetColor());
205 2 : pPattern = pDoc->GetPattern(1,1,1);
206 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
207 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be striked out with a single line", STRIKEOUT_SINGLE, aFont.GetStrikeout());
208 : //some tests on sheet2 only for ods
209 2 : if (nFormat == ODS)
210 : {
211 2 : pPattern = pDoc->GetPattern(1,2,1);
212 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
213 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be striked out with a double line", STRIKEOUT_DOUBLE, aFont.GetStrikeout());
214 2 : pPattern = pDoc->GetPattern(1,3,1);
215 2 : pPattern->GetFont(aFont, SC_AUTOCOL_RAW);
216 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be underlined with a dotted line", UNDERLINE_DOTTED, aFont.GetUnderline());
217 : //check row height import
218 : //disable for now until we figure out cause of win tinderboxes test failures
219 : //CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(256), pDoc->GetRowHeight(0,1) ); //0.178in
220 : //CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(304), pDoc->GetRowHeight(1,1) ); //0.211in
221 : //CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(477), pDoc->GetRowHeight(5,1) ); //0.3311in
222 : //check column width import
223 2 : CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(555), pDoc->GetColWidth(4,1) ); //0.3854in
224 2 : CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1280), pDoc->GetColWidth(5,1) ); //0.889in
225 2 : CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(4153), pDoc->GetColWidth(6,1) ); //2.8839in
226 : //test case for i53253 where a cell has text with different styles and space between the text.
227 2 : OUString aTestStr = pDoc->GetString(3,0,1);
228 4 : OUString aKnownGoodStr("text14 space");
229 2 : CPPUNIT_ASSERT_EQUAL( aKnownGoodStr, aTestStr );
230 : //test case for cell text with line breaks.
231 2 : aTestStr = pDoc->GetString(3,5,1);
232 2 : aKnownGoodStr = "Hello,\nCalc!";
233 4 : CPPUNIT_ASSERT_EQUAL( aKnownGoodStr, aTestStr );
234 : }
235 2 : pPattern = pDoc->GetPattern(1,4,1);
236 2 : Color aColor = static_cast<const SvxBrushItem&>(pPattern->GetItem(ATTR_BACKGROUND)).GetColor();
237 2 : CPPUNIT_ASSERT_MESSAGE("background color should be green", aColor == COL_LIGHTGREEN);
238 2 : pPattern = pDoc->GetPattern(2,0,1);
239 2 : SvxCellHorJustify eHorJustify = static_cast<SvxCellHorJustify>(static_cast<const SvxHorJustifyItem&>(pPattern->GetItem(ATTR_HOR_JUSTIFY)).GetValue());
240 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("cell content should be aligned centre horizontally", SVX_HOR_JUSTIFY_CENTER, eHorJustify);
241 : //test alignment
242 2 : pPattern = pDoc->GetPattern(2,1,1);
243 2 : eHorJustify = static_cast<SvxCellHorJustify>(static_cast<const SvxHorJustifyItem&>(pPattern->GetItem(ATTR_HOR_JUSTIFY)).GetValue());
244 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("cell content should be aligned right horizontally", SVX_HOR_JUSTIFY_RIGHT, eHorJustify);
245 2 : pPattern = pDoc->GetPattern(2,2,1);
246 2 : eHorJustify = static_cast<SvxCellHorJustify>(static_cast<const SvxHorJustifyItem&>(pPattern->GetItem(ATTR_HOR_JUSTIFY)).GetValue());
247 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("cell content should be aligned block horizontally", SVX_HOR_JUSTIFY_BLOCK, eHorJustify);
248 :
249 : //test Sheet3 only for ods and xlsx
250 2 : if ( nFormat == ODS || nFormat == XLSX )
251 : {
252 2 : pTest->createCSVPath(OUString("conditionalFormatting."), aCSVFileName);
253 2 : testCondFile(aCSVFileName, pDoc, 2);
254 : // test parent cell style import ( fdo#55198 )
255 2 : if ( nFormat == XLSX )
256 : {
257 0 : pPattern = pDoc->GetPattern(1,1,3);
258 0 : ScStyleSheet* pStyleSheet = const_cast<ScStyleSheet*>(pPattern->GetStyleSheet());
259 : // check parent style name
260 0 : OUString sExpected("Excel Built-in Date");
261 0 : OUString sResult = pStyleSheet->GetName();
262 0 : CPPUNIT_ASSERT_EQUAL_MESSAGE("parent style for Sheet4.B2 is 'Excel Built-in Date'", sExpected, sResult);
263 : // check align of style
264 0 : SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
265 0 : eHorJustify = static_cast<SvxCellHorJustify>(static_cast< const SvxHorJustifyItem& >(rItemSet.Get( ATTR_HOR_JUSTIFY ) ).GetValue() );
266 0 : CPPUNIT_ASSERT_EQUAL_MESSAGE("'Excel Built-in Date' style should be aligned centre horizontally", SVX_HOR_JUSTIFY_CENTER, eHorJustify);
267 : // check date format ( should be just month e.g. 29 )
268 0 : sResult =pDoc->GetString( 1,1,3 );
269 0 : sExpected = "29";
270 0 : CPPUNIT_ASSERT_EQUAL_MESSAGE("'Excel Built-in Date' style should just display month", sExpected, sResult );
271 :
272 : // check actual align applied to cell, should be the same as
273 : // the style
274 0 : eHorJustify = static_cast<SvxCellHorJustify>(static_cast< const SvxHorJustifyItem& >(pPattern->GetItem( ATTR_HOR_JUSTIFY ) ).GetValue() );
275 0 : CPPUNIT_ASSERT_EQUAL_MESSAGE("cell with 'Excel Built-in Date' style should be aligned centre horizontally", SVX_HOR_JUSTIFY_CENTER, eHorJustify);
276 : }
277 : }
278 :
279 2 : ScConditionalFormat* pCondFormat = pDoc->GetCondFormat(0,0,2);
280 2 : const ScRangeList& rRange = pCondFormat->GetRange();
281 2 : CPPUNIT_ASSERT(rRange == ScRange(0,0,2,3,0,2));
282 :
283 2 : pCondFormat = pDoc->GetCondFormat(0,1,2);
284 2 : const ScRangeList& rRange2 = pCondFormat->GetRange();
285 2 : CPPUNIT_ASSERT(rRange2 == ScRange(0,1,2,0,1,2));
286 :
287 2 : pCondFormat = pDoc->GetCondFormat(1,1,2);
288 2 : const ScRangeList& rRange3 = pCondFormat->GetRange();
289 4 : CPPUNIT_ASSERT(rRange3 == ScRange(1,1,2,3,1,2));
290 2 : }
291 :
292 3 : const SdrOle2Obj* getSingleChartObject(ScDocument& rDoc, sal_uInt16 nPage)
293 : {
294 : // Retrieve the chart object instance from the 2nd page (for the 2nd sheet).
295 3 : ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
296 3 : if (!pDrawLayer)
297 : {
298 0 : cout << "Failed to retrieve the drawing layer object." << endl;
299 0 : return NULL;
300 : }
301 :
302 3 : const SdrPage* pPage = pDrawLayer->GetPage(nPage);
303 3 : if (!pPage)
304 : {
305 0 : cout << "Failed to retrieve the page object." << endl;
306 0 : return NULL;
307 : }
308 :
309 3 : if (pPage->GetObjCount() != 1)
310 : {
311 0 : cout << "This page should contain one drawing object." << endl;
312 0 : return NULL;
313 : }
314 :
315 3 : const SdrObject* pObj = pPage->GetObj(0);
316 3 : if (!pObj)
317 : {
318 0 : cout << "Failed to retrieve the drawing object." << endl;
319 0 : return NULL;
320 : }
321 :
322 3 : if (pObj->GetObjIdentifier() != OBJ_OLE2)
323 : {
324 0 : cout << "This is not an OLE2 object." << endl;
325 0 : return NULL;
326 : }
327 :
328 3 : const SdrOle2Obj& rOleObj = static_cast<const SdrOle2Obj&>(*pObj);
329 3 : if (!rOleObj.IsChart())
330 : {
331 0 : cout << "This should be a chart object." << endl;
332 0 : return NULL;
333 : }
334 :
335 3 : return &rOleObj;
336 : }
337 :
338 2 : std::vector<OUString> getChartRangeRepresentations(const SdrOle2Obj& rChartObj)
339 : {
340 2 : std::vector<OUString> aRangeReps;
341 :
342 : // Make sure the chart object has correct range references.
343 4 : Reference<frame::XModel> xModel = rChartObj.getXModel();
344 2 : if (!xModel.is())
345 : {
346 0 : cout << "Failed to get the embedded object interface." << endl;
347 0 : return aRangeReps;
348 : }
349 :
350 4 : Reference<chart2::XChartDocument> xChartDoc(xModel, UNO_QUERY);
351 2 : if (!xChartDoc.is())
352 : {
353 0 : cout << "Failed to get the chart document interface." << endl;
354 0 : return aRangeReps;
355 : }
356 :
357 4 : Reference<chart2::data::XDataSource> xDataSource(xChartDoc, UNO_QUERY);
358 2 : if (!xDataSource.is())
359 : {
360 0 : cout << "Failed to get the data source interface." << endl;
361 0 : return aRangeReps;
362 : }
363 :
364 4 : Sequence<Reference<chart2::data::XLabeledDataSequence> > xDataSeqs = xDataSource->getDataSequences();
365 2 : if (!xDataSeqs.getLength())
366 : {
367 0 : cout << "There should be at least one data sequences." << endl;
368 0 : return aRangeReps;
369 : }
370 :
371 4 : Reference<chart2::data::XDataReceiver> xDataRec(xChartDoc, UNO_QUERY);
372 2 : if (!xDataRec.is())
373 : {
374 0 : cout << "Failed to get the data receiver interface." << endl;
375 0 : return aRangeReps;
376 : }
377 :
378 4 : Sequence<OUString> aRangeRepSeqs = xDataRec->getUsedRangeRepresentations();
379 8 : for (sal_Int32 i = 0, n = aRangeRepSeqs.getLength(); i < n; ++i)
380 6 : aRangeReps.push_back(aRangeRepSeqs[i]);
381 :
382 2 : return aRangeReps;
383 : }
384 :
385 2 : ScRangeList getChartRanges(ScDocument& rDoc, const SdrOle2Obj& rChartObj)
386 : {
387 2 : std::vector<OUString> aRangeReps = getChartRangeRepresentations(rChartObj);
388 2 : ScRangeList aRanges;
389 8 : for (size_t i = 0, n = aRangeReps.size(); i < n; ++i)
390 : {
391 6 : ScRange aRange;
392 6 : sal_uInt16 nRes = aRange.Parse(aRangeReps[i], &rDoc, rDoc.GetAddressConvention());
393 6 : if (nRes & SCA_VALID)
394 : // This is a range address.
395 4 : aRanges.Append(aRange);
396 : else
397 : {
398 : // Parse it as a single cell address.
399 2 : ScAddress aAddr;
400 2 : nRes = aAddr.Parse(aRangeReps[i], &rDoc, rDoc.GetAddressConvention());
401 2 : CPPUNIT_ASSERT_MESSAGE("Failed to parse a range representation.", (nRes & SCA_VALID));
402 2 : aRanges.Append(aAddr);
403 : }
404 : }
405 :
406 2 : return aRanges;
407 : }
408 :
409 : namespace {
410 :
411 454 : ScTokenArray* getTokens(ScDocument& rDoc, const ScAddress& rPos)
412 : {
413 454 : ScFormulaCell* pCell = rDoc.GetFormulaCell(rPos);
414 454 : if (!pCell)
415 : {
416 0 : OUString aStr = rPos.Format(SCA_VALID);
417 0 : cerr << aStr << " is not a formula cell." << endl;
418 0 : return NULL;
419 : }
420 :
421 454 : return pCell->GetCode();
422 : }
423 :
424 : }
425 :
426 454 : bool checkFormula(ScDocument& rDoc, const ScAddress& rPos, const char* pExpected)
427 : {
428 454 : ScTokenArray* pCode = getTokens(rDoc, rPos);
429 454 : if (!pCode)
430 : {
431 0 : cerr << "Empty token array." << endl;
432 0 : return false;
433 : }
434 :
435 454 : OUString aFormula = toString(rDoc, rPos, *pCode, rDoc.GetGrammar());
436 454 : if (aFormula != OUString::createFromAscii(pExpected))
437 : {
438 0 : cerr << "Formula '" << pExpected << "' expected, but '" << aFormula << "' found" << endl;
439 0 : return false;
440 : }
441 :
442 454 : return true;
443 : }
444 :
445 6 : bool checkFormulaPosition(ScDocument& rDoc, const ScAddress& rPos)
446 : {
447 6 : OUString aStr(rPos.Format(SCA_VALID));
448 6 : const ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
449 6 : if (!pFC)
450 : {
451 0 : cerr << "Formula cell expected at " << aStr << " but not found." << endl;
452 0 : return false;
453 : }
454 :
455 6 : if (pFC->aPos != rPos)
456 : {
457 0 : OUString aStr2(pFC->aPos.Format(SCA_VALID));
458 0 : cerr << "Formula cell at " << aStr << " has incorrect position of " << aStr2 << endl;
459 0 : return false;
460 : }
461 :
462 6 : return true;
463 : }
464 :
465 2 : bool checkFormulaPositions(
466 : ScDocument& rDoc, SCTAB nTab, SCCOL nCol, const SCROW* pRows, size_t nRowCount)
467 : {
468 2 : ScAddress aPos(nCol, 0, nTab);
469 8 : for (size_t i = 0; i < nRowCount; ++i)
470 : {
471 6 : SCROW nRow = pRows[i];
472 6 : aPos.SetRow(nRow);
473 :
474 6 : if (!checkFormulaPosition(rDoc, aPos))
475 : {
476 0 : OUString aStr(aPos.Format(SCA_VALID));
477 0 : cerr << "Formula cell position failed at " << aStr << "." << endl;
478 0 : return false;
479 : }
480 : }
481 2 : return true;
482 : }
483 :
484 5 : ScTokenArray* compileFormula(
485 : ScDocument* pDoc, const OUString& rFormula, const ScAddress* pPos,
486 : formula::FormulaGrammar::Grammar eGram )
487 : {
488 5 : ScAddress aPos(0,0,0);
489 5 : if (pPos)
490 0 : aPos = *pPos;
491 5 : ScCompiler aComp(pDoc, aPos);
492 5 : aComp.SetGrammar(eGram);
493 5 : return aComp.CompileString(rFormula);
494 : }
495 :
496 0 : void clearFormulaCellChangedFlag( ScDocument& rDoc, const ScRange& rRange )
497 : {
498 0 : const ScAddress& s = rRange.aStart;
499 0 : const ScAddress& e = rRange.aEnd;
500 0 : for (SCTAB nTab = s.Tab(); nTab <= e.Tab(); ++nTab)
501 : {
502 0 : for (SCCOL nCol = s.Col(); nCol <= e.Col(); ++nCol)
503 : {
504 0 : for (SCROW nRow = s.Row(); nRow <= e.Row(); ++nRow)
505 : {
506 0 : ScAddress aPos(nCol, nRow, nTab);
507 0 : ScFormulaCell* pFC = rDoc.GetFormulaCell(aPos);
508 0 : if (pFC)
509 0 : pFC->SetChanged(false);
510 : }
511 : }
512 : }
513 0 : }
514 :
515 228 : bool isFormulaWithoutError(ScDocument& rDoc, const ScAddress& rPos)
516 : {
517 228 : ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
518 228 : if (!pFC)
519 0 : return false;
520 :
521 228 : return pFC->GetErrCode() == 0;
522 : }
523 :
524 458 : OUString toString(
525 : ScDocument& rDoc, const ScAddress& rPos, ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram)
526 : {
527 458 : ScCompiler aComp(&rDoc, rPos, rArray);
528 458 : aComp.SetGrammar(eGram);
529 916 : OUStringBuffer aBuf;
530 458 : aComp.CreateStringFromTokenArray(aBuf);
531 916 : return aBuf.makeStringAndClear();
532 : }
533 :
534 246 : ScDocShellRef ScBootstrapFixture::load( bool bReadWrite,
535 : const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
536 : const OUString& rTypeName, SfxFilterFlags nFilterFlags, SotClipboardFormatId nClipboardID,
537 : sal_uIntPtr nFilterVersion, const OUString* pPassword )
538 : {
539 : SfxFilter* pFilter = new SfxFilter(
540 : rFilter,
541 : OUString(), nFilterFlags, nClipboardID, rTypeName, 0, OUString(),
542 246 : rUserData, OUString("private:factory/scalc*"));
543 246 : pFilter->SetVersion(nFilterVersion);
544 :
545 246 : ScDocShellRef xDocShRef = new ScDocShell;
546 246 : xDocShRef->GetDocument().EnableUserInteraction(false);
547 246 : SfxMedium* pSrcMed = new SfxMedium(rURL, bReadWrite ? STREAM_STD_READWRITE : STREAM_STD_READ );
548 246 : pSrcMed->SetFilter(pFilter);
549 246 : pSrcMed->UseInteractionHandler(false);
550 246 : SfxItemSet* pSet = pSrcMed->GetItemSet();
551 246 : if (pPassword)
552 : {
553 1 : pSet->Put(SfxStringItem(SID_PASSWORD, *pPassword));
554 : }
555 246 : pSet->Put(SfxUInt16Item(SID_MACROEXECMODE,::com::sun::star::document::MacroExecMode::ALWAYS_EXECUTE_NO_WARN));
556 : SAL_INFO( "sc.qa", "about to load " << rURL );
557 246 : if (!xDocShRef->DoLoad(pSrcMed))
558 : {
559 4 : xDocShRef->DoClose();
560 : // load failed.
561 4 : xDocShRef.Clear();
562 : }
563 :
564 246 : return xDocShRef;
565 : }
566 :
567 87 : ScDocShellRef ScBootstrapFixture::load(
568 : const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
569 : const OUString& rTypeName, SfxFilterFlags nFilterFlags, SotClipboardFormatId nClipboardID,
570 : sal_uIntPtr nFilterVersion, const OUString* pPassword )
571 : {
572 87 : return load( false, rURL, rFilter, rUserData, rTypeName, nFilterFlags, nClipboardID, nFilterVersion, pPassword );
573 : }
574 :
575 159 : ScDocShellRef ScBootstrapFixture::loadDoc(
576 : const OUString& rFileName, sal_Int32 nFormat, bool bReadWrite )
577 : {
578 159 : OUString aFileExtension(aFileFormats[nFormat].pName, strlen(aFileFormats[nFormat].pName), RTL_TEXTENCODING_UTF8 );
579 318 : OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
580 318 : OUString aFileName;
581 159 : createFileURL( rFileName, aFileExtension, aFileName );
582 318 : OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
583 159 : SfxFilterFlags nFormatType = aFileFormats[nFormat].nFormatType;
584 159 : SotClipboardFormatId nClipboardId = SotClipboardFormatId::NONE;
585 159 : if (nFormatType != SfxFilterFlags::NONE)
586 159 : nClipboardId = SotClipboardFormatId::STARCALC_8;
587 :
588 318 : return load(bReadWrite, aFileName, aFilterName, OUString(), aFilterType, nFormatType, nClipboardId, static_cast<sal_uIntPtr>(nFormatType));
589 : }
590 :
591 372 : ScBootstrapFixture::ScBootstrapFixture( const OUString& rsBaseString ) : m_aBaseString( rsBaseString ) {}
592 372 : ScBootstrapFixture::~ScBootstrapFixture() {}
593 :
594 : namespace {
595 576 : OUString EnsureSeparator(const OUStringBuffer& rFilePath)
596 : {
597 1152 : return (rFilePath.getLength() == 0) || (rFilePath[rFilePath.getLength() - 1] != '/') ?
598 : OUString("/") :
599 1564 : OUString("");
600 : }
601 : }
602 :
603 164 : void ScBootstrapFixture::createFileURL(
604 : const OUString& aFileBase, const OUString& aFileExtension, OUString& rFilePath)
605 : {
606 164 : OUStringBuffer aBuffer( getSrcRootURL() );
607 164 : aBuffer.append(EnsureSeparator(aBuffer)).append(m_aBaseString);
608 164 : aBuffer.append(EnsureSeparator(aBuffer)).append(aFileExtension);
609 164 : aBuffer.append(EnsureSeparator(aBuffer)).append(aFileBase).append(aFileExtension);
610 164 : rFilePath = aBuffer.makeStringAndClear();
611 164 : }
612 :
613 42 : void ScBootstrapFixture::createCSVPath(const OUString& aFileBase, OUString& rCSVPath)
614 : {
615 42 : OUStringBuffer aBuffer( getSrcRootPath());
616 42 : aBuffer.append(EnsureSeparator(aBuffer)).append(m_aBaseString);
617 42 : aBuffer.append(EnsureSeparator(aBuffer)).append("contentCSV/").append(aFileBase).append("csv");
618 42 : rCSVPath = aBuffer.makeStringAndClear();
619 42 : }
620 :
621 59 : ScDocShellRef ScBootstrapFixture::saveAndReload(
622 : ScDocShell* pShell, const OUString &rFilter,
623 : const OUString &rUserData, const OUString& rTypeName, SfxFilterFlags nFormatType)
624 : {
625 :
626 59 : utl::TempFile aTempFile;
627 118 : SfxMedium aStoreMedium( aTempFile.GetURL(), STREAM_STD_WRITE );
628 59 : SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
629 59 : if (nFormatType == ODS_FORMAT_TYPE)
630 20 : nExportFormat = SotClipboardFormatId::STARCHART_8;
631 : SfxFilter* pExportFilter = new SfxFilter(
632 : rFilter,
633 : OUString(), nFormatType, nExportFormat, rTypeName, 0, OUString(),
634 59 : rUserData, OUString("private:factory/scalc*") );
635 59 : pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
636 59 : aStoreMedium.SetFilter(pExportFilter);
637 59 : pShell->DoSaveAs( aStoreMedium );
638 59 : pShell->DoClose();
639 :
640 : //std::cout << "File: " << aTempFile.GetURL() << std::endl;
641 :
642 59 : SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
643 59 : if (nFormatType == ODS_FORMAT_TYPE)
644 20 : nFormat = SotClipboardFormatId::STARCALC_8;
645 :
646 59 : ScDocShellRef xDocSh = load(aTempFile.GetURL(), rFilter, rUserData, rTypeName, nFormatType, nFormat );
647 59 : if(nFormatType == XLSX_FORMAT_TYPE)
648 24 : validate(aTempFile.GetFileName(), test::OOXML);
649 35 : else if (nFormatType == ODS_FORMAT_TYPE)
650 20 : validate(aTempFile.GetFileName(), test::ODF);
651 59 : aTempFile.EnableKillingFile();
652 118 : return xDocSh;
653 : }
654 :
655 59 : ScDocShellRef ScBootstrapFixture::saveAndReload( ScDocShell* pShell, sal_Int32 nFormat )
656 : {
657 59 : OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
658 118 : OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
659 59 : ScDocShellRef xDocSh = saveAndReload(pShell, aFilterName, OUString(), aFilterType, aFileFormats[nFormat].nFormatType);
660 :
661 59 : CPPUNIT_ASSERT(xDocSh.Is());
662 118 : return xDocSh;
663 : }
664 :
665 9 : boost::shared_ptr<utl::TempFile> ScBootstrapFixture::exportTo( ScDocShell* pShell, sal_Int32 nFormat )
666 : {
667 9 : OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
668 18 : OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
669 :
670 9 : boost::shared_ptr<utl::TempFile> pTempFile(new utl::TempFile());
671 9 : pTempFile->EnableKillingFile();
672 18 : SfxMedium aStoreMedium( pTempFile->GetURL(), STREAM_STD_WRITE );
673 9 : SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
674 9 : SfxFilterFlags nFormatType = aFileFormats[nFormat].nFormatType;
675 9 : if (nFormatType == ODS_FORMAT_TYPE)
676 1 : nExportFormat = SotClipboardFormatId::STARCHART_8;
677 : SfxFilter* pExportFilter = new SfxFilter(
678 : aFilterName,
679 : OUString(), nFormatType, nExportFormat, aFilterType, 0, OUString(),
680 9 : OUString(), OUString("private:factory/scalc*") );
681 9 : pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
682 9 : aStoreMedium.SetFilter(pExportFilter);
683 9 : pShell->DoSaveAs( aStoreMedium );
684 9 : pShell->DoClose();
685 :
686 9 : if(nFormatType == XLSX_FORMAT_TYPE)
687 8 : validate(pTempFile->GetFileName(), test::OOXML);
688 1 : else if (nFormatType == ODS_FORMAT_TYPE)
689 1 : validate(pTempFile->GetFileName(), test::ODF);
690 :
691 18 : return pTempFile;
692 : }
693 :
694 2 : void ScBootstrapFixture::miscRowHeightsTest( TestParam* aTestValues, unsigned int numElems )
695 : {
696 8 : for ( unsigned int index=0; index<numElems; ++index )
697 : {
698 6 : OUString sFileName = OUString::createFromAscii( aTestValues[ index ].sTestDoc );
699 : SAL_INFO( "sc.qa", "aTestValues[" << index << "] " << sFileName );
700 6 : int nImportType = aTestValues[ index ].nImportType;
701 6 : int nExportType = aTestValues[ index ].nExportType;
702 12 : ScDocShellRef xShell = loadDoc( sFileName, nImportType );
703 6 : CPPUNIT_ASSERT(xShell.Is());
704 :
705 6 : if ( nExportType != -1 )
706 4 : xShell = saveAndReload(&(*xShell), nExportType );
707 :
708 6 : CPPUNIT_ASSERT(xShell.Is());
709 :
710 6 : ScDocument& rDoc = xShell->GetDocument();
711 :
712 24 : for (int i=0; i<aTestValues[ index ].nRowData; ++i)
713 : {
714 18 : SCROW nRow = aTestValues[ index ].pData[ i].nStartRow;
715 18 : SCROW nEndRow = aTestValues[ index ].pData[ i ].nEndRow;
716 18 : SCTAB nTab = aTestValues[ index ].pData[ i ].nTab;
717 18 : int nExpectedHeight = aTestValues[ index ].pData[ i ].nExpectedHeight;
718 18 : if ( nExpectedHeight == -1 )
719 2 : nExpectedHeight = sc::TwipsToHMM( ScGlobal::GetStandardRowHeight() );
720 18 : bool bCheckOpt = ( ( aTestValues[ index ].pData[ i ].nCheck & CHECK_OPTIMAL ) == CHECK_OPTIMAL );
721 92 : for ( ; nRow <= nEndRow; ++nRow )
722 : {
723 : SAL_INFO( "sc.qa", " checking row " << nRow << " for height " << nExpectedHeight );
724 74 : int nHeight = sc::TwipsToHMM( rDoc.GetRowHeight(nRow, nTab, false) );
725 74 : if ( bCheckOpt )
726 : {
727 2 : bool bOpt = !(rDoc.GetRowFlags( nRow, nTab ) & CR_MANUALSIZE);
728 2 : CPPUNIT_ASSERT_EQUAL(aTestValues[ index ].pData[ i ].bOptimal, bOpt);
729 : }
730 74 : CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight);
731 : }
732 : }
733 6 : xShell->DoClose();
734 6 : }
735 32 : }
736 :
737 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|