xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/libarchive/test/minitar_test.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <fstream>
16 
17 #include "sapi_minitar.h"  // NOLINT(build/include)
18 #include "gtest/gtest.h"
19 #include "sandboxed_api/sandbox2/util.h"
20 #include "sandboxed_api/util/fileops.h"
21 #include "sandboxed_api/util/path.h"
22 #include "sandboxed_api/util/status_matchers.h"
23 
24 namespace {
25 
26 using ::sapi::IsOk;
27 using ::sapi::file::JoinPath;
28 using ::sapi::file_util::fileops::Exists;
29 using ::testing::Eq;
30 using ::testing::IsTrue;
31 using ::testing::StrEq;
32 
33 // We will use a fixture class for testing which allows us to override the
34 // SetUp and TearDown functions. Also, data that needs to be initialized
35 // or destroyed only once (the test files and directories) will be handled
36 // in the SetUpTestSuite and TearDownTestSuite functions which are executed
37 // only once.
38 // All of the testing data will be placed in a temporary directory and each
39 // test will have it's own temporary directory. At the end of each test
40 // and all of the tests, the temporary data is deleted.
41 class MiniTarTest : public ::testing::Test {
42  protected:
43   // Before running the tests, we create a temporary directory which will
44   // store generated files and directories used for testing.
45   // The directory will look as follows:
46   // -file1
47   // -dir1 - file2
48   //       - dir2 - file3
SetUpTestSuite()49   static void SetUpTestSuite() {
50     absl::StatusOr<std::string> tmp_status = CreateTempDirAtCWD();
51     ASSERT_THAT(tmp_status, IsOk());
52     data_dir_ = new std::string(std::move(tmp_status).value());
53 
54     init_wd_ = new std::string(sandbox2::file_util::fileops::GetCWD());
55     ASSERT_THAT(Exists(data_dir_, false), IsTrue())
56         << "Test data directory was not created";
57     ASSERT_THAT(chdir(data_dir_.data()), Eq(0))
58         << "Could not chdir into test data directory";
59 
60     CreateAndWriteToFile(kFile1);
61     ASSERT_THAT(mkdir(kDir1.data(), 0755), Eq(0)) << "Could not create dir1";
62     CreateAndWriteToFile(kFile2);
63     ASSERT_THAT(mkdir(kDir2.data(), 0755), Eq(0)) << "Could not create dir2";
64     CreateAndWriteToFile(kFile3);
65 
66     test_count_ = 0;
67   }
68 
TearDownTestSuite()69   static void TearDownTestSuite() {
70     // The tests have the data directory as their working directory at the end
71     // so we move to the initial working directory in order to not delete the
72     // directory that we are inside of.
73     ASSERT_THAT(chdir(init_wd_->data()), Eq(0))
74         << "Could not chdir into initial working directory";
75     EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(*data_dir_),
76                 IsTrue)
77         << "Error during test data deletion";
78     delete init_wd_;
79     delete data_dir_;
80   }
81 
SetUp()82   void SetUp() override {
83     // We use a unique id based on test count to make sure that files created
84     // during tests do not overlap.
85     id_ = "test" + std::to_string(test_count_);
86 
87     absl::StatusOr<std::string> tmp_status = CreateTempDirAtCWD();
88     ASSERT_THAT(tmp_status, IsOk());
89     tmp_dir_ = tmp_status.value();
90 
91     ASSERT_THAT(Exists(tmp_dir_, false), IsTrue)
92         << "Could not create test specific temporary directory";
93     ASSERT_THAT(chdir(data_dir_->data()), Eq(0))
94         << "Could not chdir into test data directory";
95   }
96 
TearDown()97   void TearDown() override {
98     // Move to another directory before deleting the temporary folder.
99     ASSERT_THAT(chdir(data_dir_->data()), Eq(0))
100         << "Could not chdir into test data directory";
101 
102     EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(tmp_dir_),
103                 IsTrue)
104         << "Error during test temporary directory deletion";
105     ++test_count_;
106   }
107 
108   // Creates the file specified and writes the same filename.
109   // This is done in order to not have completely empty files for the
110   // archiving step.
CreateAndWriteToFile(absl::string_view file)111   static void CreateAndWriteToFile(absl::string_view file) {
112     std::ofstream fin(file.data());
113     ASSERT_THAT(fin.is_open(), IsTrue()) << "Could not create" << file;
114     fin << file;
115     fin.close();
116   }
117 
118   // Checks if the files exists and if the contents are correct.
119   // In these tests, each file contains the relative path from the test
120   // directory.
121   // Example: dir1/dir2/file3 will contain dir1/dir2/file3.
122   // What the files contain does not matter as much, the only important thing
123   // is that they are not empty so we can check if the contents are preserved.
CheckFile(const std::string & file)124   static void CheckFile(const std::string& file) {
125     ASSERT_THAT(Exists(file, false), IsTrue()) << "Could not find " << file;
126     std::ifstream fin(file);
127     ASSERT_THAT(fin.is_open(), IsTrue()) << "Error when opening " << file;
128 
129     std::string file_contents((std::istreambuf_iterator<char>(fin)),
130                               std::istreambuf_iterator<char>());
131 
132     EXPECT_THAT(file_contents, StrEq(file))
133         << "Contents of " << file << " are different after extraction";
134     fin.close();
135   }
136 
137   static int test_count_;
138   static std::string* data_dir_;
139   static std::string* init_wd_;
140   std::string tmp_dir_;
141   std::string id_;
142 
143   static constexpr absl::string_view kFile1 = "file1";
144   static constexpr absl::string_view kFile2 = "dir1/file2";
145   static constexpr absl::string_view kFile3 = "dir1/dir2/file3";
146   static constexpr absl::string_view kDir1 = "dir1";
147   static constexpr absl::string_view kDir2 = "dir1/dir2";
148 };
149 
150 int MiniTarTest::test_count_;
151 std::string* MiniTarTest::data_dir_;
152 std::string* MiniTarTest::init_wd_;
153 
154 // The tests have the following pattern:
155 // 1) From inside the test data directory, call the create function with
156 // different arguments.
157 // 2) Move to the test specific temporary directory created during the
158 // set up phase.
159 // 3) Extract the archive created at step 1.
160 // 4) Check that the files in the archive have been extracted correctly
161 // by first checking if they exist and then checking if the content is the
162 // same as in the original file.
TEST_F(MiniTarTest,TestFileSimple)163 TEST_F(MiniTarTest, TestFileSimple) {
164   std::vector<std::string> v = {kFile1.data()};
165 
166   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
167 
168   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
169       << "Could not chdir into test data directory";
170 
171   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
172               IsOk());
173 
174   CheckFile(std::string(kFile1));
175 }
176 
TEST_F(MiniTarTest,TestMultipleFiles)177 TEST_F(MiniTarTest, TestMultipleFiles) {
178   std::vector<std::string> v = {kFile1.data(), kFile2.data(), kFile3.data()};
179   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
180   ASSERT_THAT(Exists(id_.data(), false), IsTrue())
181       << "Archive file was not created";
182 
183   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
184       << "Could not chdir into test data directory";
185 
186   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
187               IsOk());
188 
189   CheckFile(std::string(kFile1));
190   CheckFile(std::string(kFile2));
191   CheckFile(std::string(kFile3));
192 }
193 
TEST_F(MiniTarTest,TestDirectorySimple)194 TEST_F(MiniTarTest, TestDirectorySimple) {
195   std::vector<std::string> v = {kDir2.data()};
196   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
197 
198   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
199       << "Could not chdir into test data directory";
200 
201   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
202               IsOk());
203 
204   CheckFile(std::string(kFile3));
205 }
206 
TEST_F(MiniTarTest,TestDirectoryNested)207 TEST_F(MiniTarTest, TestDirectoryNested) {
208   std::vector<std::string> v = {kDir1.data()};
209   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
210 
211   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
212       << "Could not chdir into test data directory";
213 
214   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
215               IsOk());
216 
217   CheckFile(std::string(kFile2));
218   CheckFile(std::string(kFile3));
219 }
220 
TEST_F(MiniTarTest,TestComplex)221 TEST_F(MiniTarTest, TestComplex) {
222   std::vector<std::string> v = {kFile1.data(), kDir1.data()};
223   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
224 
225   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
226       << "Could not chdir into test data directory";
227 
228   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
229               IsOk());
230 
231   CheckFile(std::string(kFile1));
232   CheckFile(std::string(kFile2));
233   CheckFile(std::string(kFile3));
234 }
235 
TEST_F(MiniTarTest,TestCompress)236 TEST_F(MiniTarTest, TestCompress) {
237   std::vector<std::string> v = {kFile1.data(), kDir1.data()};
238   int compress = 'Z';
239   ASSERT_THAT(CreateArchive(id_.data(), compress, v, false), IsOk());
240 
241   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
242       << "Could not chdir into test data directory";
243   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
244               IsOk());
245 
246   CheckFile(std::string(kFile1));
247   CheckFile(std::string(kFile2));
248   CheckFile(std::string(kFile3));
249 }
250 
TEST_F(MiniTarTest,TestGZIP)251 TEST_F(MiniTarTest, TestGZIP) {
252   std::vector<std::string> v = {kFile1.data(), kDir1.data()};
253   int compress = 'z';
254   ASSERT_THAT(CreateArchive(id_.data(), compress, v, false), IsOk());
255 
256   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
257       << "Could not chdir into test data directory";
258   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
259               IsOk());
260 
261   CheckFile(std::string(kFile1));
262   CheckFile(std::string(kFile2));
263   CheckFile(std::string(kFile3));
264 }
265 
TEST_F(MiniTarTest,TestBZIP2)266 TEST_F(MiniTarTest, TestBZIP2) {
267   std::vector<std::string> v = {kFile1.data(), kDir1.data()};
268   int compress = 'j';
269   ASSERT_THAT(CreateArchive(id_.data(), compress, v, false), IsOk());
270 
271   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
272       << "Could not chdir into test data directory";
273   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
274               IsOk());
275 
276   CheckFile(std::string(kFile1));
277   CheckFile(std::string(kFile2));
278   CheckFile(std::string(kFile3));
279 }
280 
TEST_F(MiniTarTest,TestPaths)281 TEST_F(MiniTarTest, TestPaths) {
282   // These should be equivalent to kFile1 and kDir1 after cleaning.
283   std::vector<std::string> v = {JoinPath("a/b/../../c/../", kFile1).data(),
284                                 JoinPath("d/../e/././///../", kDir1).data()};
285   ASSERT_THAT(CreateArchive(id_.data(), 0, v, false), IsOk());
286 
287   ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
288       << "Could not chdir into test data directory";
289   ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
290               IsOk());
291 
292   CheckFile(std::string(kFile1));
293   CheckFile(std::string(kFile2));
294   CheckFile(std::string(kFile3));
295 }
296 
297 }  // namespace
298