1 // Copyright 2015 The Chromium OS 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 "test_utils.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12
13 #include <gtest/gtest.h>
14 #include <vector>
15
16 using std::string;
17 using std::vector;
18
19 namespace {
20
21 // If |path| is absolute, or explicit relative to the current working directory,
22 // leaves it as is. Otherwise, if TMPDIR is defined in the environment and is
23 // non-empty, prepends it to |path|. Otherwise, prepends /tmp. Returns the
24 // resulting path.
PrependTmpdir(const string & path)25 const string PrependTmpdir(const string& path) {
26 if (path[0] == '/')
27 return path;
28
29 const char* tmpdir = getenv("TMPDIR");
30 const string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
31 return prefix + "/" + path;
32 }
33
MakeTempFile(const string & base_filename_template,string * filename)34 bool MakeTempFile(const string& base_filename_template, string* filename) {
35 const string filename_template = PrependTmpdir(base_filename_template);
36 vector<char> result(filename_template.size() + 1, '\0');
37 memcpy(result.data(), filename_template.data(), filename_template.size());
38
39 int mkstemp_fd = mkstemp(result.data());
40 if (mkstemp_fd < 0) {
41 perror("mkstemp()");
42 return false;
43 }
44 close(mkstemp_fd);
45
46 if (filename)
47 *filename = result.data();
48 return true;
49 }
50
51 } // namespace
52
53 namespace test_utils {
54
SetUp()55 void BsdiffTestEnvironment::SetUp() {
56 #ifdef BSDIFF_TARGET_UNITTEST
57 #define BSDIFF_TARGET_TMP_BASE "/data/tmp"
58 if (access(BSDIFF_TARGET_TMP_BASE, F_OK) == -1) {
59 mkdir(BSDIFF_TARGET_TMP_BASE, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
60 }
61 setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1);
62 #endif // defined (BSDIFF_TARGET_UNITTEST)
63 }
64
ReadFile(const string & path,vector<uint8_t> * out)65 bool ReadFile(const string& path, vector<uint8_t>* out) {
66 FILE* fp = fopen(path.c_str(), "r");
67 if (!fp)
68 return false;
69 out->clear();
70
71 uint8_t buf[16 * 1024];
72 while (true) {
73 size_t bytes_read = fread(buf, 1, sizeof(buf), fp);
74 if (!bytes_read)
75 break;
76 out->insert(out->end(), buf, buf + bytes_read);
77 }
78 bool result = !ferror(fp);
79 fclose(fp);
80 return result;
81 }
82
WriteFile(const string & path,vector<uint8_t> contents)83 bool WriteFile(const string& path, vector<uint8_t> contents) {
84 FILE* fp = fopen(path.c_str(), "r");
85 if (!fp)
86 return false;
87 size_t written = fwrite(contents.data(), 1, contents.size(), fp);
88 bool result = written == contents.size() && !ferror(fp);
89 fclose(fp);
90 return result;
91 }
92
ScopedTempFile(const string & pattern)93 ScopedTempFile::ScopedTempFile(const string& pattern) {
94 EXPECT_TRUE(MakeTempFile(pattern, &filename_));
95 }
96
~ScopedTempFile()97 ScopedTempFile::~ScopedTempFile() {
98 if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
99 perror("Unable to remove temporary file");
100 }
101 }
102
LoadFromFile(const string & filename)103 bool BsdiffPatchFile::LoadFromFile(const string& filename) {
104 vector<uint8_t> contents;
105 if (!ReadFile(filename, &contents))
106 return false;
107 file_size = contents.size();
108 // Check that the file includes at least the header.
109 TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize);
110 magic = string(contents.data(), contents.data() + 8);
111 memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len));
112 memcpy(&diff_len, contents.data() + 16, sizeof(diff_len));
113 memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len));
114
115 // Sanity check before we attempt to parse the bz2 streams.
116 TEST_AND_RETURN_FALSE(ctrl_len >= 0);
117 TEST_AND_RETURN_FALSE(diff_len >= 0);
118
119 // The cast is safe since ctrl_len and diff_len are both positive.
120 TEST_AND_RETURN_FALSE(file_size >=
121 static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len));
122 extra_len = file_size - kHeaderSize - ctrl_len - diff_len;
123
124 uint8_t* ptr = contents.data() + kHeaderSize;
125 bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len);
126 ptr += ctrl_len;
127 bz2_diff = vector<uint8_t>(ptr, ptr + diff_len);
128 ptr += diff_len;
129 bz2_extra = vector<uint8_t>(ptr, ptr + extra_len);
130
131 return true;
132 }
133
IsValid() const134 bool BsdiffPatchFile::IsValid() const {
135 TEST_AND_RETURN_FALSE(ctrl_len >= 0);
136 TEST_AND_RETURN_FALSE(diff_len >= 0);
137 TEST_AND_RETURN_FALSE(new_file_len >= 0);
138
139 // TODO(deymo): Test that the length of the decompressed bz2 streams |diff|
140 // plus |extra| are equal to the |new_file_len|.
141 // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x"
142 // and "y" value >= 0 ("z" can be negative).
143 return true;
144 }
145
146 } // namespace test_utils
147