summaryrefslogtreecommitdiff
path: root/test_utils.cc
blob: c1350eb72a72db8271029cce3f6c1bfd355c3322 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "bsdiff/test_utils.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include <gtest/gtest.h>

using std::vector;

namespace {

// If |path| is absolute, or explicit relative to the current working directory,
// leaves it as is. Otherwise, if TMPDIR is defined in the environment and is
// non-empty, prepends it to |path|. Otherwise, prepends /tmp.  Returns the
// resulting path.
const std::string PrependTmpdir(const std::string& path) {
  if (path[0] == '/')
    return path;

  const char* tmpdir = getenv("TMPDIR");
  const std::string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
  return prefix + "/" + path;
}

bool MakeTempFile(const std::string& base_filename_template,
                  std::string* filename) {
  const std::string filename_template = PrependTmpdir(base_filename_template);
  vector<char> result(filename_template.size() + 1, '\0');
  memcpy(result.data(), filename_template.data(), filename_template.size());

  int mkstemp_fd = mkstemp(result.data());
  if (mkstemp_fd < 0) {
    PLOG(ERROR) << "mkstemp() Failed";
    return false;
  }
  close(mkstemp_fd);

  if (filename)
    *filename = result.data();
  return true;
}

}  // namespace

namespace test_utils {

void BsdiffTestEnvironment::SetUp() {
#ifdef BSDIFF_TARGET_UNITTEST
#define BSDIFF_TARGET_TMP_BASE "/data/local/tmp"
  setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1);
#endif  // defined (BSDIFF_TARGET_UNITTEST)
}

bool ReadFile(const std::string& path, vector<uint8_t>* out) {
  FILE* fp = fopen(path.c_str(), "r");
  if (!fp)
    return false;
  out->clear();

  uint8_t buf[16 * 1024];
  while (true) {
    size_t bytes_read = fread(buf, 1, sizeof(buf), fp);
    if (!bytes_read)
      break;
    out->insert(out->end(), buf, buf + bytes_read);
  }
  bool result = !ferror(fp);
  fclose(fp);
  return result;
}

bool WriteFile(const std::string& path, vector<uint8_t> contents) {
  FILE* fp = fopen(path.c_str(), "r");
  if (!fp)
    return false;
  size_t written = fwrite(contents.data(), 1, contents.size(), fp);
  bool result = written == contents.size() && !ferror(fp);
  fclose(fp);
  return result;
}

ScopedTempFile::ScopedTempFile(const std::string& pattern) {
  EXPECT_TRUE(MakeTempFile(pattern, &filename_));
}

ScopedTempFile::~ScopedTempFile() {
  if (!filename_.empty() && unlink(filename_.c_str()) < 0) {
    PLOG(ERROR) << "Unable to remove temporary file.";
  }
}

bool BsdiffPatchFile::LoadFromFile(const std::string& filename) {
  vector<uint8_t> contents;
  if (!ReadFile(filename, &contents))
    return false;
  file_size = contents.size();
  // Check that the file includes at least the header.
  TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize);
  magic = std::string(contents.data(), contents.data() + 8);
  memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len));
  memcpy(&diff_len, contents.data() + 16, sizeof(diff_len));
  memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len));

  // Sanity check before we attempt to parse the bz2 streams.
  TEST_AND_RETURN_FALSE(ctrl_len >= 0);
  TEST_AND_RETURN_FALSE(diff_len >= 0);

  // The cast is safe since ctrl_len and diff_len are both positive.
  TEST_AND_RETURN_FALSE(file_size >=
        static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len));
  extra_len = file_size - kHeaderSize - ctrl_len - diff_len;

  uint8_t* ptr = contents.data() + kHeaderSize;
  bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len);
  ptr += ctrl_len;
  bz2_diff = vector<uint8_t>(ptr, ptr + diff_len);
  ptr += diff_len;
  bz2_extra = vector<uint8_t>(ptr, ptr + extra_len);

  return true;
}

bool BsdiffPatchFile::IsValid() const {
  TEST_AND_RETURN_FALSE(ctrl_len >= 0);
  TEST_AND_RETURN_FALSE(diff_len >= 0);
  TEST_AND_RETURN_FALSE(new_file_len >= 0);

  // TODO(deymo): Test that the length of the decompressed bz2 streams |diff|
  // plus |extra| are equal to the |new_file_len|.
  // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x"
  // and "y" value >= 0 ("z" can be negative).
  return true;
}

}  // namespace test_utils