xref: /aosp_15_r20/external/bsdiff/test_utils.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
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 "bsdiff/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 
15 using std::vector;
16 
17 namespace {
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.
PrependTmpdir(const std::string & path)23 const std::string PrependTmpdir(const std::string& path) {
24   if (path[0] == '/')
25     return path;
26 
27   const char* tmpdir = getenv("TMPDIR");
28   const std::string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
29   return prefix + "/" + path;
30 }
31 
MakeTempFile(const std::string & base_filename_template,std::string * filename)32 bool MakeTempFile(const std::string& base_filename_template,
33                   std::string* filename) {
34   const std::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     PLOG(ERROR) << "mkstemp() Failed";
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 
SetUp()54 void BsdiffTestEnvironment::SetUp() {
55 #ifdef BSDIFF_TARGET_UNITTEST
56 #define BSDIFF_TARGET_TMP_BASE "/data/local/tmp"
57   setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1);
58 #endif  // defined (BSDIFF_TARGET_UNITTEST)
59 }
60 
ReadFile(const std::string & path,vector<uint8_t> * out)61 bool ReadFile(const std::string& path, vector<uint8_t>* out) {
62   FILE* fp = fopen(path.c_str(), "r");
63   if (!fp)
64     return false;
65   out->clear();
66 
67   uint8_t buf[16 * 1024];
68   while (true) {
69     size_t bytes_read = fread(buf, 1, sizeof(buf), fp);
70     if (!bytes_read)
71       break;
72     out->insert(out->end(), buf, buf + bytes_read);
73   }
74   bool result = !ferror(fp);
75   fclose(fp);
76   return result;
77 }
78 
WriteFile(const std::string & path,vector<uint8_t> contents)79 bool WriteFile(const std::string& path, vector<uint8_t> contents) {
80   FILE* fp = fopen(path.c_str(), "r");
81   if (!fp)
82     return false;
83   size_t written = fwrite(contents.data(), 1, contents.size(), fp);
84   bool result = written == contents.size() && !ferror(fp);
85   fclose(fp);
86   return result;
87 }
88 
ScopedTempFile(const std::string & pattern)89 ScopedTempFile::ScopedTempFile(const std::string& pattern) {
90   EXPECT_TRUE(MakeTempFile(pattern, &filename_));
91 }
92 
~ScopedTempFile()93 ScopedTempFile::~ScopedTempFile() {
94   if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
95     PLOG(ERROR) << "Unable to remove temporary file.";
96   }
97 }
98 
LoadFromFile(const std::string & filename)99 bool BsdiffPatchFile::LoadFromFile(const std::string& filename) {
100   vector<uint8_t> contents;
101   if (!ReadFile(filename, &contents))
102     return false;
103   file_size = contents.size();
104   // Check that the file includes at least the header.
105   TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize);
106   magic = std::string(contents.data(), contents.data() + 8);
107   memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len));
108   memcpy(&diff_len, contents.data() + 16, sizeof(diff_len));
109   memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len));
110 
111   // Sanity check before we attempt to parse the bz2 streams.
112   TEST_AND_RETURN_FALSE(ctrl_len >= 0);
113   TEST_AND_RETURN_FALSE(diff_len >= 0);
114 
115   // The cast is safe since ctrl_len and diff_len are both positive.
116   TEST_AND_RETURN_FALSE(file_size >=
117         static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len));
118   extra_len = file_size - kHeaderSize - ctrl_len - diff_len;
119 
120   uint8_t* ptr = contents.data() + kHeaderSize;
121   bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len);
122   ptr += ctrl_len;
123   bz2_diff = vector<uint8_t>(ptr, ptr + diff_len);
124   ptr += diff_len;
125   bz2_extra = vector<uint8_t>(ptr, ptr + extra_len);
126 
127   return true;
128 }
129 
IsValid() const130 bool BsdiffPatchFile::IsValid() const {
131   TEST_AND_RETURN_FALSE(ctrl_len >= 0);
132   TEST_AND_RETURN_FALSE(diff_len >= 0);
133   TEST_AND_RETURN_FALSE(new_file_len >= 0);
134 
135   // TODO(deymo): Test that the length of the decompressed bz2 streams |diff|
136   // plus |extra| are equal to the |new_file_len|.
137   // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x"
138   // and "y" value >= 0 ("z" can be negative).
139   return true;
140 }
141 
142 }  // namespace test_utils
143