TestCsvParser.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * Copyright (C) 2015 Enrico Mariotti <enricomariotti@yahoo.it>
  3. * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 or (at your option)
  8. * version 3 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "TestCsvParser.h"
  19. #include <QTest>
  20. QTEST_GUILESS_MAIN(TestCsvParser)
  21. void TestCsvParser::writeToFile(const QString& contents)
  22. {
  23. if (!file->open()) {
  24. QFAIL("Cannot open temporary file!");
  25. }
  26. QTextStream out(file.data());
  27. out.setCodec("UTF-8");
  28. out << contents;
  29. out.flush();
  30. file->close();
  31. }
  32. void TestCsvParser::initTestCase()
  33. {
  34. parser.reset(new CsvParser());
  35. }
  36. void TestCsvParser::init()
  37. {
  38. file.reset(new QTemporaryFile());
  39. parser->setBackslashSyntax(false);
  40. parser->setComment('#');
  41. parser->setFieldSeparator(',');
  42. parser->setTextQualifier(QChar('"'));
  43. }
  44. void TestCsvParser::cleanup()
  45. {
  46. file->remove();
  47. }
  48. /****************** TEST CASES ******************/
  49. void TestCsvParser::testMissingQuote()
  50. {
  51. writeToFile("A,B\n:BM,1");
  52. parser->setTextQualifier(':');
  53. QVERIFY(!parser->parse(file.data()));
  54. QWARN(parser->getStatus().toLatin1());
  55. }
  56. void TestCsvParser::testMalformed()
  57. {
  58. writeToFile("A,B,C\n:BM::,1,:2:");
  59. parser->setTextQualifier(':');
  60. QVERIFY(!parser->parse(file.data()));
  61. QWARN(parser->getStatus().toLatin1());
  62. }
  63. void TestCsvParser::testBackslashSyntax()
  64. {
  65. // attended result: one"\t\"wo
  66. writeToFile("Xone\\\"\\\\t\\\\\\\"w\noX\n"
  67. "X13X,X2\\X,X,\"\"3\"X\r"
  68. "3,X\"4\"X,,\n"
  69. "XX\n"
  70. "\\");
  71. parser->setBackslashSyntax(true);
  72. parser->setTextQualifier(QChar('X'));
  73. QVERIFY(parser->parse(file.data()));
  74. t = parser->getCsvTable();
  75. QVERIFY(t.at(0).at(0) == "one\"\\t\\\"w\no");
  76. QVERIFY(t.at(1).at(0) == "13");
  77. QVERIFY(t.at(1).at(1) == "2X,");
  78. QVERIFY(t.at(1).at(2) == "\"\"3\"X");
  79. QVERIFY(t.at(2).at(0) == "3");
  80. QVERIFY(t.at(2).at(1) == "\"4\"");
  81. QVERIFY(t.at(2).at(2) == "");
  82. QVERIFY(t.at(2).at(3) == "");
  83. QVERIFY(t.at(3).at(0) == "\\");
  84. QVERIFY(t.size() == 4);
  85. }
  86. void TestCsvParser::testQuoted()
  87. {
  88. writeToFile("ro,w,\"end, of \"\"\"\"\"\"row\"\"\"\"\"\n"
  89. "2\n");
  90. QVERIFY(parser->parse(file.data()));
  91. t = parser->getCsvTable();
  92. QVERIFY(t.at(0).at(0) == "ro");
  93. QVERIFY(t.at(0).at(1) == "w");
  94. QVERIFY(t.at(0).at(2) == "end, of \"\"\"row\"\"");
  95. QVERIFY(t.at(1).at(0) == "2");
  96. QVERIFY(t.size() == 2);
  97. }
  98. void TestCsvParser::testEmptySimple()
  99. {
  100. QVERIFY(parser->parse(file.data()));
  101. t = parser->getCsvTable();
  102. QVERIFY(t.isEmpty());
  103. }
  104. void TestCsvParser::testEmptyQuoted()
  105. {
  106. writeToFile("\"\"");
  107. QVERIFY(parser->parse(file.data()));
  108. t = parser->getCsvTable();
  109. QVERIFY(t.isEmpty());
  110. }
  111. void TestCsvParser::testEmptyNewline()
  112. {
  113. writeToFile("\"\n\"");
  114. QVERIFY(parser->parse(file.data()));
  115. t = parser->getCsvTable();
  116. QVERIFY(t.isEmpty());
  117. }
  118. void TestCsvParser::testEmptyFile()
  119. {
  120. QVERIFY(parser->parse(file.data()));
  121. t = parser->getCsvTable();
  122. QVERIFY(t.isEmpty());
  123. }
  124. void TestCsvParser::testNewline()
  125. {
  126. writeToFile("1,2\n\n\n");
  127. QVERIFY(parser->parse(file.data()));
  128. t = parser->getCsvTable();
  129. QVERIFY(t.size() == 1);
  130. QVERIFY(t.at(0).at(0) == "1");
  131. QVERIFY(t.at(0).at(1) == "2");
  132. }
  133. void TestCsvParser::testCR()
  134. {
  135. writeToFile("1,2\r3,4");
  136. QVERIFY(parser->parse(file.data()));
  137. t = parser->getCsvTable();
  138. QVERIFY(t.size() == 2);
  139. QVERIFY(t.at(0).at(0) == "1");
  140. QVERIFY(t.at(0).at(1) == "2");
  141. QVERIFY(t.at(1).at(0) == "3");
  142. QVERIFY(t.at(1).at(1) == "4");
  143. }
  144. void TestCsvParser::testLF()
  145. {
  146. writeToFile("1,2\n3,4");
  147. QVERIFY(parser->parse(file.data()));
  148. t = parser->getCsvTable();
  149. QVERIFY(t.size() == 2);
  150. QVERIFY(t.at(0).at(0) == "1");
  151. QVERIFY(t.at(0).at(1) == "2");
  152. QVERIFY(t.at(1).at(0) == "3");
  153. QVERIFY(t.at(1).at(1) == "4");
  154. }
  155. void TestCsvParser::testCRLF()
  156. {
  157. writeToFile("1,2\r\n3,4");
  158. QVERIFY(parser->parse(file.data()));
  159. t = parser->getCsvTable();
  160. QVERIFY(t.size() == 2);
  161. QVERIFY(t.at(0).at(0) == "1");
  162. QVERIFY(t.at(0).at(1) == "2");
  163. QVERIFY(t.at(1).at(0) == "3");
  164. QVERIFY(t.at(1).at(1) == "4");
  165. }
  166. void TestCsvParser::testComments()
  167. {
  168. writeToFile(" #one\n"
  169. " \t # two, three \r\n"
  170. " #, sing\t with\r"
  171. " #\t me!\n"
  172. "useful,text #1!");
  173. QVERIFY(parser->parse(file.data()));
  174. t = parser->getCsvTable();
  175. QVERIFY(t.size() == 1);
  176. QVERIFY(t.at(0).at(0) == "useful");
  177. QVERIFY(t.at(0).at(1) == "text #1!");
  178. }
  179. void TestCsvParser::testColumns()
  180. {
  181. writeToFile("1,2\n"
  182. ",,,,,,,,,a\n"
  183. "a,b,c,d\n");
  184. QVERIFY(parser->parse(file.data()));
  185. t = parser->getCsvTable();
  186. QVERIFY(parser->getCsvCols() == 10);
  187. }
  188. void TestCsvParser::testSimple()
  189. {
  190. writeToFile(",,2\r,2,3\n"
  191. "A,,B\"\n"
  192. " ,,\n");
  193. QVERIFY(parser->parse(file.data()));
  194. t = parser->getCsvTable();
  195. QVERIFY(t.size() == 4);
  196. QVERIFY(t.at(0).at(0) == "");
  197. QVERIFY(t.at(0).at(1) == "");
  198. QVERIFY(t.at(0).at(2) == "2");
  199. QVERIFY(t.at(1).at(0) == "");
  200. QVERIFY(t.at(1).at(1) == "2");
  201. QVERIFY(t.at(1).at(2) == "3");
  202. QVERIFY(t.at(2).at(0) == "A");
  203. QVERIFY(t.at(2).at(1) == "");
  204. QVERIFY(t.at(2).at(2) == "B\"");
  205. QVERIFY(t.at(3).at(0) == " ");
  206. QVERIFY(t.at(3).at(1) == "");
  207. QVERIFY(t.at(3).at(2) == "");
  208. }
  209. void TestCsvParser::testSeparator()
  210. {
  211. writeToFile("\t\t2\r\t2\t3\n"
  212. "A\t\tB\"\n"
  213. " \t\t\n");
  214. parser->setFieldSeparator('\t');
  215. QVERIFY(parser->parse(file.data()));
  216. t = parser->getCsvTable();
  217. QVERIFY(t.size() == 4);
  218. QVERIFY(t.at(0).at(0) == "");
  219. QVERIFY(t.at(0).at(1) == "");
  220. QVERIFY(t.at(0).at(2) == "2");
  221. QVERIFY(t.at(1).at(0) == "");
  222. QVERIFY(t.at(1).at(1) == "2");
  223. QVERIFY(t.at(1).at(2) == "3");
  224. QVERIFY(t.at(2).at(0) == "A");
  225. QVERIFY(t.at(2).at(1) == "");
  226. QVERIFY(t.at(2).at(2) == "B\"");
  227. QVERIFY(t.at(3).at(0) == " ");
  228. QVERIFY(t.at(3).at(1) == "");
  229. QVERIFY(t.at(3).at(2) == "");
  230. }
  231. void TestCsvParser::testMultiline()
  232. {
  233. writeToFile(":1\r\n2a::b:,:3\r4:\n"
  234. "2\n");
  235. parser->setTextQualifier(QChar(':'));
  236. QVERIFY(parser->parse(file.data()));
  237. t = parser->getCsvTable();
  238. QVERIFY(t.at(0).at(0) == "1\n2a:b");
  239. QVERIFY(t.at(0).at(1) == "3\n4");
  240. QVERIFY(t.at(1).at(0) == "2");
  241. QVERIFY(t.size() == 2);
  242. }
  243. void TestCsvParser::testReparsing()
  244. {
  245. writeToFile(":te\r\nxt1:,:te\rxt2:,:end of \"this\n string\":\n"
  246. "2\n");
  247. QVERIFY(parser->parse(file.data()));
  248. t = parser->getCsvTable();
  249. QCOMPARE(t.at(0).at(0), QString(":te"));
  250. parser->setTextQualifier(QChar(':'));
  251. QVERIFY(parser->reparse());
  252. t = parser->getCsvTable();
  253. QCOMPARE(t.at(0).at(0), QString("te\nxt1"));
  254. QCOMPARE(t.at(0).at(1), QString("te\nxt2"));
  255. QCOMPARE(t.at(0).at(2), QString("end of \"this\n string\""));
  256. QCOMPARE(t.at(1).at(0), QString("2"));
  257. QCOMPARE(t.size(), 2);
  258. }
  259. void TestCsvParser::testQualifier()
  260. {
  261. writeToFile("X1X,X2XX,X,\"\"3\"\"\"X\r"
  262. "3,X\"4\"X,,\n");
  263. parser->setTextQualifier(QChar('X'));
  264. QVERIFY(parser->parse(file.data()));
  265. t = parser->getCsvTable();
  266. QVERIFY(t.size() == 2);
  267. QVERIFY(t.at(0).at(0) == "1");
  268. QVERIFY(t.at(0).at(1) == "2X,");
  269. QVERIFY(t.at(0).at(2) == "\"\"3\"\"\"X");
  270. QVERIFY(t.at(1).at(0) == "3");
  271. QVERIFY(t.at(1).at(1) == "\"4\"");
  272. QVERIFY(t.at(1).at(2) == "");
  273. QVERIFY(t.at(1).at(3) == "");
  274. }
  275. void TestCsvParser::testUnicode()
  276. {
  277. // QString m("Texte en fran\u00e7ais");
  278. // CORRECT QString g("\u20AC");
  279. // CORRECT QChar g(0x20AC);
  280. // ERROR QChar g("\u20AC");
  281. writeToFile("€1A2śA\"3śAż\"Ażac");
  282. parser->setFieldSeparator(QChar('A'));
  283. QVERIFY(parser->parse(file.data()));
  284. t = parser->getCsvTable();
  285. QVERIFY(t.size() == 1);
  286. QVERIFY(t.at(0).at(0) == "€1");
  287. QVERIFY(t.at(0).at(1) == "2ś");
  288. QVERIFY(t.at(0).at(2) == "3śAż");
  289. QVERIFY(t.at(0).at(3) == "żac");
  290. }