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 "base/files/file.h" 9 #include "base/files/file_util.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "chrome/common/media_galleries/pmp_constants.h" 12 #include "chrome/common/media_galleries/pmp_test_util.h" 13 #include "chrome/utility/media_galleries/pmp_column_reader.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace picasa { 17 18 namespace { 19 20 bool InitColumnReaderFromBytes( 21 PmpColumnReader* const reader, 22 const std::vector<char>& data, 23 const PmpFieldType expected_type) { 24 base::ScopedTempDir temp_dir; 25 if (!temp_dir.CreateUniqueTempDir()) 26 return false; 27 28 base::FilePath temp_path; 29 if (!base::CreateTemporaryFileInDir(temp_dir.path(), &temp_path)) 30 return false; 31 32 // Explicit conversion from signed to unsigned. 33 size_t bytes_written = base::WriteFile(temp_path, &data[0], data.size()); 34 if (bytes_written != data.size()) 35 return false; 36 37 base::File file(temp_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 38 if (!file.IsValid()) 39 return false; 40 41 return reader->ReadFile(&file, expected_type); 42 } 43 44 // Overridden version of Read method to make test code templatable. 45 bool DoRead(const PmpColumnReader* reader, uint32 row, std::string* target) { 46 return reader->ReadString(row, target); 47 } 48 49 bool DoRead(const PmpColumnReader* reader, uint32 row, uint32* target) { 50 return reader->ReadUInt32(row, target); 51 } 52 53 bool DoRead(const PmpColumnReader* reader, uint32 row, double* target) { 54 return reader->ReadDouble64(row, target); 55 } 56 57 bool DoRead(const PmpColumnReader* reader, uint32 row, uint8* target) { 58 return reader->ReadUInt8(row, target); 59 } 60 61 bool DoRead(const PmpColumnReader* reader, uint32 row, uint64* target) { 62 return reader->ReadUInt64(row, target); 63 } 64 65 // TestValid 66 template<class T> 67 void TestValid(const PmpFieldType field_type, 68 const std::vector<T>& elems) { 69 PmpColumnReader reader; 70 std::vector<char> data = 71 PmpTestUtil::MakeHeaderAndBody(field_type, elems.size(), elems); 72 ASSERT_TRUE(InitColumnReaderFromBytes(&reader, data, field_type)); 73 EXPECT_EQ(elems.size(), reader.rows_read()); 74 75 for (uint32 i = 0; i < elems.size() && i < reader.rows_read(); i++) { 76 T target; 77 EXPECT_TRUE(DoRead(&reader, i, &target)); 78 EXPECT_EQ(elems[i], target); 79 } 80 } 81 82 template<class T> 83 void TestMalformed(const PmpFieldType field_type, 84 const std::vector<T>& elems) { 85 PmpColumnReader reader_too_few_declared_rows; 86 std::vector<char> data_too_few_declared_rows = 87 PmpTestUtil::MakeHeaderAndBody(field_type, elems.size()-1, elems); 88 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_too_few_declared_rows, 89 data_too_few_declared_rows, 90 field_type)); 91 92 PmpColumnReader reader_too_many_declared_rows; 93 std::vector<char> data_too_many_declared_rows = 94 PmpTestUtil::MakeHeaderAndBody(field_type, elems.size()+1, elems); 95 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_too_many_declared_rows, 96 data_too_many_declared_rows, 97 field_type)); 98 99 PmpColumnReader reader_truncated; 100 std::vector<char> data_truncated = 101 PmpTestUtil::MakeHeaderAndBody(field_type, elems.size(), elems); 102 data_truncated.resize(data_truncated.size()-10); 103 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_truncated, 104 data_truncated, 105 field_type)); 106 107 PmpColumnReader reader_padded; 108 std::vector<char> data_padded = 109 PmpTestUtil::MakeHeaderAndBody(field_type, elems.size(), elems); 110 data_padded.resize(data_padded.size()+10); 111 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_padded, 112 data_padded, 113 field_type)); 114 } 115 116 template<class T> 117 void TestPrimitive(const PmpFieldType field_type) { 118 // Make an ascending vector of the primitive. 119 uint32 n = 100; 120 std::vector<T> data(n, 0); 121 for (uint32 i = 0; i < n; i++) { 122 data[i] = i*3; 123 } 124 125 TestValid<T>(field_type, data); 126 TestMalformed<T>(field_type, data); 127 } 128 129 130 TEST(PmpColumnReaderTest, HeaderParsingAndValidation) { 131 PmpColumnReader reader_good_header; 132 std::vector<char> good_header = 133 PmpTestUtil::MakeHeader(PMP_TYPE_STRING, 0); 134 EXPECT_TRUE(InitColumnReaderFromBytes(&reader_good_header, 135 good_header, 136 PMP_TYPE_STRING)); 137 EXPECT_EQ(0U, reader_good_header.rows_read()) << 138 "Read non-zero rows from header-only data."; 139 140 PmpColumnReader reader_bad_magic_bytes; 141 std::vector<char> bad_magic_bytes = 142 PmpTestUtil::MakeHeader(PMP_TYPE_STRING, 0); 143 bad_magic_bytes[0] = static_cast<char>(-128); 144 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_bad_magic_bytes, 145 bad_magic_bytes, 146 PMP_TYPE_STRING)); 147 148 PmpColumnReader reader_inconsistent_types; 149 std::vector<char> inconsistent_type = 150 PmpTestUtil::MakeHeader(PMP_TYPE_STRING, 0); 151 inconsistent_type[kPmpFieldType1Offset] = static_cast<char>(-128); 152 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_inconsistent_types, 153 inconsistent_type, 154 PMP_TYPE_STRING)); 155 156 PmpColumnReader reader_invalid_type; 157 std::vector<char> invalid_type = 158 PmpTestUtil::MakeHeader(PMP_TYPE_STRING, 0); 159 invalid_type[kPmpFieldType1Offset] = static_cast<char>(-128); 160 invalid_type[kPmpFieldType2Offset] = static_cast<char>(-128); 161 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_invalid_type, 162 invalid_type, 163 PMP_TYPE_STRING)); 164 165 PmpColumnReader reader_incomplete_header; 166 std::vector<char> incomplete_header = 167 PmpTestUtil::MakeHeader(PMP_TYPE_STRING, 0); 168 incomplete_header.resize(10); 169 EXPECT_FALSE(InitColumnReaderFromBytes(&reader_incomplete_header, 170 incomplete_header, 171 PMP_TYPE_STRING)); 172 } 173 174 TEST(PmpColumnReaderTest, StringParsing) { 175 std::vector<std::string> empty_strings(100, ""); 176 177 // Test empty strings read okay. 178 TestValid(PMP_TYPE_STRING, empty_strings); 179 180 std::vector<std::string> mixed_strings; 181 mixed_strings.push_back(""); 182 mixed_strings.push_back("Hello"); 183 mixed_strings.push_back("World"); 184 mixed_strings.push_back(""); 185 mixed_strings.push_back("123123"); 186 mixed_strings.push_back("Q"); 187 mixed_strings.push_back(""); 188 189 // Test that a mixed set of strings read correctly. 190 TestValid(PMP_TYPE_STRING, mixed_strings); 191 192 // Test with the data messed up in a variety of ways. 193 TestMalformed(PMP_TYPE_STRING, mixed_strings); 194 } 195 196 TEST(PmpColumnReaderTest, PrimitiveParsing) { 197 TestPrimitive<uint32>(PMP_TYPE_UINT32); 198 TestPrimitive<double>(PMP_TYPE_DOUBLE64); 199 TestPrimitive<uint8>(PMP_TYPE_UINT8); 200 TestPrimitive<uint64>(PMP_TYPE_UINT64); 201 } 202 203 } // namespace 204 205 } // namespace picasa 206