1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "encoder.h"
17 
18 #include <cstdint>
19 #include <limits>
20 #include <string>
21 
22 #include <gtest/gtest.h>
23 
24 namespace dist_proc {
25 namespace aggregation {
26 namespace encoding {
27 
28 namespace {
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 // ------------------------ Tests for AppendToString ------------------------ //
32 
33 struct EncodedTupleParam {
34     int64_t input;
35     const char* encoding;
36     uint8_t encoding_length;
37 };
38 
39 class EncodingCorrectnessTest : public ::testing::TestWithParam<EncodedTupleParam> {};
40 
41 TEST_P(EncodingCorrectnessTest, CorrectEncoding) {
42     EncodedTupleParam params = GetParam();
43     std::string s;
44     Encoder::AppendToString(params.input, &s);
45 
46     std::string_view expected(params.encoding, params.encoding_length);
47     EXPECT_EQ(expected, s);
48     EXPECT_EQ(params.encoding_length, s.length());
49 }
50 
51 TEST_P(EncodingCorrectnessTest, CorrectAppendedEncoding) {
52     EncodedTupleParam params = GetParam();
53     std::string_view suffix(params.encoding, params.encoding_length);
54     std::string with_prefix("thisisaprefix");
55 
56     Encoder::AppendToString(params.input, &with_prefix);
57     EXPECT_EQ(with_prefix.length(), params.encoding_length + strlen("thisisaprefix"));
58     EXPECT_EQ("thisisaprefix", with_prefix.substr(0, strlen("thisisaprefix")));
59     EXPECT_EQ(suffix, with_prefix.substr(strlen("thisisaprefix")));
60 }
61 
62 const EncodedTupleParam cases[] = {
63         {0x0LL, "\0", 1},
64         {0x1LL, "\x1\0", 1},
65         {0xALL, "\xA\0", 1},
66         {0x80LL, "\x80\x01", 2},
67         {0x4000LL, "\x80\x80\x01", 3},
68         {0x200000LL, "\x80\x80\x80\x01", 4},
69         {0x10000000LL, "\x80\x80\x80\x80\x01", 5},
70         {0xFFFFFFFFLL, "\xFF\xFF\xFF\xFF\x0F", 5},
71         {0x03FFFFFFFFLL, "\xFF\xFF\xFF\xFF\x3F", 5},
72         {0x800000000LL, "\x80\x80\x80\x80\x80\x01", 6},
73         {0x40000000000LL, "\x80\x80\x80\x80\x80\x80\x01", 7},
74         {0x2000000000000LL, "\x80\x80\x80\x80\x80\x80\x80\x01", 8},
75         {0x100000000000000LL, "\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9},
76         {-0x01LL, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01", 10},
77         {std::numeric_limits<int64_t>::min(), "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x1", 10},
78         {std::numeric_limits<int64_t>::max(), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 9}};
79 
80 INSTANTIATE_TEST_SUITE_P(EncodingCorrectnessTestCases, EncodingCorrectnessTest,
81                          ::testing::ValuesIn(cases));
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 // ------------------ Tests for SerializeToPackedStringAll ------------------ //
85 
86 struct PackedEncodingTupleParam {
87     std::vector<int64_t> values;
88     const char* encoding;
89     uint8_t encoding_length;
90 };
91 
92 class PackedSerializationTest : public ::testing::TestWithParam<PackedEncodingTupleParam> {};
93 
94 TEST_P(PackedSerializationTest, CorrectPackedEncoding) {
95     PackedEncodingTupleParam params = GetParam();
96     std::string packed;
97 
98     Encoder::SerializeToPackedStringAll(params.values.begin(), params.values.end(), &packed);
99     std::string_view expected(params.encoding, params.encoding_length);
100     EXPECT_EQ(packed, expected);
101     EXPECT_EQ(packed.length(), params.encoding_length);
102 }
103 
104 const PackedEncodingTupleParam packedCases[] = {
105         {{}, "", 0},
106         // Encoding one item should be identical to AppendToString.
107         {{0x0LL}, "\0", 1},
108         {{0x1LL}, "\x1\0", 1},
109         {{0x80LL}, "\x80\x01", 2},
110         {{0x200000LL}, "\x80\x80\x80\x01", 4},
111         {{0x10000000LL}, "\x80\x80\x80\x80\x01", 5},
112         {{0x03FFFFFFFFLL}, "\xFF\xFF\xFF\xFF\x3F", 5},
113         // Combining items from above.
114         {{0x1LL, 0x80LL}, "\x1\x80\x1", 3},
115         {{0x200000LL, 0x03FFFFFFFFLL}, "\x80\x80\x80\x1\xFF\xFF\xFF\xFF?", 9},
116         {{0x1LL, 0x80LL, 0x200000LL, 0x03FFFFFFFFLL},
117          "\x1\x80\x1\x80\x80\x80\x1\xFF\xFF\xFF\xFF?",
118          12},
119         // Multiple items.
120         {{1, 0xdeadbeef, 0x0aaabbbbccccddddL, 5},
121          "\x1\xEF\xFD\xB6\xF5\r\xDD\xBB\xB3\xE6\xBC\xF7\xAE\xD5\n\x5",
122          16},
123         {{1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB}, "\x1\x2\x3\x4\x5\x6\a\b\t\n\v", 11}};
124 
125 INSTANTIATE_TEST_SUITE_P(PackedSerializationTestCases, PackedSerializationTest,
126                          ::testing::ValuesIn(packedCases));
127 
128 TEST(EncoderTest, SerializeToPackedStringAllClearsPrepopulatedString) {
129     std::string empty;
130     std::string prepopulated = "some leftovers";
131     std::vector<int64_t> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB};
132     Encoder::SerializeToPackedStringAll(v.begin(), v.end(), &empty);
133     Encoder::SerializeToPackedStringAll(v.begin(), v.end(), &prepopulated);
134     EXPECT_EQ(prepopulated, "\x1\x2\x3\x4\x5\x6\a\b\t\n\v");
135 
136     EXPECT_EQ(empty, prepopulated);
137 }
138 
139 }  // namespace
140 
141 }  // namespace encoding
142 }  // namespace aggregation
143 }  // namespace dist_proc
144