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 "chrome/common/media_galleries/pmp_test_util.h"
6
7#include <algorithm>
8#include <iterator>
9
10#include "base/file_util.h"
11#include "base/logging.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/common/media_galleries/picasa_types.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace picasa {
17
18namespace {
19
20// Flatten a vector of elements into an array of bytes.
21template<class T>
22std::vector<char> Flatten(const std::vector<T>& elems) {
23  if (elems.empty())
24    return std::vector<char>();
25
26  const uint8* elems0 = reinterpret_cast<const uint8*>(&elems[0]);
27  std::vector<char> data_body(elems0, elems0 + sizeof(T) * elems.size());
28  return data_body;
29}
30
31// Custom specialization for std::string.
32template<>
33std::vector<char> Flatten(const std::vector<std::string>& strings) {
34  std::vector<char> totalchars;
35
36  for (std::vector<std::string>::const_iterator it = strings.begin();
37      it != strings.end(); ++it) {
38    std::copy(it->begin(), it->end(), std::back_inserter(totalchars));
39    totalchars.push_back('\0');  // Add the null termination too.
40  }
41
42  return totalchars;
43}
44
45// Returns a new vector with the concatenated contents of |a| and |b|.
46std::vector<char> CombinedVectors(const std::vector<char>& a,
47                                  const std::vector<char>& b) {
48  std::vector<char> total;
49
50  std::copy(a.begin(), a.end(), std::back_inserter(total));
51  std::copy(b.begin(), b.end(), std::back_inserter(total));
52
53  return total;
54}
55
56}  // namespace
57
58bool PmpTestUtil::WriteIndicatorFile(
59    const base::FilePath& column_file_destination,
60    const std::string& table_name) {
61  base::FilePath indicator_path = column_file_destination.Append(
62      base::FilePath::FromUTF8Unsafe(table_name + "_0"));
63
64  return base::WriteFile(indicator_path, NULL, 0) == 0;
65}
66
67template<class T>
68bool PmpTestUtil::WriteColumnFileFromVector(
69    const base::FilePath& column_file_destination,
70    const std::string& table_name,
71    const std::string& column_name,
72    const PmpFieldType field_type,
73    const std::vector<T>& elements_vector) {
74  std::string file_name = table_name + "_" + column_name + "." + kPmpExtension;
75
76  base::FilePath path = column_file_destination.AppendASCII(file_name);
77
78  std::vector<char> data = PmpTestUtil::MakeHeaderAndBody(
79      field_type, elements_vector.size(), elements_vector);
80
81  size_t bytes_written = base::WriteFile(path, &data[0], data.size());
82  return (bytes_written == data.size());
83}
84
85// Explicit Instantiation for all the valid types.
86template bool PmpTestUtil::WriteColumnFileFromVector<std::string>(
87    const base::FilePath&, const std::string&, const std::string&,
88    const PmpFieldType, const std::vector<std::string>&);
89template bool PmpTestUtil::WriteColumnFileFromVector<uint32>(
90    const base::FilePath&, const std::string&, const std::string&,
91    const PmpFieldType, const std::vector<uint32>&);
92template bool PmpTestUtil::WriteColumnFileFromVector<double>(
93    const base::FilePath&, const std::string&, const std::string&,
94    const PmpFieldType, const std::vector<double>&);
95template bool PmpTestUtil::WriteColumnFileFromVector<uint8>(
96    const base::FilePath&, const std::string&, const std::string&,
97    const PmpFieldType, const std::vector<uint8>&);
98template bool PmpTestUtil::WriteColumnFileFromVector<uint64>(
99    const base::FilePath&, const std::string&, const std::string&,
100    const PmpFieldType, const std::vector<uint64>&);
101
102// Return a vector so we don't have to worry about memory management.
103std::vector<char> PmpTestUtil::MakeHeader(const PmpFieldType field_type,
104                                            const uint32 row_count) {
105  std::vector<char> header(picasa::kPmpHeaderSize);
106
107  // Copy in magic bytes.
108  memcpy(&header[picasa::kPmpMagic1Offset], &picasa::kPmpMagic1,
109         sizeof(picasa::kPmpMagic1));
110  memcpy(&header[picasa::kPmpMagic2Offset], &picasa::kPmpMagic2,
111         sizeof(picasa::kPmpMagic2));
112  memcpy(&header[picasa::kPmpMagic3Offset], &picasa::kPmpMagic3,
113         sizeof(picasa::kPmpMagic3));
114  memcpy(&header[picasa::kPmpMagic4Offset], &picasa::kPmpMagic4,
115         sizeof(picasa::kPmpMagic4));
116
117  // Copy in field type.
118  uint16 field_type_short = static_cast<uint16>(field_type);
119  memcpy(&header[picasa::kPmpFieldType1Offset], &field_type_short,
120         sizeof(uint16));
121  memcpy(&header[picasa::kPmpFieldType2Offset], &field_type_short,
122         sizeof(uint16));
123
124  // Copy in row count.
125  memcpy(&header[picasa::kPmpRowCountOffset], &row_count, sizeof(uint32));
126
127  return header;
128}
129
130template<class T>
131std::vector<char> PmpTestUtil::MakeHeaderAndBody(
132    const PmpFieldType field_type, const uint32 row_count,
133    const std::vector<T>& elems) {
134  return CombinedVectors(PmpTestUtil::MakeHeader(field_type, row_count),
135                         Flatten(elems));
136}
137
138// Explicit Instantiation for all the valid types.
139template std::vector<char> PmpTestUtil::MakeHeaderAndBody<std::string>(
140    const PmpFieldType, const uint32, const std::vector<std::string>&);
141template std::vector<char> PmpTestUtil::MakeHeaderAndBody<uint32>(
142    const PmpFieldType, const uint32, const std::vector<uint32>&);
143template std::vector<char> PmpTestUtil::MakeHeaderAndBody<double>(
144    const PmpFieldType, const uint32, const std::vector<double>&);
145template std::vector<char> PmpTestUtil::MakeHeaderAndBody<uint8>(
146    const PmpFieldType, const uint32, const std::vector<uint8>&);
147template std::vector<char> PmpTestUtil::MakeHeaderAndBody<uint64>(
148    const PmpFieldType, const uint32, const std::vector<uint64>&);
149
150}  // namespace picasa
151