78 #define TEST_1D(FIXTURE, NAME, CASES) \
79 class FIXTURE##_##NAME##_DD : public FIXTURE { \
81 template <typename CaseType> \
82 void DoSingleCase(const CaseType& CASES##_case); \
85 TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
86 for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES); i++) { \
87 SCOPED_TRACE(testing::Message() \
88 << #CASES " case #" << i << ": " << CASES[i]); \
89 DoSingleCase(CASES[i]); \
93 template <typename CaseType> \
94 void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType& CASES##_case)
96 #define TEST_2D(FIXTURE, NAME, CASES1, CASES2) \
97 class FIXTURE##_##NAME##_DD : public FIXTURE { \
99 template <typename CaseType1, typename CaseType2> \
100 void DoSingleCase(const CaseType1& CASES1##_case, \
101 const CaseType2& CASES2##_case); \
104 TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
105 for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES1); i++) { \
106 for (int j = 0; j < GOOGLE_ARRAYSIZE(CASES2); j++) { \
107 SCOPED_TRACE(testing::Message() \
108 << #CASES1 " case #" << i << ": " << CASES1[i] << ", " \
109 << #CASES2 " case #" << j << ": " << CASES2[j]); \
110 DoSingleCase(CASES1[i], CASES2[j]); \
115 template <typename CaseType1, typename CaseType2> \
116 void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType1& CASES1##_case, \
117 const CaseType2& CASES2##_case)
123 class TestInputStream :
public ZeroCopyInputStream {
125 TestInputStream(
const void*
data,
int size,
int block_size)
127 ~TestInputStream() {}
130 bool Next(
const void**
data,
int*
size) {
157 class TestErrorCollector :
public ErrorCollector {
159 TestErrorCollector() {}
160 ~TestErrorCollector() {}
176 const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
192 #if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
196 struct SimpleTokenCase {
201 inline std::ostream&
operator<<(std::ostream& out,
202 const SimpleTokenCase& test_case) {
203 return out <<
CEscape(test_case.input);
206 SimpleTokenCase kSimpleTokenCases[] = {
250 TestInputStream
input(kSimpleTokenCases_case.input.data(),
251 kSimpleTokenCases_case.input.size(), kBlockSizes_case);
252 TestErrorCollector error_collector;
253 Tokenizer tokenizer(&
input, &error_collector);
259 EXPECT_EQ(0, tokenizer.current().column);
260 EXPECT_EQ(0, tokenizer.current().end_column);
266 EXPECT_EQ(kSimpleTokenCases_case.type, tokenizer.current().type);
268 EXPECT_EQ(kSimpleTokenCases_case.input, tokenizer.current().text);
271 EXPECT_EQ(0, tokenizer.current().column);
272 EXPECT_EQ(kSimpleTokenCases_case.input.size(),
273 tokenizer.current().end_column);
282 EXPECT_EQ(kSimpleTokenCases_case.input.size(), tokenizer.current().column);
283 EXPECT_EQ(kSimpleTokenCases_case.input.size(),
284 tokenizer.current().end_column);
294 const char* text =
"1f 2.5f 6e3f 7F";
295 TestInputStream
input(text, strlen(text), kBlockSizes_case);
296 TestErrorCollector error_collector;
297 Tokenizer tokenizer(&
input, &error_collector);
298 tokenizer.set_allow_f_after_float(
true);
302 EXPECT_EQ(tokenizer.current().text,
"1f");
305 EXPECT_EQ(tokenizer.current().text,
"2.5f");
308 EXPECT_EQ(tokenizer.current().text,
"6e3f");
311 EXPECT_EQ(tokenizer.current().text,
"7F");
326 struct MultiTokenCase {
334 inline std::ostream&
operator<<(std::ostream& out,
335 const MultiTokenCase& test_case) {
336 return out <<
CEscape(test_case.input);
339 MultiTokenCase kMultiTokenCases[] = {
347 {
"foo 1 1.2 + 'bar'",
395 {
"foo // This is a comment\n"
396 "bar // This is another comment",
404 {
"foo /* This is a block comment */ bar",
433 TestInputStream
input(kMultiTokenCases_case.input.data(),
434 kMultiTokenCases_case.input.size(), kBlockSizes_case);
435 TestErrorCollector error_collector;
436 Tokenizer tokenizer(&
input, &error_collector);
442 EXPECT_EQ(0, tokenizer.current().column);
443 EXPECT_EQ(0, tokenizer.current().end_column);
447 Tokenizer::Token token;
449 token = kMultiTokenCases_case.output[
i++];
453 Tokenizer::Token
previous = tokenizer.current();
470 EXPECT_EQ(token.type, tokenizer.current().type);
471 EXPECT_EQ(token.text, tokenizer.current().text);
472 EXPECT_EQ(token.line, tokenizer.current().line);
473 EXPECT_EQ(token.column, tokenizer.current().column);
474 EXPECT_EQ(token.end_column, tokenizer.current().end_column);
484 #if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
492 "corge /* grault */\n"
494 const char*
const kTokens[] = {
"foo",
495 "baz",
"/",
"/",
"qux",
"corge",
"/",
496 "*",
"grault",
"*",
"/",
"garply"};
499 TestInputStream
input(text, strlen(text), kBlockSizes_case);
500 TestErrorCollector error_collector;
501 Tokenizer tokenizer(&
input, &error_collector);
507 EXPECT_EQ(tokenizer.current().text, kTokens[
i]);
522 struct DocCommentCase {
530 inline std::ostream&
operator<<(std::ostream& out,
531 const DocCommentCase& test_case) {
532 return out <<
CEscape(test_case.input);
535 DocCommentCase kDocCommentCases[] = {
542 {
"prev /* ignored */ next",
548 {
"prev // trailing comment\n"
551 " trailing comment\n",
556 "// leading comment\n"
566 "// trailing comment\n"
571 " trailing comment\n"
576 {
"prev // trailing comment\n"
577 "// leading comment\n"
581 " trailing comment\n",
586 {
"prev /* trailing block comment */\n"
587 "/* leading block comment\n"
592 " trailing block comment ",
594 " leading block comment\n"
599 "/* trailing block comment\n"
603 "/* leading block comment\n"
608 " trailing block comment\n"
612 " leading block comment\n"
617 "// trailing comment\n"
619 "// detached comment\n"
622 "// second detached comment\n"
623 "/* third detached comment\n"
625 "// leading comment\n"
628 " trailing comment\n",
629 {
" detached comment\n"
631 " second detached comment\n",
632 " third detached comment\n"
634 " leading comment\n"},
638 "// detached comment\n"
640 "// leading comment\n"
644 {
" detached comment\n"},
645 " leading comment\n"},
648 "// leading comment\n"
653 " leading comment\n"},
658 TestInputStream
input(kDocCommentCases_case.input.data(),
659 kDocCommentCases_case.input.size(), kBlockSizes_case);
660 TestErrorCollector error_collector;
661 Tokenizer tokenizer(&
input, &error_collector);
664 TestInputStream input2(kDocCommentCases_case.input.data(),
665 kDocCommentCases_case.input.size(), kBlockSizes_case);
666 Tokenizer tokenizer2(&input2, &error_collector);
671 EXPECT_EQ(
"prev", tokenizer.current().text);
672 EXPECT_EQ(
"prev", tokenizer2.current().text);
680 EXPECT_EQ(
"next", tokenizer.current().text);
681 EXPECT_EQ(
"next", tokenizer2.current().text);
683 EXPECT_EQ(kDocCommentCases_case.prev_trailing_comments,
765 #ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
769 "passed text that could not have been tokenized as a float");
772 "passed text that could not have been tokenized as a float");
775 "passed text that could not have been tokenized as a float");
776 #endif // PROTOBUF_HAS_DEATH_TEST
779 TEST_F(TokenizerTest, ParseString) {
815 #ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet
818 "passed text that could not have been tokenized as a string");
819 #endif // PROTOBUF_HAS_DEATH_TEST
822 TEST_F(TokenizerTest, ParseStringAppend) {
844 inline std::ostream&
operator<<(std::ostream& out,
const ErrorCase& test_case) {
845 return out <<
CEscape(test_case.input);
848 ErrorCase kErrorCases[] = {
850 {
"'\\l' foo",
true,
"0:2: Invalid escape sequence in string literal.\n"},
851 {
"'\\X' foo",
true,
"0:2: Invalid escape sequence in string literal.\n"},
852 {
"'\\x' foo",
true,
"0:3: Expected hex digits for escape sequence.\n"},
853 {
"'foo",
false,
"0:4: Unexpected end of string.\n"},
854 {
"'bar\nfoo",
true,
"0:4: String literals cannot cross line boundaries.\n"},
855 {
"'\\u01' foo",
true,
856 "0:5: Expected four hex digits for \\u escape sequence.\n"},
857 {
"'\\u01' foo",
true,
858 "0:5: Expected four hex digits for \\u escape sequence.\n"},
859 {
"'\\uXYZ' foo",
true,
860 "0:3: Expected four hex digits for \\u escape sequence.\n"},
863 {
"123foo",
true,
"0:3: Need space between number and identifier.\n"},
866 {
"0x foo",
true,
"0:2: \"0x\" must be followed by hex digits.\n"},
867 {
"0541823 foo",
true,
868 "0:4: Numbers starting with leading zero must be in octal.\n"},
869 {
"0x123z foo",
true,
"0:5: Need space between number and identifier.\n"},
870 {
"0x123.4 foo",
true,
"0:5: Hex and octal numbers must be integers.\n"},
871 {
"0123.4 foo",
true,
"0:4: Hex and octal numbers must be integers.\n"},
874 {
"1e foo",
true,
"0:2: \"e\" must be followed by exponent.\n"},
875 {
"1e- foo",
true,
"0:3: \"e\" must be followed by exponent.\n"},
877 "0:3: Already saw decimal point or exponent; can't have another one.\n"},
879 "0:3: Already saw decimal point or exponent; can't have another one.\n"},
881 "0:1: Need space between identifier and decimal point.\n"},
883 {
"1.0f foo",
true,
"0:3: Need space between number and identifier.\n"},
887 "0:2: End-of-file inside block comment.\n"
888 "0:0: Comment started here.\n"},
890 "0:3: \"/*\" inside block comment. Block comments cannot be nested.\n"},
894 {
"\b foo",
true,
"0:0: Invalid control characters encountered in text.\n"},
896 "0:0: Invalid control characters encountered in text.\n"},
900 {
"\b",
false,
"0:0: Invalid control characters encountered in text.\n"},
907 "0:0: Invalid control characters encountered in text.\n"},
909 "0:0: Invalid control characters encountered in text.\n"},
912 {
"\300foo",
true,
"0:0: Interpreting non ascii codepoint 192.\n"},
917 TestInputStream
input(kErrorCases_case.input.data(),
918 kErrorCases_case.input.size(), kBlockSizes_case);
919 TestErrorCollector error_collector;
920 Tokenizer tokenizer(&
input, &error_collector);
923 bool last_was_foo =
false;
924 while (tokenizer.Next()) {
925 last_was_foo = tokenizer.current().text ==
"foo";
929 EXPECT_EQ(kErrorCases_case.errors, error_collector.text_);
932 if (kErrorCases_case.recoverable) {
941 TestInputStream
input(text.data(), text.size(), kBlockSizes_case);
945 TestErrorCollector error_collector;
946 Tokenizer tokenizer(&
input, &error_collector);