1/*
2 * Copyright 2011 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <vector>
18#include <algorithm>
19
20#include "gtest/gtest.h"
21#include "sfntly/port/type.h"
22#include "sfntly/data/writable_font_data.h"
23#include "sfntly/data/memory_byte_array.h"
24
25namespace sfntly {
26
27const int32_t BYTE_ARRAY_SIZES[] =
28  {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000};
29
30// array data for searching
31const int32_t LOWER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 4, 7, 13, 127};
32const int32_t UPPER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 5, 12, 16, 256};
33const int32_t kLowerByteArrayForSearchingLength = 5;
34const int32_t kUpperByteArrayForSearchingLength = 5;
35
36// search test result pairs - number to search for; index found at
37const int32_t SEARCH_TEST_PAIRS[][2] = {
38  {0, -1}, {1, -1}, {2, 0}, {3, -1}, {4, 1}, {5, 1}, {6, -1}, {12, 2},
39  {13, 3}, {17, -1}, {126, -1}, {127, 4}, {256, 4}, {257, -1}, {0x1000, -1}
40};
41const int32_t kSearchTestPairsLength = 15;
42
43// offset and start index data for searching data
44// array data size, lower_start_index, lower_offset, upper_start_index,
45// upper_offset
46const int32_t SEARCH_TEST_OFFSETS[][5] = {
47  // lower[], upper[]
48  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
49    * DataSize::kUSHORT,
50    0,
51    DataSize::kUSHORT,
52    kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
53    DataSize::kUSHORT },
54
55  // {lower, upper} []
56  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
57    * DataSize::kUSHORT,
58    0,
59    2 * DataSize::kUSHORT,
60    DataSize::kUSHORT,
61    2 * DataSize::kUSHORT },
62
63  // upper[], lower[]
64  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
65    * DataSize::kUSHORT,
66    kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
67    DataSize::kUSHORT,
68    0,
69    DataSize::kUSHORT },
70
71  // {upper, lower} []
72  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
73    * DataSize::kUSHORT,
74    DataSize::kUSHORT,
75    2 * DataSize::kUSHORT,
76    0,
77    2 * DataSize::kUSHORT }
78};
79const int32_t kSearchTestOffsetLength = 4;
80
81ReadableFontData*
82FillTestFontDataWithShortsForSearching(WritableFontData* wfd,
83                                       const int32_t* lower_data,
84                                       int32_t lower_start_index,
85                                       int32_t lower_offset,
86                                       const int32_t* upper_data,
87                                       int32_t upper_start_index,
88                                       int32_t upper_offset) {
89  // lower data
90  int offset = lower_start_index;
91  for (int32_t i = 0; i < kLowerByteArrayForSearchingLength; ++i) {
92    wfd->WriteUShort(offset, lower_data[i]);
93    offset += lower_offset;
94  }
95
96  // upper data
97  offset = upper_start_index;
98  for (int32_t i = 0; i < kUpperByteArrayForSearchingLength; ++i) {
99    wfd->WriteUShort(offset, upper_data[i]);
100    offset += upper_offset;
101  }
102
103  return wfd;
104}
105
106bool TestReadableFontDataSearching() {
107  for (int32_t i = 0; i < kSearchTestOffsetLength; ++i) {
108    const int32_t* array_setup_offset = SEARCH_TEST_OFFSETS[i];
109    WritableFontDataPtr wfd;
110    wfd.Attach(WritableFontData::CreateWritableFontData(array_setup_offset[0]));
111    FillTestFontDataWithShortsForSearching(wfd,
112                                           LOWER_BYTE_ARRAY_FOR_SEARCHING,
113                                           array_setup_offset[1],
114                                           array_setup_offset[2],
115                                           UPPER_BYTE_ARRAY_FOR_SEARCHING,
116                                           array_setup_offset[3],
117                                           array_setup_offset[4]);
118    for (int32_t j = 0; j < kSearchTestPairsLength; ++j) {
119      const int32_t* test_case = SEARCH_TEST_PAIRS[j];
120      int32_t found = wfd->SearchUShort(array_setup_offset[1],
121                                        array_setup_offset[2],
122                                        array_setup_offset[3],
123                                        array_setup_offset[4],
124                                        kLowerByteArrayForSearchingLength,
125                                        test_case[0]);
126#if defined (SFNTLY_DEBUG_FONTDATA)
127      fprintf(stderr, "Searching for %d; Got %d; Expected %d; "
128              "[test %d][offset %d]\n",
129              test_case[0], found, test_case[1], j, i);
130#endif
131      EXPECT_EQ(test_case[1], found);
132    }
133  }
134  return true;
135}
136
137void FillTestByteArray(ByteArray* ba, int32_t size) {
138  for (int32_t i = 0; i < size; ++i) {
139    ba->Put(i, (byte_t)(i % 256));
140  }
141}
142
143void ReadFontDataWithSingleByte(ReadableFontData* rfd, ByteVector* buffer) {
144  buffer->resize(rfd->Length());
145  for (int32_t index = 0; index < rfd->Length(); ++index) {
146    (*buffer)[index] = (byte_t)(rfd->ReadByte(index));
147  }
148}
149
150void ReadFontDataWithBuffer(ReadableFontData* rfd,
151                            int32_t buffer_size,
152                            ByteVector* b) {
153  ByteVector buffer(buffer_size);
154  b->resize(rfd->Length());
155
156  int32_t index = 0;
157  while (index < rfd->Length()) {
158    int32_t bytes_read = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
159    EXPECT_GE(bytes_read, 0);
160    std::copy(buffer.begin(), buffer.begin() + bytes_read, b->begin() + index);
161    index += bytes_read;
162  }
163}
164
165void ReadFontDataWithSlidingWindow(ReadableFontData* rfd, int32_t window_size,
166                                   ByteVector* b) {
167  b->resize(rfd->Length());
168  int32_t index = 0;
169  while (index < rfd->Length()) {
170    int32_t actual_window_size =
171        std::min<int32_t>(window_size, b->size() - index);
172    int32_t bytes_read =
173        rfd->ReadBytes(index, &((*b)[0]), index, actual_window_size);
174    EXPECT_GE(bytes_read, 0);
175    index += bytes_read;
176  }
177}
178
179void WriteFontDataWithSingleByte(ReadableFontData* rfd, WritableFontData* wfd) {
180  for (int32_t index = 0; index < rfd->Length(); ++index) {
181    byte_t b = (byte_t)(rfd->ReadByte(index));
182    wfd->WriteByte(index, b);
183  }
184}
185
186void WriteFontDataWithBuffer(ReadableFontData* rfd,
187                             WritableFontData* wfd,
188                             int32_t buffer_size) {
189  ByteVector buffer(buffer_size);
190  int32_t index = 0;
191  while (index < rfd->Length()) {
192    int32_t bytesRead = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
193    wfd->WriteBytes(index, &(buffer[0]), 0, buffer.size());
194    index += bytesRead;
195  }
196}
197
198void WriteFontDataWithSlidingWindow(ReadableFontData* rfd,
199                                    WritableFontData* wfd,
200                                    int32_t window_size) {
201  ByteVector b(rfd->Length());
202  int32_t index = 0;
203  while (index < rfd->Length()) {
204    int32_t sliding_size = std::min<int32_t>(window_size, b.size() - index);
205    int32_t bytes_read = rfd->ReadBytes(index, &(b[0]), index, sliding_size);
206    wfd->WriteBytes(index, &(b[0]), index, sliding_size);
207    index += bytes_read;
208  }
209}
210
211bool ReadComparison(int32_t offset,
212                    int32_t length,
213                    ReadableFontData* rfd1,
214                    ReadableFontData* rfd2) {
215  EXPECT_TRUE(length == rfd2->Length());
216  ByteVector b1, b2;
217  b1.resize(length);
218  b2.resize(length);
219
220  // single byte reads
221  ReadFontDataWithSingleByte(rfd1, &b1);
222  ReadFontDataWithSingleByte(rfd2, &b2);
223  EXPECT_EQ(memcmp(&(b1[offset]), &(b2[0]), length), 0);
224
225  // buffer reads
226  int32_t increments = std::max<int32_t>(length / 11, 1);
227  for (int32_t buffer_size = 1; buffer_size <= length;
228       buffer_size += increments) {
229    b1.clear();
230    b2.clear();
231    b1.resize(length);
232    b2.resize(length);
233    ReadFontDataWithBuffer(rfd1, buffer_size, &b1);
234    ReadFontDataWithBuffer(rfd2, buffer_size, &b2);
235    int result = memcmp(&(b1[offset]), &(b2[0]), length);
236    EXPECT_EQ(result, 0);
237  }
238
239  // sliding window reads
240  for (int32_t window_size = 1; window_size <= length;
241       window_size += increments) {
242    b1.clear();
243    b2.clear();
244    b1.resize(length);
245    b2.resize(length);
246    ReadFontDataWithSlidingWindow(rfd1, window_size, &b1);
247    ReadFontDataWithSlidingWindow(rfd2, window_size, &b2);
248    int result = memcmp(&(b1[offset]), &(b2[0]), length);
249    EXPECT_EQ(result, 0);
250  }
251  return true;
252}
253
254void SlicingReadTest(ReadableFontData* rfd) {
255  fprintf(stderr, "read - trim = ");
256  for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
257       trim += (rfd->Length() / 21) + 1) {
258    fprintf(stderr, "%d ", trim);
259    int32_t length = rfd->Length() - 2 * trim;
260    ReadableFontDataPtr slice;
261    slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
262    EXPECT_TRUE(ReadComparison(trim, length, rfd, slice));
263  }
264  fprintf(stderr, "\n");
265}
266
267void SlicingWriteTest(ReadableFontData* rfd, WritableFontData* wfd) {
268  fprintf(stderr, "write - trim = ");
269  for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
270       trim += (rfd->Length() / 21) + 1) {
271    fprintf(stderr, "%d ", trim);
272    int32_t length = rfd->Length() - 2 * trim;
273    WritableFontDataPtr w_slice;
274    ReadableFontDataPtr r_slice;
275
276    // single byte writes
277    w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
278    r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
279    WriteFontDataWithSingleByte(r_slice, w_slice);
280    EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
281
282    // buffer writes
283    int32_t increments = std::max<int32_t>(length / 11, 1);
284    for (int32_t buffer_size = 1; buffer_size < length;
285         buffer_size += increments) {
286      w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
287      r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
288      WriteFontDataWithBuffer(r_slice, w_slice, buffer_size);
289      EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
290    }
291
292    // sliding window writes
293    for (int window_size = 1; window_size < length; window_size += increments) {
294      w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
295      r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
296      WriteFontDataWithSlidingWindow(r_slice, w_slice, window_size);
297      EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
298    }
299  }
300  fprintf(stderr, "\n");
301}
302
303bool TestReadableFontData() {
304  for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
305    int32_t size = BYTE_ARRAY_SIZES[i];
306    ByteArrayPtr ba = new MemoryByteArray(size);
307    FillTestByteArray(ba, size);
308    ReadableFontDataPtr rfd = new ReadableFontData(ba);
309    SlicingReadTest(rfd);
310  }
311  return true;
312}
313
314bool TestWritableFontData() {
315  for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
316    int32_t size = BYTE_ARRAY_SIZES[i];
317    ByteArrayPtr ba = new MemoryByteArray(size);
318    FillTestByteArray(ba, size);
319    WritableFontDataPtr wfd = new WritableFontData(ba);
320    SlicingReadTest(wfd);
321    ByteArrayPtr temp = new MemoryByteArray(size);
322    WritableFontDataPtr wfd_copy = new WritableFontData(temp);
323    SlicingWriteTest(wfd, wfd_copy);
324  }
325  return true;
326}
327
328}  // namespace sfntly
329
330TEST(FontData, ReadableFontDataSearching) {
331  ASSERT_TRUE(sfntly::TestReadableFontDataSearching());
332}
333
334TEST(FontData, All) {
335  ASSERT_TRUE(sfntly::TestReadableFontData());
336  ASSERT_TRUE(sfntly::TestWritableFontData());
337}
338