1 : // Copyright 2011 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 "syzygy/core/serialization.h"
16 : #include "base/files/file_util.h"
17 : #include "gtest/gtest.h"
18 : #include "syzygy/core/unittest_util.h"
19 :
20 : namespace core {
21 :
22 : namespace {
23 :
24 : const Byte kTestData[] = "This is test data.";
25 :
26 : struct Foo {
27 : int i;
28 : double d;
29 : char s[128];
30 :
31 E : Foo() : i(0), d(0) {
32 E : memset(s, 0, sizeof(s));
33 E : }
34 :
35 E : bool operator==(const Foo& foo) const {
36 E : return i == foo.i && d == foo.d && !memcmp(s, foo.s, sizeof(s));
37 E : }
38 :
39 : // These are the serialization implementation.
40 E : template<class OutArchive> bool Save(OutArchive* out_archive) const {
41 : return out_archive->Save(i) && out_archive->Save(d) &&
42 E : out_archive->Save(s);
43 E : }
44 E : template<class InArchive> bool Load(InArchive* in_archive) {
45 : return in_archive->Load(&i) && in_archive->Load(&d) &&
46 E : in_archive->Load(&s);
47 E : }
48 : };
49 :
50 : } // namespace
51 :
52 : class SerializationTest : public testing::Test {
53 : public:
54 E : virtual void SetUp() {
55 E : ASSERT_TRUE(base::CreateNewTempDirectory(L"", &temp_dir_));
56 E : }
57 :
58 E : virtual void TearDown() {
59 E : base::DeleteFile(temp_dir_, true);
60 E : }
61 :
62 E : template<typename Data> bool TestRoundTrip(const Data& data) {
63 E : base::FilePath path;
64 E : base::ScopedFILE file;
65 E : file.reset(base::CreateAndOpenTemporaryFileInDir(temp_dir_, &path));
66 E : EXPECT_TRUE(file.get() != NULL);
67 E : EXPECT_FALSE(path.empty());
68 :
69 E : EXPECT_TRUE(testing::TestSerialization(data));
70 E : EXPECT_TRUE(testing::TestSerialization(data, file.get()));
71 :
72 E : return true;
73 E : }
74 :
75 E : const base::FilePath& temp_dir() const { return temp_dir_; }
76 :
77 : private:
78 : base::FilePath temp_dir_;
79 : };
80 :
81 E : TEST_F(SerializationTest, IteratorOutStream) {
82 E : ByteVector bytes;
83 E : ScopedOutStreamPtr out_stream;
84 E : out_stream.reset(CreateByteOutStream(std::back_inserter(bytes)));
85 :
86 : // Writing data should work, and should match the source data.
87 E : EXPECT_TRUE(out_stream->Write(2, kTestData));
88 E : EXPECT_TRUE(out_stream->Write(sizeof(kTestData) - 2, kTestData + 2));
89 E : EXPECT_EQ(sizeof(kTestData), bytes.size());
90 E : EXPECT_EQ(0, memcmp(&bytes[0], kTestData, sizeof(kTestData)));
91 E : }
92 :
93 E : TEST_F(SerializationTest, IteratorInStream) {
94 : // Populate a vector of bytes with some test data, and wrap a ByteInStream
95 : // around it.
96 E : ByteVector bytes;
97 E : bytes.resize(sizeof(kTestData));
98 E : std::copy(kTestData, kTestData + sizeof(kTestData), bytes.begin());
99 E : ScopedInStreamPtr in_stream;
100 E : in_stream.reset(CreateByteInStream(bytes.begin(), bytes.end()));
101 :
102 : // Reading data should work, and should match the source data.
103 : Byte buffer[sizeof(kTestData)];
104 E : EXPECT_TRUE(in_stream->Read(2, buffer));
105 E : EXPECT_TRUE(in_stream->Read(sizeof(kTestData) - 2, buffer + 2));
106 E : EXPECT_EQ(0, memcmp(&bytes[0], kTestData, sizeof(kTestData)));
107 :
108 : // We should not be able to read past the end of an exhausted buffer.
109 E : EXPECT_FALSE(in_stream->Read(sizeof(kTestData), buffer));
110 E : }
111 :
112 E : TEST_F(SerializationTest, FileOutStream) {
113 E : base::FilePath path;
114 E : base::ScopedFILE file;
115 E : file.reset(base::CreateAndOpenTemporaryFileInDir(temp_dir(), &path));
116 E : EXPECT_TRUE(file.get() != NULL);
117 E : EXPECT_FALSE(path.empty());
118 :
119 E : FileOutStream out_stream(file.get());
120 :
121 : // Write some test data to a file.
122 E : EXPECT_TRUE(out_stream.Write(2, kTestData));
123 E : EXPECT_TRUE(out_stream.Write(sizeof(kTestData) - 2, kTestData + 2));
124 :
125 : // Load the data from the file and ensure it matches the original data.
126 E : file.reset();
127 E : file.reset(base::OpenFile(path, "rb"));
128 : Byte buffer[sizeof(kTestData)];
129 : EXPECT_EQ(sizeof(kTestData), fread(buffer, 1, sizeof(kTestData),
130 E : file.get()));
131 E : EXPECT_EQ(0, memcmp(buffer, kTestData, sizeof(kTestData)));
132 E : }
133 :
134 E : TEST_F(SerializationTest, FileInStream) {
135 E : base::FilePath path;
136 E : base::ScopedFILE file;
137 E : file.reset(base::CreateAndOpenTemporaryFileInDir(temp_dir(), &path));
138 E : EXPECT_TRUE(file.get() != NULL);
139 E : EXPECT_FALSE(path.empty());
140 :
141 : // Write some test data to a file, then close and reopen it for reading.
142 : EXPECT_EQ(sizeof(kTestData), fwrite(kTestData, 1, sizeof(kTestData),
143 E : file.get()));
144 E : file.reset();
145 E : file.reset(base::OpenFile(path, "rb"));
146 :
147 E : FileInStream in_stream(file.get());
148 : Byte buffer[sizeof(kTestData)];
149 E : EXPECT_TRUE(in_stream.Read(sizeof(kTestData), buffer));
150 E : EXPECT_EQ(0, memcmp(buffer, kTestData, sizeof(kTestData)));
151 :
152 : // We should not be able to read any more data.
153 E : EXPECT_FALSE(in_stream.Read(sizeof(kTestData), buffer));
154 E : }
155 :
156 E : TEST_F(SerializationTest, PlainOldDataTypesRoundTrip) {
157 E : EXPECT_TRUE(TestRoundTrip<bool>(true));
158 E : EXPECT_TRUE(TestRoundTrip<char>('c'));
159 E : EXPECT_TRUE(TestRoundTrip<wchar_t>(L'c'));
160 E : EXPECT_TRUE(TestRoundTrip<float>(0.1f));
161 E : EXPECT_TRUE(TestRoundTrip<double>(9.7e45));
162 E : EXPECT_TRUE(TestRoundTrip<int8>(-8));
163 E : EXPECT_TRUE(TestRoundTrip<int16>(-16));
164 E : EXPECT_TRUE(TestRoundTrip<int32>(-32));
165 E : EXPECT_TRUE(TestRoundTrip<int64>(-64));
166 E : EXPECT_TRUE(TestRoundTrip<uint8>(8));
167 E : EXPECT_TRUE(TestRoundTrip<uint16>(16));
168 E : EXPECT_TRUE(TestRoundTrip<uint32>(32));
169 E : EXPECT_TRUE(TestRoundTrip<uint64>(64));
170 E : }
171 :
172 E : TEST_F(SerializationTest, StlTypesRoundTrip) {
173 E : std::string string = "This is a string.";
174 E : EXPECT_TRUE(TestRoundTrip<std::string>(string));
175 :
176 E : std::wstring wstring = L"This is a wstring.";
177 E : EXPECT_TRUE(TestRoundTrip<std::wstring>(wstring));
178 :
179 E : std::map<int, int> map;
180 E : map.insert(std::make_pair(0, 1));
181 E : map.insert(std::make_pair(1, -1));
182 E : map.insert(std::make_pair(100, 42));
183 E : EXPECT_TRUE(TestRoundTrip(map));
184 :
185 E : std::pair<int, int> pair(0, 1);
186 E : EXPECT_TRUE(TestRoundTrip(pair));
187 :
188 E : std::set<int> set;
189 E : set.insert(0);
190 E : set.insert(2);
191 E : set.insert(4);
192 E : EXPECT_TRUE(TestRoundTrip(set));
193 :
194 E : std::vector<int> vector;
195 E : vector.push_back(1);
196 E : vector.push_back(3);
197 E : vector.push_back(5);
198 E : EXPECT_TRUE(TestRoundTrip(vector));
199 E : }
200 :
201 E : TEST_F(SerializationTest, CustomTypeRoundTrip) {
202 E : const char string[] = "I'm fond of jellybeans.";
203 :
204 E : Foo foo;
205 E : foo.i = 42;
206 E : foo.d = 13.7;
207 E : memcpy(foo.s, string, sizeof(string));
208 :
209 E : EXPECT_TRUE(TestRoundTrip(foo));
210 E : }
211 :
212 : } // namespace core
|