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 
15 using std::string;
16 using std::vector;
17 
18 namespace {
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.
PrependTmpdir(const string & path)24 const 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 
MakeTempFile(const string & base_filename_template,string * filename)33 bool 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 
52 namespace test_utils {
53 
ReadFile(const string & path,vector<uint8_t> * out)54 bool 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 
WriteFile(const string & path,vector<uint8_t> contents)72 bool 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 
ScopedTempFile(const string & pattern)82 ScopedTempFile::ScopedTempFile(const string& pattern) {
83   EXPECT_TRUE(MakeTempFile(pattern, &filename_));
84 }
85 
~ScopedTempFile()86 ScopedTempFile::~ScopedTempFile() {
87   if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
88     perror("Unable to remove temporary file");
89   }
90 }
91 
LoadFromFile(const string & filename)92 bool 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 
IsValid() const121 bool 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