blob: 6d01bf948efcb7131c8d1f630e55715ffb829785 [file] [log] [blame]
Vitaly Buka00b61072016-10-19 23:22:511// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "protobuf_mutator.h"
Vitaly Buka00b61072016-10-19 23:22:5116
Vitaly Buka0e17fd72016-11-18 18:02:4617#include <iostream>
18#include <map>
19#include <string>
Vitaly Buka00b61072016-10-19 23:22:5120
Vitaly Buka0e17fd72016-11-18 18:02:4621#include "google/protobuf/message.h"
Vitaly Buka00b61072016-10-19 23:22:5122
Vitaly Buka0e17fd72016-11-18 18:02:4623using google::protobuf::Message;
24using google::protobuf::FieldDescriptor;
25using google::protobuf::EnumValueDescriptor;
26using google::protobuf::Descriptor;
27using google::protobuf::Reflection;
28using google::protobuf::OneofDescriptor;
29
30namespace {
31
32const size_t kAddWeight = 1;
33const size_t kDeleteWeight = 1;
34const size_t kUpdateWeight = 4;
35const size_t kSwapWeight = 4;
36const size_t kReplaceWeight = 1;
37
38enum class Mutation {
Vitaly Buka30de3092016-11-18 19:39:0739 None,
Vitaly Buka0e17fd72016-11-18 18:02:4640 Add,
Vitaly Buka30de3092016-11-18 19:39:0741 AddRepeated,
Vitaly Buka0e17fd72016-11-18 18:02:4642 Delete,
43 Update,
44 Swap,
45 // Replace,
46};
47
48std::map<std::string, int> stat;
49
Vitaly Buka30de3092016-11-18 19:39:0750class FieldMutator {
51 public:
52 FieldMutator(Message* message, const FieldDescriptor& field,
53 std::mt19937_64* rng)
54 : message_(message), field_(field), rng_(rng) {}
55
56 bool CreateField() {
57 const Reflection* reflection = message_->GetReflection();
58
59 switch (field_.cpp_type()) {
60 case FieldDescriptor::CPPTYPE_INT32:
61 reflection->SetInt32(
62 message_, &field_,
63 field_.has_default_value() ? field_.default_value_int32() : 0);
64 break;
65 case FieldDescriptor::CPPTYPE_INT64:
66 reflection->SetInt64(
67 message_, &field_,
68 field_.has_default_value() ? field_.default_value_int64() : 0);
69 break;
70 case FieldDescriptor::CPPTYPE_UINT32:
71 reflection->SetUInt32(
72 message_, &field_,
73 field_.has_default_value() ? field_.default_value_uint32() : 0);
74 break;
75 case FieldDescriptor::CPPTYPE_UINT64:
76 reflection->SetUInt64(
77 message_, &field_,
78 field_.has_default_value() ? field_.default_value_uint64() : 0);
79 break;
80 case FieldDescriptor::CPPTYPE_DOUBLE:
81 reflection->SetDouble(
82 message_, &field_,
83 field_.has_default_value() ? field_.default_value_double() : 0);
84 break;
85 case FieldDescriptor::CPPTYPE_FLOAT:
86 reflection->SetFloat(
87 message_, &field_,
88 field_.has_default_value() ? field_.default_value_float() : 0);
89 break;
90 case FieldDescriptor::CPPTYPE_BOOL:
91 reflection->SetBool(message_, &field_, field_.has_default_value() &&
92 field_.default_value_bool());
93 break;
94 case FieldDescriptor::CPPTYPE_ENUM:
95 reflection->SetEnum(message_, &field_,
96 field_.has_default_value()
97 ? field_.default_value_enum()
98 : field_.enum_type()->value(0));
99 break;
100 case FieldDescriptor::CPPTYPE_STRING:
101 reflection->SetString(message_, &field_,
102 field_.has_default_value()
103 ? field_.default_value_string()
104 : std::string());
105 break;
106 case FieldDescriptor::CPPTYPE_MESSAGE:
107 reflection->MutableMessage(message_, &field_);
108 break;
109 default:
110 assert(!"Unknown type");
111 return false;
112 };
113 return true;
114 }
115
116 private:
117 Message* message_;
118 const FieldDescriptor& field_;
119 std::mt19937_64* rng_;
120};
121
Vitaly Buka0e17fd72016-11-18 18:02:46122} // namespace
123
124ProtobufMutator::ProtobufMutator(uint32_t seed, bool always_initialized)
125 : rng_(seed), always_initialized_(always_initialized) {}
Vitaly Buka00b61072016-10-19 23:22:51126
127ProtobufMutator::~ProtobufMutator() {
Vitaly Buka0e17fd72016-11-18 18:02:46128 for (const auto& p : stat) {
129 std::cout << p.first << "\t" << p.second << std::endl;
130 }
Vitaly Buka00b61072016-10-19 23:22:51131}
132
Vitaly Buka0e17fd72016-11-18 18:02:46133bool ProtobufMutator::Mutate(Message* message) {
134 // size
135
136 const Descriptor* descriptor = message->GetDescriptor();
137 const Reflection* reflection = message->GetReflection();
138 // reflection->ListFields
139
140 size_t current_weight = 0;
141 const FieldDescriptor* selected_field = nullptr;
Vitaly Buka0e17fd72016-11-18 18:02:46142
143 // Pick field to mutate.
144 for (int i = 0; i < descriptor->field_count(); ++i) {
145 const FieldDescriptor* field = descriptor->field(i);
146 stat[field->full_name()];
147
148 // Select entire oneof group with probability of single field.
149 if (field->containing_oneof() && field->index_in_oneof() != 0) continue;
150
151 if (GetRandom(1, ++current_weight)) selected_field = field;
152
153 // assert(!field->is_repeated() || !field->containing_oneof());
154 // assert(field->is_optional() || !field->containing_oneof());
155 // assert(!field->is_required() || !field->containing_oneof());
156
157 // if (field->is_required()) {
158
159 // } else if field->is_optional() {
160
161 // } else if field->is_optional() {
162
163 // if (field->is_repeated() ||
164 // (!field->is_repeated() && !reflection->HasField(*message, field)) ||
165 // (!field->is_repeated() && !reflection->HasField(*message, field))) {
166
167 // }
168 }
169
Vitaly Buka30de3092016-11-18 19:39:07170 assert(selected_field);
171
Vitaly Buka0e17fd72016-11-18 18:02:46172 current_weight = 0;
Vitaly Buka30de3092016-11-18 19:39:07173 Mutation mutation = Mutation::None;
Vitaly Buka0e17fd72016-11-18 18:02:46174
175 if (const OneofDescriptor* oneof = selected_field->containing_oneof()) {
176 selected_field = reflection->GetOneofFieldDescriptor(*message, oneof);
177 if (!selected_field) {
Vitaly Buka0e17fd72016-11-18 18:02:46178 selected_field = oneof->field(GetRandomIndex(oneof->field_count()));
Vitaly Buka30de3092016-11-18 19:39:07179 mutation = Mutation::Add;
Vitaly Buka0e17fd72016-11-18 18:02:46180 }
181 } else {
Vitaly Buka30de3092016-11-18 19:39:07182 if (selected_field->is_repeated()) {
183 if (!reflection->FieldSize(*message, selected_field))
184 mutation = Mutation::AddRepeated;
185 } else {
186 if (!reflection->HasField(*message, selected_field))
187 mutation = Mutation::Add;
188 }
189 // if (!reflection->FieldSize(*message, selected_field)) {
190 // mutation = Mutation::AddRepeated;
191 // } else if (!selected_field->is_repeated() && !)) {
192
193 // }
Vitaly Buka0e17fd72016-11-18 18:02:46194 switch (selected_field->label()) {
195 case FieldDescriptor::LABEL_REQUIRED:
196 break;
197 case FieldDescriptor::LABEL_OPTIONAL:
198 break;
199 case FieldDescriptor::LABEL_REPEATED:
200 break;
201 default:
202 assert(!"Unknown label");
203 }
204 }
205
206 stat[selected_field->full_name()]++;
207
Vitaly Buka30de3092016-11-18 19:39:07208 FieldMutator field_mutator(message, *selected_field, &rng_);
209
210 assert(selected_field);
211 switch (mutation) {
212 case Mutation::Add:
213 return field_mutator.CreateField();
214 }
215
Vitaly Buka0e17fd72016-11-18 18:02:46216 // for (int i = 0; i < descriptor->field_count(); ++i) {
217 // const FieldDescriptor* field = descriptor->field(i);
218
219 // switch(field->type()) {
220 // case FieldDescriptor::TYPE_DOUBLE:
221 // case FieldDescriptor::TYPE_FLOAT:
222 // case FieldDescriptor::TYPE_INT64:
223 // case FieldDescriptor::TYPE_UINT64:
224 // case FieldDescriptor::TYPE_INT32:
225 // case FieldDescriptor::TYPE_FIXED64:
226 // case FieldDescriptor::TYPE_FIXED32:
227 // case FieldDescriptor::TYPE_BOOL:
228 // case FieldDescriptor::TYPE_STRING:
229 // case FieldDescriptor::TYPE_GROUP:
230 // case FieldDescriptor::TYPE_MESSAGE:
231 // case FieldDescriptor::TYPE_BYTES:
232 // case FieldDescriptor::TYPE_UINT32:
233 // case FieldDescriptor::TYPE_ENUM:
234 // case FieldDescriptor::TYPE_SFIXED32:
235 // case FieldDescriptor::TYPE_SFIXED64:
236 // case FieldDescriptor::TYPE_SINT32:
237 // case FieldDescriptor::TYPE_SINT64:
238 // break;
239 // default:
240 // assert(!"Unknown type");
241 // };
242
243 // printf("%s %s %d", field->type_name(), field->full_name().c_str(),
244 // field->type());
245 // if (field->is_repeated()) {
246 // int s = reflection->FieldSize(*message, field);
247 // printf(" %d", s);
248 // } else {
249 // if (reflection->HasField(*message, field)) {
250 // }
251 // }
252 // printf("\n");
253 // }
254
Vitaly Buka00b61072016-10-19 23:22:51255 return false;
256}
Vitaly Buka0e17fd72016-11-18 18:02:46257
258bool ProtobufMutator::CrossOver(const Message& with, Message* message) {
Vitaly Buka00b61072016-10-19 23:22:51259 return false;
260}
261
262bool ProtobufMutator::MutateField(const FieldDescriptor& field, int32_t* value) {
263 return false;
264}
265
Vitaly Buka0e17fd72016-11-18 18:02:46266bool ProtobufMutator::MutateField(const FieldDescriptor& field,
267 int64_t* value) {
268 return false;
269}
270
271bool ProtobufMutator::MutateField(const FieldDescriptor& field,
272 uint32_t* value) {
273 return false;
274}
275
276bool ProtobufMutator::MutateField(const FieldDescriptor& field,
277 uint64_t* value) {
278 return false;
279}
280
281bool ProtobufMutator::MutateField(const FieldDescriptor& field, double* value) {
282 return false;
283}
284
285bool ProtobufMutator::MutateField(const FieldDescriptor& field, float* value) {
286 return false;
287}
288
289bool ProtobufMutator::MutateField(const FieldDescriptor& field, bool* value) {
290 return false;
291}
292
293bool ProtobufMutator::MutateField(const FieldDescriptor& field,
294 const EnumValueDescriptor** value) {
295 return false;
296}
297
298bool ProtobufMutator::MutateField(const FieldDescriptor& field,
299 Message* value) {
300 return false;
301}
302
303bool ProtobufMutator::GetRandom(size_t n, size_t m) {
304 assert(n <= m);
305 return std::uniform_int_distribution<size_t>(1, m)(rng_) <= n;
306}
307
308size_t ProtobufMutator::GetRandomIndex(size_t count) {
309 assert(count > 0);
310 return std::uniform_int_distribution<size_t>(0, count - 1)(rng_);
311}