-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Serialize (and deserialize) bool values #791
Changes from 2 commits
099d8b3
6dbfd5b
99204f4
74892fc
37d7c6c
5e390dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,16 @@ class Serializer { | |
} | ||
|
||
private: | ||
static void EncodeNull(pb_ostream_t* stream); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional: these can be free functions in .cc file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
static void EncodeBool(pb_ostream_t* stream, bool bool_value); | ||
static void EncodeVarint(pb_ostream_t* stream, | ||
uint32_t field_number, | ||
uint64_t value); | ||
|
||
static void DecodeNull(pb_istream_t* stream); | ||
static bool DecodeBool(pb_istream_t* stream); | ||
static uint64_t DecodeVarint(pb_istream_t* stream); | ||
|
||
// TODO(rsgowman): We don't need the database_id_ yet (but will eventually). | ||
// const firebase::firestore::model::DatabaseId& database_id_; | ||
}; | ||
|
@@ -134,6 +144,8 @@ inline bool operator==(const Serializer::TypedValue& lhs, | |
FIREBASE_DEV_ASSERT(rhs.value.null_value == | ||
google_protobuf_NullValue_NULL_VALUE); | ||
return true; | ||
case firebase::firestore::model::FieldValue::Type::Boolean: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest to move this to .cc file, it's getting long quickly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it's not going to get any shorter in the future either. Done. |
||
return lhs.value.boolean_value == rhs.value.boolean_value; | ||
default: | ||
// TODO(rsgowman): implement the other types | ||
abort(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,5 +93,42 @@ TEST_F(SerializerTest, EncodesNullProtoToBytes) { | |
ExpectRoundTrip(proto, bytes, FieldValue::Type::Null); | ||
} | ||
|
||
TEST_F(SerializerTest, EncodesBoolModelToProto) { | ||
for (bool test : {true, false}) { | ||
FieldValue model = FieldValue::BooleanValue(test); | ||
Serializer::TypedValue proto{FieldValue::Type::Boolean, | ||
google_firestore_v1beta1_Value_init_default}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Continuing the discussion from the previous PR: why does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't. It's done this way for symmetry with the underlying nanopb struct. We could add some ctors/etc, but we do still need to work with the underlying nanopb POD, so I don't think that's going to buy us very much. Additionally, there (probably) won't be wrappers for the other nanopb protos. (The only reason this one exists is because of the oneof within the proto.) So code that uses this has to deal with nanopb POD structs anyways. (All that said, I don't object to converting it. Though that path may lead us to wrapping all of nanopbs structs.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general, I think it's preferable to have higher-level code, unless there is a specific reason not to. So in this case, hiding the Why would this lead to wrapping other nanopb structs? Is it for symmetry? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed offline. Summary:
Decision: Defer for now. (But others are welcome to chime in.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SGTM to defer; I'd make the argument that we can deviate from convention if it keeps us from repeating code too much. We can also just wrap these in local functions if we find ourselves repeating this incantation too often in tests. |
||
proto.value.boolean_value = test; | ||
ExpectRoundTrip(model, proto, FieldValue::Type::Boolean); | ||
} | ||
} | ||
|
||
TEST_F(SerializerTest, EncodesBoolProtoToBytes) { | ||
struct TestCase { | ||
bool value; | ||
std::vector<uint8_t> bytes; | ||
}; | ||
|
||
/* NB: proto true_bytes were created via (and similarly for false_bytes): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment is great, but a little repetitive with the one for nulls. Perhaps move the command to a file-level comment (along the lines of byte values used in tests were obtained by running echo 'APPROPRIATE_VALUE_HERE' | There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
echo 'boolean_value: true' \ | ||
| ./build/external/protobuf/src/protobuf-build/src/protoc \ | ||
-I./Firestore/Protos/protos \ | ||
-I./build/external/protobuf/src/protobuf/src/ \ | ||
--encode=google.firestore.v1beta1.Value \ | ||
google/firestore/v1beta1/document.proto \ | ||
> output.bin | ||
*/ | ||
std::vector<uint8_t> true_bytes{0x08, 0x01}; | ||
std::vector<uint8_t> false_bytes{0x08, 0x00}; | ||
|
||
for (const TestCase& test : | ||
{TestCase{true, true_bytes}, TestCase{false, false_bytes}}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Iterating through two test cases is a little odd. I've done this for symmetry with java (as well as with the future test cases) but don't object to unrolling the loop either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a little clumsy specified inline in the loop this way. Also it needlessly separates the boolean from the bytes in the input. Maybe initialize the TestCases above? // TEXT_FORMAT_PROTO: 'boolean_value: true'
TestCase true_case{true, {0x08, 0x01}};
// TEXT_FORMAT_PROTO: 'boolean_value: false'
TestCase false_case{false, {0x08, 0x00}};
for (const TestCase& test : {true_case, false_case}) {
// ...
} Or even: std::vector<TestCase> cases{
// TEXT_FORMAT_PROTO: 'boolean_value: true'
{true, {0x08, 0x01}},
// TEXT_FORMAT_PROTO: 'boolean_value: false'
{false, {0x08, 0x00}
};
for (const TestCase& test : cases) {
// ...
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really like the latter option; done. (The style formatter really does a number on it though.) |
||
Serializer::TypedValue proto{FieldValue::Type::Boolean, | ||
google_firestore_v1beta1_Value_init_default}; | ||
proto.value.boolean_value = test.value; | ||
ExpectRoundTrip(proto, test.bytes, FieldValue::Type::Boolean); | ||
} | ||
} | ||
|
||
// TODO(rsgowman): Test [en|de]coding multiple protos into the same output | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional: death-test for decode invalid bytes? say, if there is data-corruption, I guess those should be caught by decoder. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we'll definitely need that. Error handling's not there yet though, so I've just added a TODO for now. |
||
// vector. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer more something more natural reading/sounding than "retval". How about "result"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. (retval is an old habit of mine; I can guarantee you'll see it again. Feel free to keep calling it out.)