| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 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 // TestValid |
| 71 template<class T> |
| 72 void TestValid(PmpColumnReader* reader, const uint16 field_type, |
| 73 const std::vector<T>& elems) { |
| 74 uint32 rows_read = 0xFF; |
| 75 |
| 76 std::vector<uint8> data = Combined(MakeHeader(field_type, elems.size()), |
| 77 Flatten(elems)); |
| 78 EXPECT_TRUE(reader->ReadFromMemory(&rows_read, &data[0], data.size())); |
| 79 EXPECT_EQ(rows_read, elems.size()); |
| 80 |
| 81 for(uint32 i = 0; i < elems.size(); i++) { |
| 82 T target; |
| 83 EXPECT_TRUE(reader->Read(i, &target)); |
| 84 EXPECT_EQ(target, elems[i]); |
| 85 } |
| 86 } |
| 87 |
| 88 template<class T> |
| 89 void TestMalformed(PmpColumnReader* reader, const uint16 field_type, |
| 90 const std::vector<T>& elems) { |
| 91 |
| 92 std::vector<uint8> data_too_few_declared_rows = |
| 93 Combined(MakeHeader(field_type, elems.size()-1), Flatten(elems)); |
| 94 EXPECT_FALSE(reader->ReadFromMemory(NULL, |
| 95 &data_too_few_declared_rows[0], |
| 96 data_too_few_declared_rows.size())); |
| 97 |
| 98 std::vector<uint8> data_too_many_declared_rows = |
| 99 Combined(MakeHeader(field_type, elems.size()+1), Flatten(elems)); |
| 100 EXPECT_FALSE(reader->ReadFromMemory(NULL, |
| 101 &data_too_many_declared_rows[0], |
| 102 data_too_many_declared_rows.size())); |
| 103 |
| 104 std::vector<uint8> data_truncated = |
| 105 Combined(MakeHeader(field_type, elems.size()), Flatten(elems)); |
| 106 data_truncated.resize(data_truncated.size()-10); |
| 107 |
| 108 EXPECT_FALSE(reader->ReadFromMemory(NULL, &data_truncated[0], |
| 109 data_truncated.size())); |
| 110 |
| 111 std::vector<uint8> data_padded = |
| 112 Combined(MakeHeader(field_type, elems.size()), Flatten(elems)); |
| 113 data_padded.resize(data_padded.size()+10); |
| 114 EXPECT_FALSE(reader->ReadFromMemory(NULL, &data_padded[0], |
| 115 data_padded.size())); |
| 116 } |
| 117 |
| 118 template<class T> |
| 119 void TestPrimitives(const uint16 field_type) { |
| 120 PmpColumnReader reader("testcolumn"); |
| 121 |
| 122 // Make an ascending vector of the primitive |
| 123 uint32 n = 100; |
| 124 std::vector<T> data(n, 0); |
| 125 for(uint32 i = 0; i < n; i++) { |
| 126 data[i] = i*3; |
| 127 } |
| 128 |
| 129 TestValid(&reader, field_type, data); |
| 130 TestMalformed(&reader, field_type, data); |
| 131 } |
| 132 |
| 133 |
| 134 TEST(PmpColumnReaderTest, HeaderParsingAndValidation) { |
| 135 PmpColumnReader reader("testcolumn"); |
| 136 |
| 137 // Good header |
| 138 uint32 rows_read = 0xFF; |
| 139 std::vector<uint8> good_header = MakeHeader(0x00, 0); |
| 140 EXPECT_TRUE(reader.ReadFromMemory(&rows_read, &good_header[0], |
| 141 good_header.size())); |
| 142 EXPECT_EQ(rows_read, 0U) << "Read non-zero rows from header-only data."; |
| 143 |
| 144 // Botch up elements of the header |
| 145 std::vector<uint8> bad_magic_byte = MakeHeader(0x00, 0); |
| 146 bad_magic_byte[0] = 0xff; |
| 147 EXPECT_FALSE(reader.ReadFromMemory(NULL, &bad_magic_byte[0], |
| 148 bad_magic_byte.size())); |
| 149 |
| 150 // Where corrupt means the type fields don't agree |
| 151 std::vector<uint8> corrupt_type = MakeHeader(0x00, 0); |
| 152 corrupt_type[fileapi::kPmpFieldTypeFirstOffset] = 0xff; |
| 153 EXPECT_FALSE(reader.ReadFromMemory(NULL, &corrupt_type[0], |
| 154 corrupt_type.size())); |
| 155 |
| 156 std::vector<uint8> invalid_type = MakeHeader(0x00, 0); |
| 157 invalid_type[fileapi::kPmpFieldTypeFirstOffset] = 0xff; |
| 158 invalid_type[fileapi::kPmpFieldTypeSecondOffset] = 0xff; |
| 159 EXPECT_FALSE(reader.ReadFromMemory(NULL, &invalid_type[0], |
| 160 invalid_type.size())); |
| 161 |
| 162 std::vector<uint8> incomplete_header = MakeHeader(0x00, 0); |
| 163 incomplete_header.resize(10); |
| 164 EXPECT_FALSE(reader.ReadFromMemory(NULL, &incomplete_header[0], |
| 165 incomplete_header.size())); |
| 166 } |
| 167 |
| 168 TEST(PmpColumnReaderTest, StringParsing) { |
| 169 uint16 string_type = 0x00; |
| 170 PmpColumnReader reader("testcolumn"); |
| 171 |
| 172 std::vector<std::string> empty_strings(100, ""); |
| 173 |
| 174 // Test empty strings read okay |
| 175 TestValid(&reader, string_type, empty_strings); |
| 176 |
| 177 std::vector<std::string> mixed_strings; |
| 178 mixed_strings.push_back(""); |
| 179 mixed_strings.push_back("Hello"); |
| 180 mixed_strings.push_back("World"); |
| 181 mixed_strings.push_back(""); |
| 182 mixed_strings.push_back("123123"); |
| 183 mixed_strings.push_back("Q"); |
| 184 mixed_strings.push_back(""); |
| 185 |
| 186 // Test that a mixed set of strings read correctly |
| 187 TestValid(&reader, string_type, mixed_strings); |
| 188 |
| 189 // Test with the data messed up in a variety of ways |
| 190 TestMalformed(&reader, string_type, mixed_strings); |
| 191 } |
| 192 |
| 193 TEST(PmpColumnReaderTest, PrimitiveParsing) { |
| 194 TestPrimitives<uint32>(0x01); |
| 195 TestPrimitives<double>(0x02); |
| 196 TestPrimitives<uint8>(0x03); |
| 197 TestPrimitives<uint64>(0x04); |
| 198 TestPrimitives<uint16>(0x05); |
| 199 TestPrimitives<uint32>(0x07); |
| 200 } |
| 201 |
| 202 } // namespace |
| OLD | NEW |