| Alexei Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 1 | // 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 |  | 
 | 20 | namespace pw::protobuf { | 
 | 21 | namespace { | 
 | 22 |  | 
 | 23 | class TestDecodeHandler : public DecodeHandler { | 
 | 24 |  public: | 
 | 25 |   Status ProcessField(Decoder* decoder, uint32_t field_number) override { | 
| Alexei Frolov | 6d9b9b4 | 2020-01-14 12:57:33 -0800 | [diff] [blame^] | 26 |     std::string_view str; | 
 | 27 |  | 
| Alexei Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 28 |     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 Frolov | 6d9b9b4 | 2020-01-14 12:57:33 -0800 | [diff] [blame^] | 35 |       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 Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 49 |     } | 
 | 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 Frolov | 6d9b9b4 | 2020-01-14 12:57:33 -0800 | [diff] [blame^] | 58 |   bool test_bool = true; | 
 | 59 |   double test_double = 0; | 
 | 60 |   uint32_t test_fixed32 = 0; | 
 | 61 |   char test_string[16]; | 
| Alexei Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 62 | }; | 
 | 63 |  | 
 | 64 | TEST(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 Frolov | 6d9b9b4 | 2020-01-14 12:57:33 -0800 | [diff] [blame^] | 80 |     // type=string, k=6, v="Hello world" | 
 | 81 |     0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', | 
| Alexei Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 82 |   }; | 
 | 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 Frolov | 6d9b9b4 | 2020-01-14 12:57:33 -0800 | [diff] [blame^] | 90 |   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 Frolov | dea46f7 | 2020-01-07 13:28:24 -0800 | [diff] [blame] | 94 | } | 
 | 95 |  | 
 | 96 | TEST(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 |  | 
 | 117 | TEST(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 |  | 
 | 128 | TEST(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. | 
 | 140 | class 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 |  | 
 | 164 | TEST(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. | 
 | 196 | class 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 |  | 
 | 218 | TEST(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 |