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