blob: c655b09d4292182e3f8fec75e2b81585d9213d42 [file] [log] [blame]
Alexei Frolovdea46f72020-01-07 13:28:24 -08001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#include "pw_protobuf/decoder.h"
16
17#include "gtest/gtest.h"
18#include "pw_preprocessor/util.h"
19
20namespace pw::protobuf {
21namespace {
22
23class TestDecodeHandler : public DecodeHandler {
24 public:
25 Status ProcessField(Decoder* decoder, uint32_t field_number) override {
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080026 std::string_view str;
27
Alexei Frolovdea46f72020-01-07 13:28:24 -080028 switch (field_number) {
29 case 1:
30 decoder->ReadInt32(field_number, &test_int32);
31 break;
32 case 2:
33 decoder->ReadSint32(field_number, &test_sint32);
34 break;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080035 case 3:
36 decoder->ReadBool(field_number, &test_bool);
37 break;
38 case 4:
39 decoder->ReadDouble(field_number, &test_double);
40 break;
41 case 5:
42 decoder->ReadFixed32(field_number, &test_fixed32);
43 break;
44 case 6:
45 decoder->ReadString(field_number, &str);
46 std::memcpy(test_string, str.data(), str.size());
47 test_string[str.size()] = '\0';
48 break;
Alexei Frolovdea46f72020-01-07 13:28:24 -080049 }
50
51 called = true;
52 return Status::OK;
53 }
54
55 bool called = false;
56 int32_t test_int32 = 0;
57 int32_t test_sint32 = 0;
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080058 bool test_bool = true;
59 double test_double = 0;
60 uint32_t test_fixed32 = 0;
61 char test_string[16];
Alexei Frolovdea46f72020-01-07 13:28:24 -080062};
63
64TEST(Decoder, Decode) {
65 Decoder decoder;
66 TestDecodeHandler handler;
67
68 // clang-format off
69 uint8_t encoded_proto[] = {
70 // type=int32, k=1, v=42
71 0x08, 0x2a,
72 // type=sint32, k=2, v=-13
73 0x10, 0x19,
74 // type=bool, k=3, v=false
75 0x18, 0x00,
76 // type=double, k=4, v=3.14159
77 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
78 // type=fixed32, k=5, v=0xdeadbeef
79 0x2d, 0xef, 0xbe, 0xad, 0xde,
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080080 // type=string, k=6, v="Hello world"
81 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
Alexei Frolovdea46f72020-01-07 13:28:24 -080082 };
83 // clang-format on
84
85 decoder.set_handler(&handler);
86 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::OK);
87 EXPECT_TRUE(handler.called);
88 EXPECT_EQ(handler.test_int32, 42);
89 EXPECT_EQ(handler.test_sint32, -13);
Alexei Frolov6d9b9b42020-01-14 12:57:33 -080090 EXPECT_FALSE(handler.test_bool);
91 EXPECT_EQ(handler.test_double, 3.14159);
92 EXPECT_EQ(handler.test_fixed32, 0xdeadbeef);
93 EXPECT_STREQ(handler.test_string, "Hello world");
Alexei Frolovdea46f72020-01-07 13:28:24 -080094}
95
96TEST(Decoder, Decode_OverridesDuplicateFields) {
97 Decoder decoder;
98 TestDecodeHandler handler;
99
100 // clang-format off
101 uint8_t encoded_proto[] = {
102 // type=int32, k=1, v=42
103 0x08, 0x2a,
104 // type=int32, k=1, v=43
105 0x08, 0x2b,
106 // type=int32, k=1, v=44
107 0x08, 0x2c,
108 };
109 // clang-format on
110
111 decoder.set_handler(&handler);
112 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::OK);
113 EXPECT_TRUE(handler.called);
114 EXPECT_EQ(handler.test_int32, 44);
115}
116
117TEST(Decoder, Decode_Empty) {
118 Decoder decoder;
119 TestDecodeHandler handler;
120
121 decoder.set_handler(&handler);
122 EXPECT_EQ(decoder.Decode(span<std::byte>()), Status::OK);
123 EXPECT_FALSE(handler.called);
124 EXPECT_EQ(handler.test_int32, 0);
125 EXPECT_EQ(handler.test_sint32, 0);
126}
127
128TEST(Decoder, Decode_BadData) {
129 Decoder decoder;
130 TestDecodeHandler handler;
131
132 // Field key without a value.
133 uint8_t encoded_proto[] = {0x08};
134
135 decoder.set_handler(&handler);
136 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::DATA_LOSS);
137}
138
139// Only processes fields numbered 1 or 3.
140class OneThreeDecodeHandler : public DecodeHandler {
141 public:
142 Status ProcessField(Decoder* decoder, uint32_t field_number) override {
143 switch (field_number) {
144 case 1:
145 EXPECT_EQ(decoder->ReadInt32(field_number, &field_one), Status::OK);
146 break;
147 case 3:
148 EXPECT_EQ(decoder->ReadInt32(field_number, &field_three), Status::OK);
149 break;
150 default:
151 // Do nothing.
152 break;
153 }
154
155 called = true;
156 return Status::OK;
157 }
158
159 bool called = false;
160 int32_t field_one = 0;
161 int32_t field_three = 0;
162};
163
164TEST(Decoder, Decode_SkipsUnprocessedFields) {
165 Decoder decoder;
166 OneThreeDecodeHandler handler;
167
168 // clang-format off
169 uint8_t encoded_proto[] = {
170 // type=int32, k=1, v=42
171 // Should be read.
172 0x08, 0x2a,
173 // type=sint32, k=2, v=-13
174 // Should be ignored.
175 0x10, 0x19,
176 // type=int32, k=2, v=3
177 // Should be ignored.
178 0x10, 0x03,
179 // type=int32, k=3, v=99
180 // Should be read.
181 0x18, 0x63,
182 // type=int32, k=4, v=16
183 // Should be ignored.
184 0x20, 0x10,
185 };
186 // clang-format on
187
188 decoder.set_handler(&handler);
189 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::OK);
190 EXPECT_TRUE(handler.called);
191 EXPECT_EQ(handler.field_one, 42);
192 EXPECT_EQ(handler.field_three, 99);
193}
194
195// Only processes fields numbered 1 or 3.
196class ExitOnOneDecoder : public DecodeHandler {
197 public:
198 Status ProcessField(Decoder* decoder, uint32_t field_number) override {
199 switch (field_number) {
200 case 1:
201 EXPECT_EQ(decoder->ReadInt32(field_number, &field_one), Status::OK);
202 return Status::CANCELLED;
203 case 3:
204 EXPECT_EQ(decoder->ReadInt32(field_number, &field_three), Status::OK);
205 break;
206 default:
207 // Do nothing.
208 break;
209 }
210
211 return Status::OK;
212 }
213
214 int32_t field_one = 0;
215 int32_t field_three = 1111;
216};
217
218TEST(Decoder, Decode_StopsOnNonOkStatus) {
219 Decoder decoder;
220 ExitOnOneDecoder handler;
221
222 // clang-format off
223 uint8_t encoded_proto[] = {
224 // type=int32, k=1, v=42
225 // Should be read.
226 0x08, 0x2a,
227 // type=int32, k=3, v=99
228 // Should be skipped.
229 0x18, 0x63,
230 // type=int32, k=2, v=16
231 // Should be skipped.
232 0x08, 0x10,
233 };
234 // clang-format on
235
236 decoder.set_handler(&handler);
237 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::CANCELLED);
238 EXPECT_EQ(handler.field_one, 42);
239 EXPECT_EQ(handler.field_three, 1111);
240}
241
242} // namespace
243} // namespace pw::protobuf