xref: /aosp_15_r20/external/bsdiff/test_utils.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
1*a3a45f30SXin Li // Copyright 2015 The Chromium OS Authors. All rights reserved.
2*a3a45f30SXin Li // Use of this source code is governed by a BSD-style license that can be
3*a3a45f30SXin Li // found in the LICENSE file.
4*a3a45f30SXin Li 
5*a3a45f30SXin Li #include "bsdiff/test_utils.h"
6*a3a45f30SXin Li 
7*a3a45f30SXin Li #include <stdio.h>
8*a3a45f30SXin Li #include <stdlib.h>
9*a3a45f30SXin Li #include <string.h>
10*a3a45f30SXin Li #include <sys/stat.h>
11*a3a45f30SXin Li #include <unistd.h>
12*a3a45f30SXin Li 
13*a3a45f30SXin Li #include <gtest/gtest.h>
14*a3a45f30SXin Li 
15*a3a45f30SXin Li using std::vector;
16*a3a45f30SXin Li 
17*a3a45f30SXin Li namespace {
18*a3a45f30SXin Li 
19*a3a45f30SXin Li // If |path| is absolute, or explicit relative to the current working directory,
20*a3a45f30SXin Li // leaves it as is. Otherwise, if TMPDIR is defined in the environment and is
21*a3a45f30SXin Li // non-empty, prepends it to |path|. Otherwise, prepends /tmp.  Returns the
22*a3a45f30SXin Li // resulting path.
PrependTmpdir(const std::string & path)23*a3a45f30SXin Li const std::string PrependTmpdir(const std::string& path) {
24*a3a45f30SXin Li   if (path[0] == '/')
25*a3a45f30SXin Li     return path;
26*a3a45f30SXin Li 
27*a3a45f30SXin Li   const char* tmpdir = getenv("TMPDIR");
28*a3a45f30SXin Li   const std::string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
29*a3a45f30SXin Li   return prefix + "/" + path;
30*a3a45f30SXin Li }
31*a3a45f30SXin Li 
MakeTempFile(const std::string & base_filename_template,std::string * filename)32*a3a45f30SXin Li bool MakeTempFile(const std::string& base_filename_template,
33*a3a45f30SXin Li                   std::string* filename) {
34*a3a45f30SXin Li   const std::string filename_template = PrependTmpdir(base_filename_template);
35*a3a45f30SXin Li   vector<char> result(filename_template.size() + 1, '\0');
36*a3a45f30SXin Li   memcpy(result.data(), filename_template.data(), filename_template.size());
37*a3a45f30SXin Li 
38*a3a45f30SXin Li   int mkstemp_fd = mkstemp(result.data());
39*a3a45f30SXin Li   if (mkstemp_fd < 0) {
40*a3a45f30SXin Li     PLOG(ERROR) << "mkstemp() Failed";
41*a3a45f30SXin Li     return false;
42*a3a45f30SXin Li   }
43*a3a45f30SXin Li   close(mkstemp_fd);
44*a3a45f30SXin Li 
45*a3a45f30SXin Li   if (filename)
46*a3a45f30SXin Li     *filename = result.data();
47*a3a45f30SXin Li   return true;
48*a3a45f30SXin Li }
49*a3a45f30SXin Li 
50*a3a45f30SXin Li }  // namespace
51*a3a45f30SXin Li 
52*a3a45f30SXin Li namespace test_utils {
53*a3a45f30SXin Li 
SetUp()54*a3a45f30SXin Li void BsdiffTestEnvironment::SetUp() {
55*a3a45f30SXin Li #ifdef BSDIFF_TARGET_UNITTEST
56*a3a45f30SXin Li #define BSDIFF_TARGET_TMP_BASE "/data/local/tmp"
57*a3a45f30SXin Li   setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1);
58*a3a45f30SXin Li #endif  // defined (BSDIFF_TARGET_UNITTEST)
59*a3a45f30SXin Li }
60*a3a45f30SXin Li 
ReadFile(const std::string & path,vector<uint8_t> * out)61*a3a45f30SXin Li bool ReadFile(const std::string& path, vector<uint8_t>* out) {
62*a3a45f30SXin Li   FILE* fp = fopen(path.c_str(), "r");
63*a3a45f30SXin Li   if (!fp)
64*a3a45f30SXin Li     return false;
65*a3a45f30SXin Li   out->clear();
66*a3a45f30SXin Li 
67*a3a45f30SXin Li   uint8_t buf[16 * 1024];
68*a3a45f30SXin Li   while (true) {
69*a3a45f30SXin Li     size_t bytes_read = fread(buf, 1, sizeof(buf), fp);
70*a3a45f30SXin Li     if (!bytes_read)
71*a3a45f30SXin Li       break;
72*a3a45f30SXin Li     out->insert(out->end(), buf, buf + bytes_read);
73*a3a45f30SXin Li   }
74*a3a45f30SXin Li   bool result = !ferror(fp);
75*a3a45f30SXin Li   fclose(fp);
76*a3a45f30SXin Li   return result;
77*a3a45f30SXin Li }
78*a3a45f30SXin Li 
WriteFile(const std::string & path,vector<uint8_t> contents)79*a3a45f30SXin Li bool WriteFile(const std::string& path, vector<uint8_t> contents) {
80*a3a45f30SXin Li   FILE* fp = fopen(path.c_str(), "r");
81*a3a45f30SXin Li   if (!fp)
82*a3a45f30SXin Li     return false;
83*a3a45f30SXin Li   size_t written = fwrite(contents.data(), 1, contents.size(), fp);
84*a3a45f30SXin Li   bool result = written == contents.size() && !ferror(fp);
85*a3a45f30SXin Li   fclose(fp);
86*a3a45f30SXin Li   return result;
87*a3a45f30SXin Li }
88*a3a45f30SXin Li 
ScopedTempFile(const std::string & pattern)89*a3a45f30SXin Li ScopedTempFile::ScopedTempFile(const std::string& pattern) {
90*a3a45f30SXin Li   EXPECT_TRUE(MakeTempFile(pattern, &filename_));
91*a3a45f30SXin Li }
92*a3a45f30SXin Li 
~ScopedTempFile()93*a3a45f30SXin Li ScopedTempFile::~ScopedTempFile() {
94*a3a45f30SXin Li   if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
95*a3a45f30SXin Li     PLOG(ERROR) << "Unable to remove temporary file.";
96*a3a45f30SXin Li   }
97*a3a45f30SXin Li }
98*a3a45f30SXin Li 
LoadFromFile(const std::string & filename)99*a3a45f30SXin Li bool BsdiffPatchFile::LoadFromFile(const std::string& filename) {
100*a3a45f30SXin Li   vector<uint8_t> contents;
101*a3a45f30SXin Li   if (!ReadFile(filename, &contents))
102*a3a45f30SXin Li     return false;
103*a3a45f30SXin Li   file_size = contents.size();
104*a3a45f30SXin Li   // Check that the file includes at least the header.
105*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize);
106*a3a45f30SXin Li   magic = std::string(contents.data(), contents.data() + 8);
107*a3a45f30SXin Li   memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len));
108*a3a45f30SXin Li   memcpy(&diff_len, contents.data() + 16, sizeof(diff_len));
109*a3a45f30SXin Li   memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len));
110*a3a45f30SXin Li 
111*a3a45f30SXin Li   // Sanity check before we attempt to parse the bz2 streams.
112*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(ctrl_len >= 0);
113*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(diff_len >= 0);
114*a3a45f30SXin Li 
115*a3a45f30SXin Li   // The cast is safe since ctrl_len and diff_len are both positive.
116*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(file_size >=
117*a3a45f30SXin Li         static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len));
118*a3a45f30SXin Li   extra_len = file_size - kHeaderSize - ctrl_len - diff_len;
119*a3a45f30SXin Li 
120*a3a45f30SXin Li   uint8_t* ptr = contents.data() + kHeaderSize;
121*a3a45f30SXin Li   bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len);
122*a3a45f30SXin Li   ptr += ctrl_len;
123*a3a45f30SXin Li   bz2_diff = vector<uint8_t>(ptr, ptr + diff_len);
124*a3a45f30SXin Li   ptr += diff_len;
125*a3a45f30SXin Li   bz2_extra = vector<uint8_t>(ptr, ptr + extra_len);
126*a3a45f30SXin Li 
127*a3a45f30SXin Li   return true;
128*a3a45f30SXin Li }
129*a3a45f30SXin Li 
IsValid() const130*a3a45f30SXin Li bool BsdiffPatchFile::IsValid() const {
131*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(ctrl_len >= 0);
132*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(diff_len >= 0);
133*a3a45f30SXin Li   TEST_AND_RETURN_FALSE(new_file_len >= 0);
134*a3a45f30SXin Li 
135*a3a45f30SXin Li   // TODO(deymo): Test that the length of the decompressed bz2 streams |diff|
136*a3a45f30SXin Li   // plus |extra| are equal to the |new_file_len|.
137*a3a45f30SXin Li   // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x"
138*a3a45f30SXin Li   // and "y" value >= 0 ("z" can be negative).
139*a3a45f30SXin Li   return true;
140*a3a45f30SXin Li }
141*a3a45f30SXin Li 
142*a3a45f30SXin Li }  // namespace test_utils
143