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. 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 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 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 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 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 93 ScopedTempFile::ScopedTempFile(const string& pattern) { 94 EXPECT_TRUE(MakeTempFile(pattern, &filename_)); 95 } 96 97 ScopedTempFile::~ScopedTempFile() { 98 if (!filename_.empty() && unlink(filename_.c_str()) < 0) { 99 perror("Unable to remove temporary file"); 100 } 101 } 102 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 134 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