blob: eb079d57d44054ac1bd70d4387b4f06e60a71fd1 [file] [log] [blame]
Alex Deymoa5cff222015-04-08 14:10:30 -07001// 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
Alex Deymodcd423b2017-09-13 20:54:24 +02005#include "bsdiff/test_utils.h"
Alex Deymoa5cff222015-04-08 14:10:30 -07006
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
Jed Estep9abc2042016-02-19 11:12:14 -080010#include <sys/stat.h>
Alex Deymoa5cff222015-04-08 14:10:30 -070011#include <unistd.h>
12
13#include <gtest/gtest.h>
Alex Deymoa5cff222015-04-08 14:10:30 -070014
Alex Deymoa5cff222015-04-08 14:10:30 -070015using std::vector;
16
17namespace {
18
19// If |path| is absolute, or explicit relative to the current working directory,
20// leaves it as is. Otherwise, if TMPDIR is defined in the environment and is
21// non-empty, prepends it to |path|. Otherwise, prepends /tmp. Returns the
22// resulting path.
Alex Deymoc0461f02017-09-22 15:05:42 +020023const std::string PrependTmpdir(const std::string& path) {
Alex Deymoa5cff222015-04-08 14:10:30 -070024 if (path[0] == '/')
25 return path;
26
Alex Deymoe1526cf2015-10-12 17:48:28 -070027 const char* tmpdir = getenv("TMPDIR");
Alex Deymoc0461f02017-09-22 15:05:42 +020028 const std::string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
Alex Deymoa5cff222015-04-08 14:10:30 -070029 return prefix + "/" + path;
30}
31
Alex Deymoc0461f02017-09-22 15:05:42 +020032bool MakeTempFile(const std::string& base_filename_template,
33 std::string* filename) {
34 const std::string filename_template = PrependTmpdir(base_filename_template);
Alex Deymoa5cff222015-04-08 14:10:30 -070035 vector<char> result(filename_template.size() + 1, '\0');
36 memcpy(result.data(), filename_template.data(), filename_template.size());
37
38 int mkstemp_fd = mkstemp(result.data());
39 if (mkstemp_fd < 0) {
Amin Hassani1106bf72017-11-15 17:26:03 -080040 PLOG(ERROR) << "mkstemp() Failed";
Alex Deymoa5cff222015-04-08 14:10:30 -070041 return false;
42 }
43 close(mkstemp_fd);
44
45 if (filename)
46 *filename = result.data();
47 return true;
48}
49
50} // namespace
51
52namespace test_utils {
53
Jed Estep9abc2042016-02-19 11:12:14 -080054void BsdiffTestEnvironment::SetUp() {
55#ifdef BSDIFF_TARGET_UNITTEST
56#define BSDIFF_TARGET_TMP_BASE "/data/tmp"
57 if (access(BSDIFF_TARGET_TMP_BASE, F_OK) == -1) {
58 mkdir(BSDIFF_TARGET_TMP_BASE, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
59 }
60 setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1);
Alex Deymoc0461f02017-09-22 15:05:42 +020061#endif // defined (BSDIFF_TARGET_UNITTEST)
Jed Estep9abc2042016-02-19 11:12:14 -080062}
63
Alex Deymoc0461f02017-09-22 15:05:42 +020064bool ReadFile(const std::string& path, vector<uint8_t>* out) {
Alex Deymoa5cff222015-04-08 14:10:30 -070065 FILE* fp = fopen(path.c_str(), "r");
66 if (!fp)
67 return false;
68 out->clear();
69
70 uint8_t buf[16 * 1024];
71 while (true) {
72 size_t bytes_read = fread(buf, 1, sizeof(buf), fp);
73 if (!bytes_read)
74 break;
75 out->insert(out->end(), buf, buf + bytes_read);
76 }
77 bool result = !ferror(fp);
78 fclose(fp);
79 return result;
80}
81
Alex Deymoc0461f02017-09-22 15:05:42 +020082bool WriteFile(const std::string& path, vector<uint8_t> contents) {
Alex Deymoa5cff222015-04-08 14:10:30 -070083 FILE* fp = fopen(path.c_str(), "r");
84 if (!fp)
85 return false;
86 size_t written = fwrite(contents.data(), 1, contents.size(), fp);
87 bool result = written == contents.size() && !ferror(fp);
88 fclose(fp);
89 return result;
90}
91
Alex Deymoc0461f02017-09-22 15:05:42 +020092ScopedTempFile::ScopedTempFile(const std::string& pattern) {
Alex Deymoa5cff222015-04-08 14:10:30 -070093 EXPECT_TRUE(MakeTempFile(pattern, &filename_));
94}
95
96ScopedTempFile::~ScopedTempFile() {
97 if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
Amin Hassani1106bf72017-11-15 17:26:03 -080098 PLOG(ERROR) << "Unable to remove temporary file.";
Alex Deymoa5cff222015-04-08 14:10:30 -070099 }
100}
101
Alex Deymoc0461f02017-09-22 15:05:42 +0200102bool BsdiffPatchFile::LoadFromFile(const std::string& filename) {
Alex Deymoa5cff222015-04-08 14:10:30 -0700103 vector<uint8_t> contents;
104 if (!ReadFile(filename, &contents))
105 return false;
106 file_size = contents.size();
107 // Check that the file includes at least the header.
108 TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize);
Alex Deymoc0461f02017-09-22 15:05:42 +0200109 magic = std::string(contents.data(), contents.data() + 8);
Alex Deymoa5cff222015-04-08 14:10:30 -0700110 memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len));
111 memcpy(&diff_len, contents.data() + 16, sizeof(diff_len));
112 memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len));
113
Alex Deymoa5cff222015-04-08 14:10:30 -0700114 // Sanity check before we attempt to parse the bz2 streams.
115 TEST_AND_RETURN_FALSE(ctrl_len >= 0);
116 TEST_AND_RETURN_FALSE(diff_len >= 0);
117
Jed Estep9abc2042016-02-19 11:12:14 -0800118 // The cast is safe since ctrl_len and diff_len are both positive.
119 TEST_AND_RETURN_FALSE(file_size >=
120 static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len));
121 extra_len = file_size - kHeaderSize - ctrl_len - diff_len;
122
Alex Deymoa5cff222015-04-08 14:10:30 -0700123 uint8_t* ptr = contents.data() + kHeaderSize;
124 bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len);
125 ptr += ctrl_len;
126 bz2_diff = vector<uint8_t>(ptr, ptr + diff_len);
127 ptr += diff_len;
128 bz2_extra = vector<uint8_t>(ptr, ptr + extra_len);
129
130 return true;
131}
132
133bool BsdiffPatchFile::IsValid() const {
134 TEST_AND_RETURN_FALSE(ctrl_len >= 0);
135 TEST_AND_RETURN_FALSE(diff_len >= 0);
136 TEST_AND_RETURN_FALSE(new_file_len >= 0);
137
138 // TODO(deymo): Test that the length of the decompressed bz2 streams |diff|
139 // plus |extra| are equal to the |new_file_len|.
140 // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x"
141 // and "y" value >= 0 ("z" can be negative).
142 return true;
143}
144
145} // namespace test_utils