| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <algorithm> |
| 6 #include <vector> |
| 7 |
| 8 #include "testing/gtest/include/gtest/gtest.h" |
| 9 #include "webkit/fileapi/media/picasa/pmp_column_reader.h" |
| 10 #include "webkit/fileapi/media/picasa/pmp_constants.h" |
| 11 |
| 12 namespace { |
| 13 |
| 14 using fileapi::PmpColumnReader; |
| 15 |
| 16 // Return a vector so we don't have to worry about memory management. |
| 17 std::vector<uint8> MakeHeader(const uint16 field_type, const uint32 row_count) { |
| 18 std::vector<uint8> header(fileapi::kPmpHeaderSize); |
| 19 |
| 20 // Copy in magic bytes. |
| 21 memcpy(&header[0], fileapi::kPmpMagicO0S4, 4); |
| 22 memcpy(&header[6], fileapi::kPmpMagicO6S2, 2); |
| 23 memcpy(&header[8], fileapi::kPmpMagicO8S4, 4); |
| 24 memcpy(&header[14], fileapi::kPmpMagicO14S2, 2); |
| 25 |
| 26 // Copy in field type. |
| 27 memcpy(&header[fileapi::kPmpFieldTypeFirstOffset], &field_type, 2); |
| 28 memcpy(&header[fileapi::kPmpFieldTypeSecondOffset], &field_type, 2); |
| 29 |
| 30 // Copy in row count. |
| 31 memcpy(&header[fileapi::kPmpRowCountOffset], &row_count, 4); |
| 32 |
| 33 return header; |
| 34 } |
| 35 |
| 36 // Flatten a vector of elements into an array of bytes. |
| 37 template<class T> |
| 38 std::vector<uint8> Flatten(const std::vector<T>& elems) { |
| 39 const uint8* elems0 = reinterpret_cast<const uint8*>(&elems[0]); |
| 40 std::vector<uint8> data_body(elems0, elems0 + sizeof(T)*elems.size()); |
| 41 |
| 42 return data_body; |
| 43 } |
| 44 |
| 45 // Custom specialization for strings. |
| 46 // Given a vector of strings, returns a vector of all the characters in strings. |
| 47 template<> |
| 48 std::vector<uint8> Flatten(const std::vector<std::string>& strings) { |
| 49 std::vector<uint8> totalchars; |
| 50 |
| 51 for(std::vector<std::string>::const_iterator it = strings.begin(); |
| 52 it != strings.end(); it++) { |
| 53 std::copy(it->begin(), it->end(), std::back_inserter(totalchars)); |
| 54 totalchars.push_back('\0'); // Add the null termination too. |
| 55 } |
| 56 |
| 57 return totalchars; |
| 58 } |
| 59 |
| 60 std::vector<uint8> Combined(const std::vector<uint8>& a, |
| 61 const std::vector<uint8>& b) { |
| 62 std::vector<uint8> total; |
| 63 |
| 64 std::copy(a.begin(), a.end(), std::back_inserter(total)); |
| 65 std::copy(b.begin(), b.end(), std::back_inserter(total)); |
| 66 |
| 67 return total; |
| 68 } |
| 69 |
| 70 // Overridden version of Read method to make test code templatable. |
| 71 bool DoRead(const PmpColumnReader* reader, uint32 row, std::string* target) { |
| 72 return reader->ReadString(row, target); |
| 73 } |
| 74 |
| 75 bool DoRead(const PmpColumnReader* reader, uint32 row, uint32* target) { |
| 76 return reader->ReadUInt32(row, target); |
| 77 } |
| 78 |
| 79 bool DoRead(const PmpColumnReader* reader, uint32 row, double* target) { |
| 80 return reader->ReadDouble64(row, target); |
| 81 } |
| 82 |
| 83 bool DoRead(const PmpColumnReader* reader, uint32 row, uint8* target) { |
| 84 return reader->ReadUInt8(row, target); |
| 85 } |
| 86 |
| 87 bool DoRead(const PmpColumnReader* reader, uint32 row, uint64* target) { |
| 88 return reader->ReadUInt64(row, target); |
| 89 } |
| 90 |
| 91 // TestValid |
| 92 template<class T> |
| 93 void TestValid(PmpColumnReader* reader, const uint16 field_type, |
| 94 const std::vector<T>& elems) { |
| 95 uint32 rows_read = 0xFF; |
| 96 |
| 97 std::vector<uint8> data = Combined(MakeHeader(field_type, elems.size()), |
| 98 Flatten(elems)); |
| 99 EXPECT_TRUE(reader->ReadFromMemory(&rows_read, &data[0], data.size())); |
| 100 EXPECT_EQ(rows_read, elems.size()); |
| 101 |
| 102 for(uint32 i = 0; i < elems.size(); i++) { |
| 103 T target; |
| 104 EXPECT_TRUE(DoRead(reader, i, &target)); |
| 105 EXPECT_EQ(target, elems[i]); |
| 106 } |
| 107 } |
| 108 |
| 109 template<class T> |
| 110 void TestMalformed(PmpColumnReader* reader, const uint16 field_type, |
| 111 const std::vector<T>& elems) { |
| 112 |
| 113 std::vector<uint8> data_too_few_declared_rows = |
| 114 Combined(MakeHeader(field_type, elems.size()-1), Flatten(elems)); |
| 115 EXPECT_FALSE(reader->ReadFromMemory(NULL, |
| 116 &data_too_few_declared_rows[0], |
| 117 data_too_few_declared_rows.size())); |
| 118 |
| 119 std::vector<uint8> data_too_many_declared_rows = |
| 120 Combined(MakeHeader(field_type, elems.size()+1), Flatten(elems)); |
| 121 EXPECT_FALSE(reader->ReadFromMemory(NULL, |
| 122 &data_too_many_declared_rows[0], |
| 123 data_too_many_declared_rows.size())); |
| 124 |
| 125 std::vector<uint8> data_truncated = |
| 126 Combined(MakeHeader(field_type, elems.size()), Flatten(elems)); |
| 127 data_truncated.resize(data_truncated.size()-10); |
| 128 |
| 129 EXPECT_FALSE(reader->ReadFromMemory(NULL, &data_truncated[0], |
| 130 data_truncated.size())); |
| 131 |
| 132 std::vector<uint8> data_padded = |
| 133 Combined(MakeHeader(field_type, elems.size()), Flatten(elems)); |
| 134 data_padded.resize(data_padded.size()+10); |
| 135 EXPECT_FALSE(reader->ReadFromMemory(NULL, &data_padded[0], |
| 136 data_padded.size())); |
| 137 } |
| 138 |
| 139 template<class T> |
| 140 void TestPrimitives(const uint16 field_type) { |
| 141 PmpColumnReader reader("testcolumn"); |
| 142 |
| 143 // Make an ascending vector of the primitive. |
| 144 uint32 n = 100; |
| 145 std::vector<T> data(n, 0); |
| 146 for(uint32 i = 0; i < n; i++) { |
| 147 data[i] = i*3; |
| 148 } |
| 149 |
| 150 TestValid<T>(&reader, field_type, data); |
| 151 TestMalformed<T>(&reader, field_type, data); |
| 152 } |
| 153 |
| 154 |
| 155 TEST(PmpColumnReaderTest, HeaderParsingAndValidation) { |
| 156 PmpColumnReader reader("testcolumn"); |
| 157 |
| 158 // Good header. |
| 159 uint32 rows_read = 0xFF; |
| 160 std::vector<uint8> good_header = MakeHeader(0x00, 0); |
| 161 EXPECT_TRUE(reader.ReadFromMemory(&rows_read, &good_header[0], |
| 162 good_header.size())); |
| 163 EXPECT_EQ(rows_read, 0U) << "Read non-zero rows from header-only data."; |
| 164 |
| 165 // Botch up elements of the header. |
| 166 std::vector<uint8> bad_magic_byte = MakeHeader(0x00, 0); |
| 167 bad_magic_byte[0] = 0xff; |
| 168 EXPECT_FALSE(reader.ReadFromMemory(NULL, &bad_magic_byte[0], |
| 169 bad_magic_byte.size())); |
| 170 |
| 171 // Corrupt means the type fields don't agree. |
| 172 std::vector<uint8> corrupt_type = MakeHeader(0x00, 0); |
| 173 corrupt_type[fileapi::kPmpFieldTypeFirstOffset] = 0xff; |
| 174 EXPECT_FALSE(reader.ReadFromMemory(NULL, &corrupt_type[0], |
| 175 corrupt_type.size())); |
| 176 |
| 177 std::vector<uint8> invalid_type = MakeHeader(0x00, 0); |
| 178 invalid_type[fileapi::kPmpFieldTypeFirstOffset] = 0xff; |
| 179 invalid_type[fileapi::kPmpFieldTypeSecondOffset] = 0xff; |
| 180 EXPECT_FALSE(reader.ReadFromMemory(NULL, &invalid_type[0], |
| 181 invalid_type.size())); |
| 182 |
| 183 std::vector<uint8> incomplete_header = MakeHeader(0x00, 0); |
| 184 incomplete_header.resize(10); |
| 185 EXPECT_FALSE(reader.ReadFromMemory(NULL, &incomplete_header[0], |
| 186 incomplete_header.size())); |
| 187 } |
| 188 |
| 189 TEST(PmpColumnReaderTest, StringParsing) { |
| 190 PmpColumnReader reader("testcolumn"); |
| 191 |
| 192 std::vector<std::string> empty_strings(100, ""); |
| 193 |
| 194 // Test empty strings read okay. |
| 195 TestValid(&reader, fileapi::kPmpFieldTypeString, empty_strings); |
| 196 |
| 197 std::vector<std::string> mixed_strings; |
| 198 mixed_strings.push_back(""); |
| 199 mixed_strings.push_back("Hello"); |
| 200 mixed_strings.push_back("World"); |
| 201 mixed_strings.push_back(""); |
| 202 mixed_strings.push_back("123123"); |
| 203 mixed_strings.push_back("Q"); |
| 204 mixed_strings.push_back(""); |
| 205 |
| 206 // Test that a mixed set of strings read correctly. |
| 207 TestValid(&reader, fileapi::kPmpFieldTypeString, mixed_strings); |
| 208 |
| 209 // Test with the data messed up in a variety of ways. |
| 210 TestMalformed(&reader, fileapi::kPmpFieldTypeString, mixed_strings); |
| 211 } |
| 212 |
| 213 TEST(PmpColumnReaderTest, PrimitiveParsing) { |
| 214 TestPrimitives<uint32>(fileapi::kPmpFieldTypeUInt32); |
| 215 TestPrimitives<double>(fileapi::kPmpFieldTypeDouble64); |
| 216 TestPrimitives<uint8>(fileapi::kPmpFieldTypeUInt8); |
| 217 TestPrimitives<uint64>(fileapi::kPmpFieldTypeUInt64); |
| 218 } |
| 219 |
| 220 } // namespace |
| OLD | NEW |