workbook_test_suite.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. // Copyright (c) 2014-2021 Thomas Fussell
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE
  20. //
  21. // @license: http://www.opensource.org/licenses/mit-license.php
  22. // @author: see AUTHORS file
  23. #include <algorithm>
  24. #include <iostream>
  25. #include <xlnt/xlnt.hpp>
  26. #include <detail/serialization/open_stream.hpp>
  27. #include <helpers/temporary_file.hpp>
  28. #include <helpers/test_suite.hpp>
  29. #include <xlnt/cell/cell.hpp>
  30. #include <xlnt/styles/format.hpp>
  31. #include <xlnt/styles/style.hpp>
  32. #include <xlnt/workbook/workbook.hpp>
  33. #include <xlnt/workbook/worksheet_iterator.hpp>
  34. #include <xlnt/worksheet/range.hpp>
  35. #include <xlnt/worksheet/worksheet.hpp>
  36. class workbook_test_suite : public test_suite
  37. {
  38. public:
  39. workbook_test_suite()
  40. {
  41. register_test(test_active_sheet);
  42. register_test(test_create_sheet);
  43. register_test(test_add_correct_sheet);
  44. register_test(test_add_sheet_from_other_workbook);
  45. register_test(test_add_sheet_at_index);
  46. register_test(test_get_sheet_by_title);
  47. register_test(test_get_sheet_by_title_const);
  48. register_test(test_get_sheet_by_index);
  49. register_test(test_get_sheet_by_index_const);
  50. register_test(test_index_operator);
  51. register_test(test_contains);
  52. register_test(test_iter);
  53. register_test(test_const_iter);
  54. register_test(test_get_index);
  55. register_test(test_get_sheet_names);
  56. register_test(test_add_named_range);
  57. register_test(test_get_named_range);
  58. register_test(test_remove_named_range);
  59. register_test(test_post_increment_iterator);
  60. register_test(test_copy_iterator);
  61. register_test(test_manifest);
  62. register_test(test_memory);
  63. register_test(test_clear);
  64. register_test(test_comparison);
  65. register_test(test_id_gen);
  66. register_test(test_load_file);
  67. register_test(test_Issue279);
  68. register_test(test_Issue353);
  69. register_test(test_Issue494);
  70. }
  71. void test_active_sheet()
  72. {
  73. xlnt::workbook wb;
  74. xlnt_assert_equals(wb.active_sheet(), wb[0]);
  75. wb.create_sheet();
  76. wb.create_sheet();
  77. wb.active_sheet(2);
  78. xlnt_assert_equals(wb.active_sheet(), wb[2]);
  79. }
  80. void test_create_sheet()
  81. {
  82. xlnt::workbook wb;
  83. auto new_sheet = wb.create_sheet();
  84. auto last = std::distance(wb.begin(), wb.end()) - 1;
  85. xlnt_assert_equals(new_sheet, wb[last]);
  86. }
  87. void test_add_correct_sheet()
  88. {
  89. xlnt::workbook wb;
  90. auto new_sheet = wb.create_sheet();
  91. new_sheet.cell("A6").value(1.498);
  92. wb.copy_sheet(new_sheet);
  93. xlnt_assert_differs(wb[1].id(), wb[2].id());
  94. xlnt_assert(wb[1].compare(wb[2], false));
  95. wb.create_sheet().cell("A6").value(1.497);
  96. xlnt_assert(!wb[1].compare(wb[3], false));
  97. }
  98. void test_add_sheet_from_other_workbook()
  99. {
  100. xlnt::workbook wb1, wb2;
  101. auto new_sheet = wb1.active_sheet();
  102. xlnt_assert_throws(wb2.copy_sheet(new_sheet), xlnt::invalid_parameter);
  103. xlnt_assert_throws(wb2.index(new_sheet), std::runtime_error);
  104. }
  105. void test_add_sheet_at_index()
  106. {
  107. xlnt::workbook wb;
  108. auto ws = wb.active_sheet();
  109. ws.cell("B3").value(2);
  110. ws.title("Active");
  111. wb.copy_sheet(ws, 0);
  112. xlnt_assert_equals(wb.sheet_titles().at(0), "Sheet1");
  113. xlnt_assert_equals(wb.sheet_by_index(0).cell("B3").value<int>(), 2);
  114. xlnt_assert_equals(wb.sheet_titles().at(1), "Active");
  115. xlnt_assert_equals(wb.sheet_by_index(1).cell("B3").value<int>(), 2);
  116. }
  117. void test_remove_sheet()
  118. {
  119. xlnt::workbook wb, wb2;
  120. auto new_sheet = wb.create_sheet(0);
  121. new_sheet.title("removed");
  122. wb.remove_sheet(new_sheet);
  123. xlnt_assert(!wb.contains("removed"));
  124. xlnt_assert_throws(wb.remove_sheet(wb2.active_sheet()), std::runtime_error);
  125. }
  126. void test_get_sheet_by_title()
  127. {
  128. xlnt::workbook wb;
  129. auto new_sheet = wb.create_sheet();
  130. std::string title = "my sheet";
  131. new_sheet.title(title);
  132. auto found_sheet = wb.sheet_by_title(title);
  133. xlnt_assert_equals(new_sheet, found_sheet);
  134. xlnt_assert_throws(wb.sheet_by_title("error"), xlnt::key_not_found);
  135. const auto &wb_const = wb;
  136. xlnt_assert_throws(wb_const.sheet_by_title("error"), xlnt::key_not_found);
  137. }
  138. void test_get_sheet_by_title_const()
  139. {
  140. xlnt::workbook wb;
  141. auto new_sheet = wb.create_sheet();
  142. std::string title = "my sheet";
  143. new_sheet.title(title);
  144. const xlnt::workbook &wbconst = wb;
  145. auto found_sheet = wbconst.sheet_by_title(title);
  146. xlnt_assert_equals(new_sheet, found_sheet);
  147. }
  148. void test_get_sheet_by_index()
  149. {
  150. xlnt::workbook wb;
  151. auto new_sheet = wb.create_sheet();
  152. xlnt_assert_equals(new_sheet, wb.sheet_by_index(1)); // in range
  153. xlnt_assert_throws(wb.sheet_by_index(2), xlnt::invalid_parameter); // out of range
  154. }
  155. void test_get_sheet_by_index_const()
  156. {
  157. xlnt::workbook wb;
  158. auto new_sheet = wb.create_sheet();
  159. const auto &wb_const = wb;
  160. xlnt_assert_equals(new_sheet, wb_const.sheet_by_index(1)); // in range
  161. xlnt_assert_throws(wb_const.sheet_by_index(2), xlnt::invalid_parameter); // out of range
  162. }
  163. void test_index_operator() // test_getitem
  164. {
  165. xlnt::workbook wb;
  166. xlnt_assert_throws_nothing(wb["Sheet1"]);
  167. xlnt_assert_throws(wb["NotThere"], xlnt::key_not_found);
  168. }
  169. void test_contains()
  170. {
  171. xlnt::workbook wb;
  172. xlnt_assert(wb.contains("Sheet1"));
  173. xlnt_assert(!wb.contains("NotThere"));
  174. }
  175. void test_iter()
  176. {
  177. xlnt::workbook wb;
  178. for (auto ws : wb)
  179. {
  180. xlnt_assert_equals(ws.title(), "Sheet1");
  181. }
  182. xlnt::workbook wb2;
  183. auto iter = wb.begin();
  184. auto iter_copy(iter); // copy ctor
  185. xlnt_assert_equals(iter, iter_copy);
  186. auto begin_2(wb2.begin());
  187. xlnt_assert_differs(begin_2, iter);
  188. iter = begin_2; // copy assign
  189. xlnt_assert_equals(iter, begin_2);
  190. iter = wb.begin();
  191. iter = std::move(begin_2);
  192. xlnt_assert_equals(iter, wb2.begin());
  193. auto citer = wb.cbegin();
  194. auto citer_copy(citer); // copy ctor
  195. xlnt_assert_equals(citer, citer_copy);
  196. auto cbegin_2(wb2.cbegin());
  197. xlnt_assert_differs(cbegin_2, citer);
  198. citer = cbegin_2; // copy assign
  199. xlnt_assert_equals(citer, cbegin_2);
  200. citer = wb.cbegin();
  201. citer = std::move(cbegin_2);
  202. xlnt_assert_equals(citer, wb2.cbegin());
  203. wb2.create_sheet(); // wb2 iterators assumed invalidated
  204. iter = wb2.begin();
  205. xlnt_assert_equals((*iter).title(), "Sheet1");
  206. ++iter;
  207. xlnt_assert_differs(iter, wb2.begin());
  208. xlnt_assert_equals((*iter).title(), "Sheet2");
  209. auto temp = --iter;
  210. xlnt_assert_equals((*temp).title(), "Sheet1");
  211. xlnt_assert_equals((*iter).title(), "Sheet1");
  212. iter++;
  213. xlnt_assert_equals((*iter).title(), "Sheet2");
  214. temp = iter++;
  215. xlnt_assert_equals((*temp).title(), "Sheet2");
  216. xlnt_assert_equals(iter, wb2.end());
  217. iter = temp--;
  218. xlnt_assert_equals((*iter).title(), "Sheet2");
  219. xlnt_assert_equals((*temp).title(), "Sheet1");
  220. xlnt_assert_equals(xlnt::worksheet_iterator{}, xlnt::worksheet_iterator{});
  221. }
  222. void test_const_iter()
  223. {
  224. const xlnt::workbook wb;
  225. for (auto ws : wb)
  226. {
  227. xlnt_assert_equals(ws.title(), "Sheet1");
  228. }
  229. xlnt::workbook wb2;
  230. auto iter = wb.cbegin();
  231. auto iter_copy(iter); // copy ctor
  232. xlnt_assert_equals(iter, iter_copy);
  233. auto begin_2(wb2.cbegin());
  234. xlnt_assert_differs(begin_2, iter);
  235. iter = begin_2; // copy assign
  236. xlnt_assert_equals(iter, begin_2);
  237. iter = wb.cbegin();
  238. iter = std::move(begin_2);
  239. xlnt_assert_equals(iter, wb2.cbegin());
  240. // wb2 iterators assumed invalidated
  241. wb2.create_sheet();
  242. iter = wb2.cbegin();
  243. xlnt_assert_equals((*iter).title(), "Sheet1");
  244. ++iter;
  245. xlnt_assert_differs(iter, wb2.cbegin());
  246. xlnt_assert_equals((*iter).title(), "Sheet2");
  247. auto temp = --iter;
  248. xlnt_assert_equals((*temp).title(), "Sheet1");
  249. xlnt_assert_equals((*iter).title(), "Sheet1");
  250. iter++;
  251. xlnt_assert_equals((*iter).title(), "Sheet2");
  252. temp = iter++;
  253. xlnt_assert_equals((*temp).title(), "Sheet2");
  254. xlnt_assert_equals(iter, wb2.cend());
  255. iter = temp--;
  256. xlnt_assert_equals((*iter).title(), "Sheet2");
  257. xlnt_assert_equals((*temp).title(), "Sheet1");
  258. xlnt_assert_equals(xlnt::const_worksheet_iterator{}, xlnt::const_worksheet_iterator{});
  259. }
  260. void test_get_index()
  261. {
  262. xlnt::workbook wb;
  263. wb.create_sheet().title("1");
  264. wb.create_sheet().title("2");
  265. auto sheet_index = wb.index(wb.sheet_by_title("1"));
  266. xlnt_assert_equals(sheet_index, 1);
  267. sheet_index = wb.index(wb.sheet_by_title("2"));
  268. xlnt_assert_equals(sheet_index, 2);
  269. }
  270. void test_get_sheet_names()
  271. {
  272. xlnt::workbook wb;
  273. wb.create_sheet().title("test_get_sheet_titles");
  274. const std::vector<std::string> expected_titles = {"Sheet1", "test_get_sheet_titles"};
  275. xlnt_assert_equals(wb.sheet_titles(), expected_titles);
  276. }
  277. void test_add_named_range()
  278. {
  279. xlnt::workbook wb, wb2;
  280. auto new_sheet = wb.create_sheet();
  281. wb.create_named_range("test_nr", new_sheet, "A1");
  282. xlnt_assert(new_sheet.has_named_range("test_nr"));
  283. xlnt_assert(wb.has_named_range("test_nr"));
  284. xlnt_assert_throws(wb2.create_named_range("test_nr", new_sheet, "A1"), std::runtime_error);
  285. }
  286. void test_get_named_range()
  287. {
  288. xlnt::workbook wb;
  289. auto new_sheet = wb.create_sheet();
  290. wb.create_named_range("test_nr", new_sheet, "A1");
  291. auto found_range = wb.named_range("test_nr");
  292. auto expected_range = new_sheet.range("A1");
  293. xlnt_assert_equals(expected_range, found_range);
  294. xlnt_assert_throws(wb.named_range("test_nr2"), std::runtime_error);
  295. }
  296. void test_remove_named_range()
  297. {
  298. xlnt::workbook wb;
  299. auto new_sheet = wb.create_sheet();
  300. wb.create_named_range("test_nr", new_sheet, "A1");
  301. wb.remove_named_range("test_nr");
  302. xlnt_assert(!new_sheet.has_named_range("test_nr"));
  303. xlnt_assert(!wb.has_named_range("test_nr"));
  304. xlnt_assert_throws(wb.remove_named_range("test_nr2"), std::runtime_error);
  305. }
  306. void test_post_increment_iterator()
  307. {
  308. xlnt::workbook wb;
  309. wb.create_sheet().title("Sheet2");
  310. wb.create_sheet().title("Sheet3");
  311. auto iter = wb.begin();
  312. xlnt_assert_equals((*(iter++)).title(), "Sheet1");
  313. xlnt_assert_equals((*(iter++)).title(), "Sheet2");
  314. xlnt_assert_equals((*(iter++)).title(), "Sheet3");
  315. xlnt_assert_equals(iter, wb.end());
  316. const auto wb_const = wb;
  317. auto const_iter = wb_const.begin();
  318. xlnt_assert_equals((*(const_iter++)).title(), "Sheet1");
  319. xlnt_assert_equals((*(const_iter++)).title(), "Sheet2");
  320. xlnt_assert_equals((*(const_iter++)).title(), "Sheet3");
  321. xlnt_assert_equals(const_iter, wb_const.end());
  322. }
  323. void test_copy_iterator()
  324. {
  325. xlnt::workbook wb;
  326. wb.create_sheet().title("Sheet2");
  327. wb.create_sheet().title("Sheet3");
  328. auto iter = wb.begin();
  329. xlnt_assert_equals((*iter).title(), "Sheet1");
  330. iter++;
  331. xlnt_assert_equals((*iter).title(), "Sheet2");
  332. auto copy = wb.begin();
  333. copy = iter;
  334. xlnt_assert_equals((*iter).title(), "Sheet2");
  335. xlnt_assert_equals(iter, copy);
  336. iter++;
  337. xlnt_assert_equals((*iter).title(), "Sheet3");
  338. xlnt_assert_differs(iter, copy);
  339. copy++;
  340. xlnt_assert_equals((*iter).title(), "Sheet3");
  341. xlnt_assert_equals(iter, copy);
  342. }
  343. void test_manifest()
  344. {
  345. xlnt::manifest m;
  346. xlnt_assert(!m.has_default_type("xml"));
  347. xlnt_assert_throws(m.default_type("xml"), xlnt::key_not_found);
  348. xlnt_assert(!m.has_relationship(xlnt::path("/"), xlnt::relationship_type::office_document));
  349. xlnt_assert(m.relationships(xlnt::path("xl/workbook.xml")).empty());
  350. }
  351. void test_memory()
  352. {
  353. xlnt::workbook wb, wb2;
  354. wb.active_sheet().title("swap");
  355. std::swap(wb, wb2);
  356. xlnt_assert_equals(wb.active_sheet().title(), "Sheet1");
  357. xlnt_assert_equals(wb2.active_sheet().title(), "swap");
  358. wb = wb2;
  359. xlnt_assert_equals(wb.active_sheet().title(), "swap");
  360. }
  361. void test_clear()
  362. {
  363. xlnt::workbook wb;
  364. xlnt::style s = wb.create_style("s");
  365. wb.active_sheet().cell("B2").value("B2");
  366. wb.active_sheet().cell("B2").style(s);
  367. xlnt_assert(wb.active_sheet().cell("B2").has_style());
  368. wb.clear_styles();
  369. xlnt_assert(!wb.active_sheet().cell("B2").has_style());
  370. xlnt::format format = wb.create_format();
  371. xlnt::font font;
  372. font.size(41);
  373. format.font(font, true);
  374. wb.active_sheet().cell("B2").format(format);
  375. xlnt_assert(wb.active_sheet().cell("B2").has_format());
  376. wb.clear_formats();
  377. xlnt_assert(!wb.active_sheet().cell("B2").has_format());
  378. wb.clear();
  379. xlnt_assert(wb.sheet_titles().empty());
  380. }
  381. void test_comparison()
  382. {
  383. xlnt::workbook wb, wb2;
  384. xlnt_assert(wb == wb);
  385. xlnt_assert(!(wb != wb));
  386. xlnt_assert(!(wb == wb2));
  387. xlnt_assert(wb != wb2);
  388. const auto &wb_const = wb;
  389. //TODO these aren't tests...
  390. wb_const.manifest();
  391. xlnt_assert(wb.has_theme());
  392. wb.create_style("style1");
  393. wb.style("style1");
  394. wb_const.style("style1");
  395. }
  396. void test_id_gen()
  397. {
  398. xlnt::workbook wb;
  399. wb.create_sheet();
  400. wb.create_sheet();
  401. wb.remove_sheet(wb[1]);
  402. wb.create_sheet();
  403. xlnt_assert_differs(wb[1].id(), wb[2].id());
  404. }
  405. void test_load_file()
  406. {
  407. xlnt::path file = path_helper::test_file("2_minimal.xlsx");
  408. xlnt::workbook wb_path(file);
  409. // ctor from ifstream
  410. std::ifstream file_reader(file.string(), std::ios::binary);
  411. xlnt_assert_equals(wb_path, xlnt::workbook(file_reader));
  412. // load with string
  413. xlnt::workbook wb_load1;
  414. xlnt_assert_differs(wb_path, wb_load1);
  415. wb_load1.load(file.string());
  416. xlnt_assert_equals(wb_path, wb_load1);
  417. // load with wstring
  418. xlnt::workbook wb_load2;
  419. wb_load2.load(file.string());
  420. xlnt_assert_equals(wb_path, wb_load2);
  421. // load with path
  422. xlnt::workbook wb_load3;
  423. wb_load3.load(file);
  424. xlnt_assert_equals(wb_path, wb_load3);
  425. // load with istream
  426. xlnt::workbook wb_load4;
  427. std::ifstream file_reader2(file.string(), std::ios::binary);
  428. wb_load4.load(file_reader2);
  429. xlnt_assert_equals(wb_path, wb_load4);
  430. // load with vector
  431. std::ifstream file_reader3(file.string(), std::ios::binary);
  432. file_reader3.unsetf(std::ios::skipws);
  433. std::vector<uint8_t> data(std::istream_iterator<uint8_t>{file_reader3},
  434. std::istream_iterator<uint8_t>());
  435. xlnt::workbook wb_load5;
  436. wb_load5.load(data);
  437. xlnt_assert_equals(wb_path, wb_load5);
  438. }
  439. void test_Issue279()
  440. {
  441. xlnt::workbook wb(path_helper::test_file("Issue279_workbook_delete_rename.xlsx"));
  442. while (wb.sheet_count() > 1)
  443. {
  444. if (wb[1].title() != "BOM")
  445. {
  446. wb.remove_sheet(wb[1]);
  447. }
  448. else
  449. {
  450. wb.remove_sheet(wb[0]);
  451. }
  452. }
  453. // get sheet bom change title
  454. auto ws1 = wb.sheet_by_index(0);
  455. ws1.title("checkedBom");
  456. // report sheet
  457. auto ws2 = wb.create_sheet(1);
  458. ws2.title("REPORT");
  459. //save a copy file
  460. wb.save("temp.xlsx");
  461. }
  462. void test_Issue353()
  463. {
  464. xlnt::workbook wb1;
  465. wb1.load(path_helper::test_file("Issue353_first_row_empty_w_properties.xlsx"));
  466. wb1.save("temp_issue353.xlsx");
  467. xlnt::workbook wb2;
  468. wb2.load("temp_issue353.xlsx");
  469. auto ws = wb2.active_sheet();
  470. xlnt_assert_equals(ws.row_properties(1).spans.get(), "1:8");
  471. xlnt_assert_equals(ws.row_properties(17).spans.get(), "2:7");
  472. }
  473. void test_Issue494()
  474. {
  475. xlnt::workbook wb;
  476. wb.load(path_helper::test_file("Issue494_shared_string.xlsx"));
  477. auto ws = wb.active_sheet();
  478. xlnt_assert_equals(ws.cell(2, 1).to_string(), "V1.00");
  479. xlnt_assert_equals(ws.cell(2, 2).to_string(), "V1.00");
  480. }
  481. };
  482. static workbook_test_suite x;