btool
A parser/converter/transpiler for .bib files
ParserStateFixtureTest.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
2 #include <ParserState.hpp>
3 #include <BibElement.hpp>
4 #include <ParserException.hpp>
5 #include <GlobalParserState.hpp>
6 #include <StyleParserState.hpp>
7 #include <KeyParserState.hpp>
8 #include <ValueParserState.hpp>
10 
11 using namespace std::literals::string_literals;
12 
13 template<class D, class S>
14 bool isType(const S *src) {
15  return dynamic_cast<const D *>(src) != nullptr;
16 }
17 
23 class ParserStateFixtureTest : public ::testing::Test {
24  protected:
25  ParserContext context = ParserContext(""s);
26  std::vector<BibElement> result;
27 
28  void SetUp() override {
29  context = ParserContext("fixtureFile.bib"s);
30  result = {};
31  }
32 };
33 
34 TEST_F(ParserStateFixtureTest, globalStateIgnoresEverythingButAt) {
35  const auto file = R"(some
36 non
37 
38 at_ characters)"s;
39 
40  ParserState *state = new GlobalParserState{context, result};
41 
42  ASSERT_NO_THROW([&]() {
43  for (const auto c : file) {
44  state = state->handleCharacter(c);
45  }
46  }());
47  ASSERT_TRUE(isType<GlobalParserState>(state));
48 
49  delete state;
50 }
51 
52 TEST_F(ParserStateFixtureTest, globalStateSwitchesToStyleAtAt) {
53  const auto file = R"(some@)"s;
54  ParserState *state = new GlobalParserState{context, result};
55 
56  ASSERT_NO_THROW([&]() {
57  for (const auto c : file) {
58  state = state->handleCharacter(c);
59  }
60  }());
61  ASSERT_FALSE(isType<GlobalParserState>(state));
62  ASSERT_TRUE(isType<StyleParserState>(state));
63 
64  delete state;
65 }
66 
67 TEST_F(ParserStateFixtureTest, styleParserStateFailsWithWhitespace) {
68  const auto file = R"(here are spaces)"s;
69  ParserState *state = new StyleParserState{context, result};
70 
71  ASSERT_ANY_THROW([&]() {
72  for (const auto c : file) {
73  state = state->handleCharacter(c);
74  }
75  }());
76 
77  delete state;
78 }
79 
80 TEST_F(ParserStateFixtureTest, styleParserStateDontFailOnCorrectStyle) {
81  const auto file = R"(thisIsAValidStyle)"s;
82  ParserState *state = new StyleParserState{context, result};
83 
84  ASSERT_NO_THROW([&]() {
85  for (const auto c : file) {
86  state = state->handleCharacter(c);
87  }
88  }());
89 
90  ASSERT_TRUE(isType<StyleParserState>(state));
91  delete state;
92 }
93 
94 TEST_F(ParserStateFixtureTest, styleParserStateSwitchesToIdentifierStateOnBrace) {
95  const auto file = R"(thisIsAValidStyle{)"s;
96  ParserState *state = new StyleParserState{context, result};
97 
98  ASSERT_NO_THROW([&]() {
99  for (const auto c : file) {
100  state = state->handleCharacter(c);
101  }
102  }());
103 
104  ASSERT_EQ(result.front().style, "thisIsAValidStyle"s);
105  ASSERT_FALSE(isType<StyleParserState>(state));
106  ASSERT_TRUE(isType<IdentifierParserState>(state));
107  delete state;
108 }
109 
110 TEST_F(ParserStateFixtureTest, globalStateCanGoToIdentifierState) {
111  const auto file = R"(someUselessStuff @thisIsAValidStyle{)"s;
112  ParserState *state = new GlobalParserState{context, result};
113 
114  ASSERT_NO_THROW([&]() {
115  for (const auto c : file) {
116  state = state->handleCharacter(c);
117  }
118  }());
119 
120  ASSERT_EQ(result.front().style, "thisIsAValidStyle"s);
121  ASSERT_TRUE(isType<IdentifierParserState>(state));
122  delete state;
123 }
124 
125 TEST_F(ParserStateFixtureTest, identifierCantContainWhitespace) {
126  const auto file = R"(identifier with whitespace)"s;
127  ParserState *state = new IdentifierParserState{context, result};
128 
129  ASSERT_ANY_THROW([&]() {
130  for (const auto c : file) {
131  state = state->handleCharacter(c);
132  }
133  }());
134 
135  delete state;
136 }
137 
138 TEST_F(ParserStateFixtureTest, identifierEndsAtCommaAndIsSaved) {
139  const auto file = R"(identifier,)"s;
140  result.push_back({"", "", {}});
141  ParserState *state = new IdentifierParserState{context, result};
142 
143  ASSERT_NO_THROW([&]() {
144  for (const auto c : file) {
145  state = state->handleCharacter(c);
146  }
147  }());
148 
149  ASSERT_EQ(result.front().id, "identifier"s);
150  ASSERT_TRUE(isType<KeyParserState>(state));
151  delete state;
152 }
153 
154 TEST_F(ParserStateFixtureTest, keyStateIgnoresTrailingWhitespace) {
155  const auto file = R"( this is a key )"s;
156  ParserState *state = new KeyParserState{context, result};
157 
158  ASSERT_NO_THROW([&]() {
159  for (const auto c : file) {
160  state = state->handleCharacter(c);
161  }
162  }());
163 
164  ASSERT_TRUE(isType<KeyParserState>(state));
165  delete state;
166 }
167 
168 TEST_F(ParserStateFixtureTest, keyStateExitsOnEqualSignAndTrimsKey) {
169  const auto file = R"( this is a key =)"s;
170  result.push_back({"", "", {}});
171  ParserState *state = new KeyParserState{context, result};
172 
173  ASSERT_NO_THROW([&]() {
174  for (const auto c : file) {
175  state = state->handleCharacter(c);
176  }
177  }());
178 
179  ASSERT_EQ(result.front().attributes.front().name, "this is a key"s);
180  ASSERT_TRUE(isType<ValueParserState>(state));
181  delete state;
182 }
183 
184 TEST_F(ParserStateFixtureTest, valueStateTrimsWhitespaceAndExitsToKeyState) {
185  const auto file = R"( this is a key ,)"s;
186  result.push_back({"", "", {{"", ""}}});
187  ParserState *state = new ValueParserState{context, result};
188 
189  ASSERT_NO_THROW([&]() {
190  for (const auto c : file) {
191  state = state->handleCharacter(c);
192  }
193  }());
194 
195  ASSERT_EQ(result.front().attributes.front().value, "this is a key"s);
196  ASSERT_TRUE(isType<KeyParserState>(state));
197  delete state;
198 }
199 
200 TEST_F(ParserStateFixtureTest, valueStateExitsOnCommaAndMatchingBraces) {
201  const auto file = R"( {{ this, is a key }} ,)"s;
202  result.push_back({"", "", {{"", ""}}});
203  ParserState *state = new ValueParserState{context, result};
204 
205  ASSERT_NO_THROW([&]() {
206  for (const auto c : file) {
207  state = state->handleCharacter(c);
208  }
209  }());
210 
211  ASSERT_EQ(result.front().attributes.front().value, "this, is a key"s);
212  ASSERT_TRUE(isType<KeyParserState>(state));
213  delete state;
214 }
215 
216 TEST_F(ParserStateFixtureTest, keyStateExitsToGlobalStateOnClosingBrace) {
217  const auto file = R"(} )"s;
218  ParserState *state = new KeyParserState{context, result};
219 
220  ASSERT_NO_THROW([&]() {
221  for (const auto c : file) {
222  state = state->handleCharacter(c);
223  }
224  }());
225 
226  ASSERT_TRUE(isType<GlobalParserState>(state));
227  delete state;
228 }
229 
230 TEST_F(ParserStateFixtureTest, valueStateExitsToGlobalStateOnClosingBrace) {
231  const auto file = R"(} )"s;
232  result.push_back({"", "", {{"", ""}}});
233  ParserState *state = new ValueParserState{context, result};
234 
235  ASSERT_NO_THROW([&]() {
236  for (const auto c : file) {
237  state = state->handleCharacter(c);
238  }
239  }());
240 
241  ASSERT_TRUE(isType<GlobalParserState>(state));
242  delete state;
243 }
244 
245 TEST_F(ParserStateFixtureTest, canParseFullElement) {
246  const auto file = R"(@inproceedings{Feigenspan11,
247  author = {Janet Feigenspan},
248  title = {{Program Comprehension of Feature-Oriented Software Development}},
249  booktitle = {International Doctoral Symposium on Empirical Software Engineering (IDoESE)},
250  year = {2011},
251  month = Sep,
252  url = {http://wwwiti.cs.uni-magdeburg.de/iti_db/publikationen/ps/auto/Feigenspan11.pdf}
253 })"s;
254  ParserState *state = new GlobalParserState{context, result};
255 
256  BibElement expected{"Feigenspan11", "inproceedings", {
257  {"author", "Janet Feigenspan"},
258  {"title", "Program Comprehension of Feature-Oriented Software Development"},
259  {"booktitle", "International Doctoral Symposium on Empirical Software Engineering (IDoESE)"},
260  {"year", "2011"},
261  {"month", "Sep"},
262  {"url", "http://wwwiti.cs.uni-magdeburg.de/iti_db/publikationen/ps/auto/Feigenspan11.pdf"}
263  }};
264 
265  ASSERT_NO_THROW([&]() {
266  for (const auto c : file) {
267  state = state->handleCharacter(c);
268  }
269  }());
270 
271  ASSERT_EQ(result.front(), expected);
272  ASSERT_TRUE(isType<GlobalParserState>(state));
273  delete state;
274 }
275 
276 TEST_F(ParserStateFixtureTest, canParseMultipleElements) {
277  const auto file = R"(
278 @inproceedings{Feigenspan11,
279  author = {Janet Feigenspan},
280  title = {{Program Comprehension of Feature-Oriented Software Development}},
281  booktitle = {International Doctoral Symposium on Empirical Software Engineering (IDoESE)},
282  year = {2011},
283  month = Sep,
284  url = {http://wwwiti.cs.uni-magdeburg.de/iti_db/publikationen/ps/auto/Feigenspan11.pdf}
285 }
286 @article{FeigenspanSiFr11,
287  author = {Janet Feigenspan and Norbert Siegmund and Jana Fruth},
288  title = {{On the Role of Program Comprehension in Embedded Systems}},
289  journal = {Softwaretechnik-Trends},
290  year = {2011},
291  volume = {31},
292  number = {2},
293  month = May,
294  url = {http://www.uni-koblenz-landau.de/koblenz/fb4/institute/uebergreifend/sre/conferences/wsr/wsr2011/wsr2011_proceedings.pdf}
295 })"s;
296  ParserState *state = new GlobalParserState{context, result};
297 
298  std::vector<BibElement> expected{
299  {"Feigenspan11", "inproceedings", {
300  {"author", "Janet Feigenspan"},
301  {"title", "Program Comprehension of Feature-Oriented Software Development"},
302  {"booktitle", "International Doctoral Symposium on Empirical Software Engineering (IDoESE)"},
303  {"year", "2011"},
304  {"month", "Sep"},
305  {"url", "http://wwwiti.cs.uni-magdeburg.de/iti_db/publikationen/ps/auto/Feigenspan11.pdf"}
306  }}, {"FeigenspanSiFr11", "article", {
307  {"author", "Janet Feigenspan and Norbert Siegmund and Jana Fruth"},
308  {"title", "On the Role of Program Comprehension in Embedded Systems"},
309  {"journal", "Softwaretechnik-Trends"},
310  {"year", "2011"},
311  {"volume", "31"},
312  {"number", "2"},
313  {"month", "May"},
314  {"url",
315  "http://www.uni-koblenz-landau.de/koblenz/fb4/institute/uebergreifend/sre/conferences/wsr/wsr2011/wsr2011_proceedings.pdf"}
316  }}};
317 
318  ASSERT_NO_THROW([&]() {
319  for (const auto c : file) {
320  state = state->handleCharacter(c);
321  }
322  }());
323 
324  ASSERT_EQ(result, expected);
325  delete state;
326 }
ParserState.hpp
GlobalParserState.hpp
ParserState
Definition: ParserState.hpp:7
KeyParserState.hpp
ValueParserState.hpp
ParserStateFixtureTest
Definition: ParserStateFixtureTest.cpp:23
ParserContext
Definition: ParserContext.hpp:10
ParserException.hpp
KeyParserState
Key Parser State.
Definition: KeyParserState.hpp:14
ParserStateFixtureTest::SetUp
void SetUp() override
Definition: ParserStateFixtureTest.cpp:28
GlobalParserState
Global Parser State.
Definition: GlobalParserState.hpp:14
ParserState::handleCharacter
virtual auto handleCharacter(char c) -> ParserState *=0
IdentifierParserState
Identifier Parser State.
Definition: IdentifierParserState.hpp:14
ParserStateFixtureTest::result
std::vector< BibElement > result
Definition: ParserStateFixtureTest.cpp:26
StyleParserState.hpp
ValueParserState
Key Parser State.
Definition: ValueParserState.hpp:16
isType
bool isType(const S *src)
Definition: ParserStateFixtureTest.cpp:14
TEST_F
TEST_F(ParserStateFixtureTest, globalStateIgnoresEverythingButAt)
Definition: ParserStateFixtureTest.cpp:34
StyleParserState
Style Parser State.
Definition: StyleParserState.hpp:14
BibElement.hpp
IdentifierParserState.hpp
BibElement
bib-element-Container
Definition: BibElement.hpp:14