1 #include <cppunit/CompilerOutputter.h>
2 #include <cppunit/TestCaller.h>
3 #include <cppunit/TestFixture.h>
4 #include <cppunit/extensions/TestFactoryRegistry.h>
5 #include <cppunit/ui/text/TestRunner.h>
6 
7 #include "csvline.hh"
8 
9 class CSVLineTest : public CppUnit::TestFixture {
10    public:
suite()11     static CppUnit::TestSuite *suite() {
12         CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite("CSV Line");
13 
14         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
15             "should produce correct line on empty fields",
16             &CSVLineTest::getEmptyLine));
17 
18         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
19             "should return fields unescaped",
20             &CSVLineTest::getFieldsUnescaped));
21 
22         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
23             "should produce correct line", &CSVLineTest::getLine));
24 
25         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
26             "should throw on adding to much fields",
27             &CSVLineTest::throwTooMuchFields));
28 
29         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
30             "should throw on getting invalid index",
31             &CSVLineTest::throwInvalidIndex));
32 
33         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
34             "should parse line correctly", &CSVLineTest::parseLine));
35 
36         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
37             "should parse corner case lines correctly",
38             &CSVLineTest::parseCornerCases));
39 
40         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
41             "should parse empty CSV line correctly",
42             &CSVLineTest::parseEmptyCsvLine));
43 
44         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
45             "should throw on empty line", &CSVLineTest::throwEmptyLine));
46 
47         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
48             "should throw on malformed line",
49             &CSVLineTest::throwMalformedLine));
50 
51         suiteOfTests->addTest(new CppUnit::TestCaller<CSVLineTest>(
52             "should use different separator", &CSVLineTest::separator));
53 
54         return suiteOfTests;
55     }
56 
getEmptyLine()57     void getEmptyLine() {
58         yapet::CSVLine csvLine{3};
59 
60         std::string actual{csvLine.getLine()};
61         std::string expected{",,"};
62         CPPUNIT_ASSERT_EQUAL(expected, actual);
63     }
64 
getFieldsUnescaped()65     void getFieldsUnescaped() {
66         yapet::CSVLine csvLine{1};
67 
68         csvLine.addField(0, "\",\"");
69 
70         std::string actual{csvLine[0]};
71         std::string expected{","};
72         CPPUNIT_ASSERT_EQUAL(expected, actual);
73     }
74 
getLine()75     void getLine() {
76         yapet::CSVLine csvLine{3};
77 
78         csvLine.addField(0, "Field 1");
79         csvLine.addField(1, "Field,2");
80         csvLine.addField(2, "Field\",3");
81 
82         std::string actual{csvLine.getLine()};
83         std::string expected{"Field 1,\"Field,2\",\"Field\"\",3\""};
84         CPPUNIT_ASSERT_EQUAL(expected, actual);
85     }
86 
throwTooMuchFields()87     void throwTooMuchFields() {
88         yapet::CSVLine csvLine{2};
89 
90         CPPUNIT_ASSERT_THROW(csvLine.addField(3, ""), std::out_of_range);
91         CPPUNIT_ASSERT_THROW(csvLine[3], std::out_of_range);
92     }
93 
throwInvalidIndex()94     void throwInvalidIndex() {
95         yapet::CSVLine csvLine{2};
96         CPPUNIT_ASSERT_THROW(csvLine[3], std::out_of_range);
97     }
98 
parseLine()99     void parseLine() {
100         yapet::CSVLine csvLine1{3};
101         csvLine1.parseLine("a,b,c");
102         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine1[0]);
103         CPPUNIT_ASSERT_EQUAL(std::string{"b"}, csvLine1[1]);
104         CPPUNIT_ASSERT_EQUAL(std::string{"c"}, csvLine1[2]);
105 
106         yapet::CSVLine csvLine2{1};
107         csvLine2.parseLine("a");
108         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine2[0]);
109 
110         yapet::CSVLine csvLine3{2};
111         CPPUNIT_ASSERT_THROW(csvLine3.parseLine("a,b,c"),
112                              std::invalid_argument);
113 
114         yapet::CSVLine csvLine4{2};
115         CPPUNIT_ASSERT_THROW(csvLine4.parseLine("a"), std::invalid_argument);
116     }
117 
parseCornerCases()118     void parseCornerCases() {
119         yapet::CSVLine csvLine2{2};
120         csvLine2.parseLine("\"a,\",b\"");
121         CPPUNIT_ASSERT_EQUAL(std::string{"a,"}, csvLine2[0]);
122         CPPUNIT_ASSERT_EQUAL(std::string{"b\""}, csvLine2[1]);
123 
124         yapet::CSVLine csvLine3{3};
125         csvLine3.parseLine("a,b\",");
126         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
127         CPPUNIT_ASSERT_EQUAL(std::string{"b\""}, csvLine3[1]);
128         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
129 
130         csvLine3.parseLine("a,\"b,\"\"\",");
131         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
132         CPPUNIT_ASSERT_EQUAL(std::string{"b,\""}, csvLine3[1]);
133         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
134 
135         // Start of line
136         csvLine3.parseLine("\"\"\"\",a,");
137         CPPUNIT_ASSERT_EQUAL(std::string{"\""}, csvLine3[0]);
138         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[1]);
139         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
140 
141         csvLine3.parseLine("\",\"\"\",a,");
142         CPPUNIT_ASSERT_EQUAL(std::string{",\""}, csvLine3[0]);
143         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[1]);
144         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
145 
146         csvLine3.parseLine("\"\"\",\",a,");
147         CPPUNIT_ASSERT_EQUAL(std::string{"\","}, csvLine3[0]);
148         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[1]);
149         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
150 
151         // In middle of line
152         csvLine3.parseLine("a,\"\"\"\",");
153         CPPUNIT_ASSERT_EQUAL(std::string{"\""}, csvLine3[1]);
154         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
155         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
156 
157         csvLine3.parseLine("a,\",\"\"\",");
158         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
159         CPPUNIT_ASSERT_EQUAL(std::string{",\""}, csvLine3[1]);
160         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
161 
162         csvLine3.parseLine("a,\"\"\",\",");
163         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
164         CPPUNIT_ASSERT_EQUAL(std::string{"\","}, csvLine3[1]);
165         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine3[2]);
166 
167         // at end of line
168         csvLine3.parseLine("a,b,\"\"\"\"");
169         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
170         CPPUNIT_ASSERT_EQUAL(std::string{"b"}, csvLine3[1]);
171         CPPUNIT_ASSERT_EQUAL(std::string{"\""}, csvLine3[2]);
172 
173         csvLine3.parseLine("a,b,\",\"\"\"");
174         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
175         CPPUNIT_ASSERT_EQUAL(std::string{"b"}, csvLine3[1]);
176         CPPUNIT_ASSERT_EQUAL(std::string{",\""}, csvLine3[2]);
177 
178         csvLine3.parseLine("a,,\"\"\",\"");
179         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
180         CPPUNIT_ASSERT_EQUAL(std::string{""}, csvLine3[1]);
181         CPPUNIT_ASSERT_EQUAL(std::string{"\","}, csvLine3[2]);
182 
183         csvLine3.parseLine("a,\"b\",\"c\"");
184         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
185         CPPUNIT_ASSERT_EQUAL(std::string{"b"}, csvLine3[1]);
186         CPPUNIT_ASSERT_EQUAL(std::string{"c"}, csvLine3[2]);
187 
188         csvLine2.parseLine("a\",b");
189         CPPUNIT_ASSERT_EQUAL(std::string{"a\""}, csvLine2[0]);
190         CPPUNIT_ASSERT_EQUAL(std::string{"b"}, csvLine2[1]);
191 
192         csvLine2.parseLine("a,\"b\"\",c\"");
193         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine2[0]);
194         CPPUNIT_ASSERT_EQUAL(std::string{"b\",c"}, csvLine2[1]);
195 
196         csvLine2.parseLine("a,\"\"");
197         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine2[0]);
198         CPPUNIT_ASSERT_EQUAL(std::string{""}, csvLine2[1]);
199 
200         csvLine3.parseLine("a,\"\",\",\"");
201         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
202         CPPUNIT_ASSERT_EQUAL(std::string{""}, csvLine3[1]);
203         CPPUNIT_ASSERT_EQUAL(std::string{","}, csvLine3[2]);
204 
205         csvLine3.parseLine("a,\"\"\"\",\",\"");
206         CPPUNIT_ASSERT_EQUAL(std::string{"a"}, csvLine3[0]);
207         CPPUNIT_ASSERT_EQUAL(std::string{"\""}, csvLine3[1]);
208         CPPUNIT_ASSERT_EQUAL(std::string{","}, csvLine3[2]);
209     }
210 
parseEmptyCsvLine()211     void parseEmptyCsvLine() {
212         yapet::CSVLine csvLine{3};
213         csvLine.parseLine(",,");
214 
215         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine[0]);
216         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine[1]);
217         CPPUNIT_ASSERT_EQUAL(std::string{}, csvLine[2]);
218     }
219 
throwEmptyLine()220     void throwEmptyLine() {
221         yapet::CSVLine csvLine{3};
222         CPPUNIT_ASSERT_THROW(csvLine.parseLine(""), std::invalid_argument);
223     }
224 
throwMalformedLine()225     void throwMalformedLine() {
226         yapet::CSVLine csvLine1{3};
227         CPPUNIT_ASSERT_THROW(csvLine1.parseLine("a,\"b,c"),
228                              std::invalid_argument);
229     }
230 
separator()231     void separator() {
232         yapet::CSVLine csvLine1{4, ';'};
233         csvLine1.parseLine("\"a;\";b\"\";\"c;\"\"\";\"d\"");
234         CPPUNIT_ASSERT_EQUAL(std::string{"a;"}, csvLine1[0]);
235         CPPUNIT_ASSERT_EQUAL(std::string{"b\"\""}, csvLine1[1]);
236         CPPUNIT_ASSERT_EQUAL(std::string{"c;\""}, csvLine1[2]);
237         CPPUNIT_ASSERT_EQUAL(std::string{"d"}, csvLine1[3]);
238 
239         yapet::CSVLine csvLine2{3, ';'};
240         csvLine2.addField(0, "Field 1");
241         csvLine2.addField(1, "Field;2");
242         csvLine2.addField(2, "Field\";3");
243 
244         std::string actual{csvLine2.getLine()};
245         std::string expected{"Field 1;\"Field;2\";\"Field\"\";3\""};
246         CPPUNIT_ASSERT_EQUAL(expected, actual);
247     }
248 };
249 
main()250 int main() {
251     CppUnit::TextUi::TestRunner runner;
252     runner.addTest(CSVLineTest::suite());
253     return runner.run() ? 0 : 1;
254 }