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