blob: 6d2f8cf7bb1364cd6558c6cd4e45528338ec44e8 [file] [log] [blame]
Yecheng Zhao931f4d52021-09-02 23:15:13 -07001// Copyright 2021 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/helpers.h"
16
17#include "gtest/gtest.h"
18#include "pw_protobuf/encoder.h"
19
20namespace pw::protobuf {
21
22TEST(ProtoHelper, WriteProtoStringToBytesMapEntry) {
23 // The following defines an instance of the message below:
24 //
25 // message Maps {
26 // map<string, string> map_a = 1;
27 // map<string, string> map_b = 2;
28 // }
29 //
30 // where
31 //
32 // Maps.map_a['key_foo'] = 'foo_a'
33 // Maps.map_a['key_bar'] = 'bar_a'
34 //
35 // Maps.map_b['key_foo'] = 'foo_b'
36 // Maps.map_b['key_bar'] = 'bar_b'
37 //
38 // clang-format off
39 std::uint8_t encoded_proto[] = {
40 // map_a["key_bar"] = "bar_a", key = 1
41 0x0a, 0x10,
42 0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r', // map key
43 0x12, 0x05, 'b', 'a', 'r', '_', 'a', // map value
44
45 // map_a["key_foo"] = "foo_a", key = 1
46 0x0a, 0x10,
47 0x0a, 0x07, 'k', 'e', 'y', '_', 'f', 'o', 'o',
48 0x12, 0x05, 'f', 'o', 'o', '_', 'a',
49
50 // map_b["key_foo"] = "foo_b", key = 2
51 0x12, 0x10,
52 0x0a, 0x07, 'k', 'e', 'y', '_', 'f', 'o', 'o',
53 0x12, 0x05, 'f', 'o', 'o', '_', 'b',
54
55 // map_b["key_bar"] = "bar_b", key = 2
56 0x12, 0x10,
57 0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r',
58 0x12, 0x05, 'b', 'a', 'r', '_', 'b',
59 };
60 // clang-format on
61
62 // Now construct the same message with WriteStringToBytesMapEntry
63 std::byte dst_buffer[sizeof(encoded_proto)];
64 stream::MemoryWriter writer(dst_buffer);
65
66 const struct {
67 uint32_t field_number;
68 std::string_view key;
69 std::string_view value;
70 } kMapData[] = {
71 {1, "key_bar", "bar_a"},
72 {1, "key_foo", "foo_a"},
73 {2, "key_foo", "foo_b"},
74 {2, "key_bar", "bar_b"},
75 };
76
77 std::byte stream_pipe_buffer[1];
78 for (auto ele : kMapData) {
79 stream::MemoryReader key_reader(std::as_bytes(std::span{ele.key}));
80 stream::MemoryReader value_reader(std::as_bytes(std::span{ele.value}));
81 ASSERT_TRUE(WriteProtoStringToBytesMapEntry(ele.field_number,
82 key_reader,
83 ele.key.size(),
84 value_reader,
85 ele.value.size(),
86 stream_pipe_buffer,
87 writer)
88 .ok());
89 }
90
91 ASSERT_EQ(memcmp(dst_buffer, encoded_proto, sizeof(dst_buffer)), 0);
92}
93
94TEST(ProtoHelper, WriteProtoStringToBytesMapEntryExceedsWriteLimit) {
95 // Construct an instance of the message below:
96 //
97 // message Maps {
98 // map<string, string> map_a = 1;
99 // }
100 //
101 // where
102 //
103 // Maps.map_a['key_bar'] = 'bar_a'. The needed buffer size is 18 in this
104 // case:
105 //
106 // {
107 // 0x0a, 0x10,
108 // 0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r',
109 // 0x12, 0x05, 'b', 'a', 'r', '_', 'a',
110 // }
111 //
112 // Use a smaller buffer.
113 std::byte encode_buffer[17];
114 stream::MemoryWriter writer(encode_buffer);
115 constexpr uint32_t kFieldNumber = 1;
116 std::string_view key = "key_bar";
117 std::string_view value = "bar_a";
118 stream::MemoryReader key_reader(std::as_bytes(std::span{key}));
119 stream::MemoryReader value_reader(std::as_bytes(std::span{value}));
120 std::byte stream_pipe_buffer[1];
121 ASSERT_EQ(
122 WriteProtoStringToBytesMapEntry(kFieldNumber,
123 key_reader,
124 key_reader.ConservativeReadLimit(),
125 value_reader,
126 value_reader.ConservativeReadLimit(),
127 stream_pipe_buffer,
128 writer),
129 Status::ResourceExhausted());
130}
131
132TEST(ProtoHelper, WriteProtoStringToBytesMapEntryInvalidArgument) {
133 std::byte encode_buffer[17];
134 stream::MemoryWriter writer(encode_buffer);
135 std::string_view key = "key_bar";
136 std::string_view value = "bar_a";
137 stream::MemoryReader key_reader(std::as_bytes(std::span{key}));
138 stream::MemoryReader value_reader(std::as_bytes(std::span{value}));
139 std::byte stream_pipe_buffer[1];
140
141 ASSERT_EQ(
142 WriteProtoStringToBytesMapEntry(19091,
143 key_reader,
144 key_reader.ConservativeReadLimit(),
145 value_reader,
146 value_reader.ConservativeReadLimit(),
147 stream_pipe_buffer,
148 writer),
149 Status::InvalidArgument());
150}
151
152} // namespace pw::protobuf