1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "google/protobuf/compiler/objectivec/line_consumer.h"
9
10 #include <string>
11 #include <tuple>
12 #include <utility>
13 #include <vector>
14
15 #include <gtest/gtest.h>
16 #include "absl/base/macros.h"
17 #include "absl/strings/str_cat.h"
18 #include "absl/strings/string_view.h"
19 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
20
21 namespace google {
22 namespace protobuf {
23 namespace compiler {
24 namespace objectivec {
25
26 namespace {
27
28 class TestLineCollector : public LineConsumer {
29 public:
TestLineCollector(std::vector<std::string> * inout_lines,const std::string * reject_line=nullptr,bool skip_msg=false)30 explicit TestLineCollector(std::vector<std::string>* inout_lines,
31 const std::string* reject_line = nullptr,
32 bool skip_msg = false)
33 : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {}
34
ConsumeLine(absl::string_view line,std::string * out_error)35 bool ConsumeLine(absl::string_view line, std::string* out_error) override {
36 if (reject_ && *reject_ == line) {
37 if (!skip_msg_) {
38 *out_error = absl::StrCat("Rejected '", *reject_, "'");
39 }
40 return false;
41 }
42 if (lines_) {
43 lines_->emplace_back(line);
44 }
45 return true;
46 }
47
48 private:
49 std::vector<std::string>* lines_;
50 const std::string* reject_;
51 bool skip_msg_;
52 };
53
54 const int kBlockSizes[] = {-1, 1, 2, 5, 64};
55 const int kBlockSizeCount = ABSL_ARRAYSIZE(kBlockSizes);
56
TEST(ObjCHelper,ParseSimple_BasicsSuccess)57 TEST(ObjCHelper, ParseSimple_BasicsSuccess) {
58 const std::vector<std::pair<std::string, std::vector<std::string>>> tests = {
59 {"", {}},
60 {"a", {"a"}},
61 {"a c", {"a c"}},
62 {" a c ", {"a c"}},
63 {"\ta c ", {"a c"}},
64 {"abc\n", {"abc"}},
65 {"abc\nd f", {"abc", "d f"}},
66 {"\n abc \n def \n\n", {"abc", "def"}},
67 };
68
69 for (const auto& test : tests) {
70 for (int i = 0; i < kBlockSizeCount; i++) {
71 io::ArrayInputStream input(test.first.data(), test.first.size(),
72 kBlockSizes[i]);
73 std::string err_str;
74 std::vector<std::string> lines;
75 TestLineCollector collector(&lines);
76 EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str));
77 EXPECT_EQ(lines, test.second);
78 EXPECT_TRUE(err_str.empty());
79 }
80 }
81 }
82
TEST(ObjCHelper,ParseSimple_DropsComments)83 TEST(ObjCHelper, ParseSimple_DropsComments) {
84 const std::vector<std::pair<std::string, std::vector<std::string>>> tests = {
85 {"# nothing", {}},
86 {"#", {}},
87 {"##", {}},
88 {"\n# nothing\n", {}},
89 {"a # same line", {"a"}},
90 {"a # same line\n", {"a"}},
91 {"a\n# line\nc", {"a", "c"}},
92 {"# n o t # h i n g #", {}},
93 {"## n o # t h i n g #", {}},
94 {"a# n o t # h i n g #", {"a"}},
95 {"a\n## n o # t h i n g #", {"a"}},
96 };
97
98 for (const auto& test : tests) {
99 for (int i = 0; i < kBlockSizeCount; i++) {
100 io::ArrayInputStream input(test.first.data(), test.first.size(),
101 kBlockSizes[i]);
102 std::string err_str;
103 std::vector<std::string> lines;
104 TestLineCollector collector(&lines);
105 EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str));
106 EXPECT_EQ(lines, test.second);
107 EXPECT_TRUE(err_str.empty());
108 }
109 }
110 }
111
TEST(ObjCHelper,ParseSimple_RejectLines)112 TEST(ObjCHelper, ParseSimple_RejectLines) {
113 const std::vector<std::tuple<std::string, std::string, int>> tests = {
114 std::make_tuple("a\nb\nc", "a", 1),
115 std::make_tuple("a\nb\nc", "b", 2),
116 std::make_tuple("a\nb\nc", "c", 3),
117 std::make_tuple("a\nb\nc\n", "c", 3),
118 };
119
120 for (const auto& test : tests) {
121 for (int i = 0; i < kBlockSizeCount; i++) {
122 io::ArrayInputStream input(std::get<0>(test).data(),
123 std::get<0>(test).size(), kBlockSizes[i]);
124 std::string err_str;
125 TestLineCollector collector(nullptr, &std::get<1>(test));
126 EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str));
127 std::string expected_err =
128 absl::StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '",
129 std::get<1>(test), "'");
130 EXPECT_EQ(err_str, expected_err);
131 }
132 }
133 }
134
TEST(ObjCHelper,ParseSimple_RejectLinesNoMessage)135 TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) {
136 const std::vector<std::tuple<std::string, std::string, int>> tests = {
137 std::make_tuple("a\nb\nc", "a", 1),
138 std::make_tuple("a\nb\nc", "b", 2),
139 std::make_tuple("a\nb\nc", "c", 3),
140 std::make_tuple("a\nb\nc\n", "c", 3),
141 };
142
143 for (const auto& test : tests) {
144 for (int i = 0; i < kBlockSizeCount; i++) {
145 io::ArrayInputStream input(std::get<0>(test).data(),
146 std::get<0>(test).size(), kBlockSizes[i]);
147 std::string err_str;
148 TestLineCollector collector(nullptr, &std::get<1>(test),
149 true /* skip msg */);
150 EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str));
151 std::string expected_err =
152 absl::StrCat("error: dummy Line ", std::get<2>(test),
153 ", ConsumeLine failed without setting an error.");
154 EXPECT_EQ(err_str, expected_err);
155 }
156 }
157 }
158
159 } // namespace
160
161 } // namespace objectivec
162 } // namespace compiler
163 } // namespace protobuf
164 } // namespace google
165