| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "peridot/bin/cloud_provider_firestore/firestore/encoding.h" |
| |
| #include <string> |
| |
| #include <google/protobuf/util/time_util.h> |
| #include <gtest/gtest.h> |
| |
| #include "peridot/bin/cloud_provider_firestore/firestore/testing/encoding.h" |
| #include "peridot/lib/convert/convert.h" |
| |
| namespace cloud_provider_firestore { |
| |
| namespace { |
| |
| // Creates correct std::strings with \0 bytes inside from C-style string |
| // constants. |
| std::string operator"" _s(const char* str, size_t size) { |
| return std::string(str, size); |
| } |
| |
| using StringEncodingTest = ::testing::TestWithParam<std::string>; |
| |
| TEST_P(StringEncodingTest, BackAndForth) { |
| std::string data = GetParam(); |
| std::string encoded; |
| std::string decoded; |
| |
| encoded = EncodeKey(data); |
| EXPECT_EQ('+', encoded.back()); |
| EXPECT_TRUE(DecodeKey(encoded, &decoded)); |
| EXPECT_EQ(data, decoded); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(ExampleData, StringEncodingTest, |
| ::testing::Values(""_s, "abcdef"_s, "\x02\x7F"_s, |
| "~!@#$%^&*()_+-="_s, "\0"_s, |
| "bazinga\0\0\0"_s)); |
| |
| TEST(BatchEncodingTest, Empty) { |
| cloud_provider::CommitPack commits; |
| ASSERT_TRUE(cloud_provider::EncodeCommitPack({}, &commits)); |
| google::firestore::v1beta1::Document document; |
| ASSERT_TRUE(EncodeCommitBatch(commits, &document)); |
| |
| std::vector<cloud_provider::CommitPackEntry> entries; |
| std::string timestamp; |
| ASSERT_TRUE(DecodeCommitBatch(document, &entries, ×tamp)); |
| EXPECT_EQ(0u, entries.size()); |
| } |
| |
| TEST(BatchEncodingTest, TwoCommits) { |
| cloud_provider::CommitPack commits; |
| ASSERT_TRUE(cloud_provider::EncodeCommitPack( |
| {{"id0", "data0"}, {"id1", "data1"}}, &commits)); |
| google::firestore::v1beta1::Document document; |
| ASSERT_TRUE(EncodeCommitBatch(commits, &document)); |
| |
| std::vector<cloud_provider::CommitPackEntry> entries; |
| std::string timestamp; |
| ASSERT_TRUE(DecodeCommitBatch(document, &entries, ×tamp)); |
| EXPECT_EQ(2u, entries.size()); |
| EXPECT_EQ("id0", entries[0].id); |
| EXPECT_EQ("data0", entries[0].data); |
| EXPECT_EQ("id1", entries[1].id); |
| EXPECT_EQ("data1", entries[1].data); |
| } |
| |
| TEST(BatchEncodingTest, Timestamp) { |
| cloud_provider::CommitPack commits; |
| ASSERT_TRUE(cloud_provider::EncodeCommitPack({{"id0", "data0"}}, &commits)); |
| google::firestore::v1beta1::Document document; |
| google::protobuf::Timestamp protobuf_timestamp; |
| ASSERT_TRUE(google::protobuf::util::TimeUtil::FromString( |
| "2018-06-26T14:39:22+00:00", &protobuf_timestamp)); |
| std::string original_timestamp; |
| ASSERT_TRUE(protobuf_timestamp.SerializeToString(&original_timestamp)); |
| EncodeCommitBatchWithTimestamp(commits, original_timestamp, &document); |
| |
| std::vector<cloud_provider::CommitPackEntry> entries; |
| std::string decoded_timestamp; |
| EXPECT_TRUE(DecodeCommitBatch(document, &entries, &decoded_timestamp)); |
| EXPECT_EQ(original_timestamp, decoded_timestamp); |
| } |
| |
| TEST(BatchEncodingTest, DecodingErrors) { |
| std::vector<cloud_provider::CommitPackEntry> entries; |
| std::string timestamp; |
| |
| { |
| // Empty document. |
| google::firestore::v1beta1::Document document; |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Non-empty but the commit key is missing. |
| google::firestore::v1beta1::Document document; |
| (*document.mutable_fields())["some_field"].set_integer_value(3); |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Commits field is not an array. |
| google::firestore::v1beta1::Document document; |
| (*document.mutable_fields())["commits"].set_integer_value(3); |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Commits contains a commit that is not a map. |
| google::firestore::v1beta1::Document document; |
| google::firestore::v1beta1::ArrayValue* commit_array = |
| (*document.mutable_fields())["commits"].mutable_array_value(); |
| commit_array->add_values()->set_integer_value(3); |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Commits contains a commit that misses the "data" field. |
| google::firestore::v1beta1::Document document; |
| google::firestore::v1beta1::ArrayValue* commit_array = |
| (*document.mutable_fields())["commits"].mutable_array_value(); |
| google::firestore::v1beta1::MapValue* commit_value = |
| commit_array->add_values()->mutable_map_value(); |
| *((*commit_value->mutable_fields())["id"].mutable_bytes_value()) = |
| "some_id"; |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Commits contains a commit that misses the "id" field. |
| google::firestore::v1beta1::Document document; |
| google::firestore::v1beta1::ArrayValue* commit_array = |
| (*document.mutable_fields())["commits"].mutable_array_value(); |
| google::firestore::v1beta1::MapValue* commit_value = |
| commit_array->add_values()->mutable_map_value(); |
| *((*commit_value->mutable_fields())["data"].mutable_bytes_value()) = |
| "some_data"; |
| EXPECT_FALSE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| |
| { |
| // Correct batch (sanity check). |
| google::firestore::v1beta1::Document document; |
| google::firestore::v1beta1::ArrayValue* commit_array = |
| (*document.mutable_fields())["commits"].mutable_array_value(); |
| google::firestore::v1beta1::MapValue* commit_value = |
| commit_array->add_values()->mutable_map_value(); |
| *((*commit_value->mutable_fields())["id"].mutable_bytes_value()) = |
| "some_id"; |
| *((*commit_value->mutable_fields())["data"].mutable_bytes_value()) = |
| "some_data"; |
| EXPECT_TRUE(DecodeCommitBatch(document, &entries, ×tamp)); |
| } |
| } |
| |
| } // namespace |
| |
| } // namespace cloud_provider_firestore |