1 // Copyright (c) 2012 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 "scoped_temp_path.h"
6 
7 #include <string.h>  // for strlen.
8 #include <sys/stat.h>
9 
10 #include <vector>
11 
12 #include "base/logging.h"
13 #include "compat/string.h"
14 #include "compat/test.h"
15 
16 namespace {
17 
18 // For testing the creation of multiple temp paths.
19 const int kNumMultiplePaths = 32;
20 
21 // When testing non-empty directories, populate them with this many files.
22 const int kNumFilesPerNonEmptyDirectory = 10;
23 
24 // The length of the path template suffix used internally by ScopedTempPath and
25 // derived classes.
26 const size_t kTemplateSuffixSize = strlen("XXXXXX");
27 
28 // Temporary paths use this prefix by default. Copied from scoped_temp_path.cc.
29 const char kTempPathTemplatePrefix[] = "/tmp/quipper.";
30 
31 // Tests if |path| exists on the file system.
PathExists(const string & path)32 bool PathExists(const string& path) {
33   struct stat buf;
34   // stat() returns 0 on success, i.e. if the path exists and is valid.
35   return !stat(path.c_str(), &buf);
36 }
37 
38 // Creates some files in a directory. Returns the number of files created.
PopulateDirectoryWithFiles(const string & dir,int num_files)39 int PopulateDirectoryWithFiles(const string& dir, int num_files) {
40   // The last six characters of the file template must be "XXXXXX".
41   const char kPathTemplateSuffix[] = "/testXXXXXX";
42 
43   // The string providing the path template for creating temp files must not be
44   // constant, so allocate some space here.
45   size_t buf_size = dir.size() + strlen(kPathTemplateSuffix) + 1;
46   char* path_template = new char[buf_size];
47 
48   int num_files_created = 0;
49   for (int i = 0; i < num_files; ++i) {
50     // Construct the mutable path template.
51     snprintf(path_template, buf_size, "%s%s", dir.c_str(), kPathTemplateSuffix);
52     // Create the file and make sure it is valid.
53     int fd = mkstemp(path_template);
54     if (fd == -1) {
55       LOG(ERROR) << "Could not create file, errno=" << errno;
56       continue;
57     }
58     ++num_files_created;
59     close(fd);
60   }
61   delete[] path_template;
62 
63   return num_files_created;
64 }
65 
66 }  // namespace
67 
68 namespace quipper {
69 
70 // Create one file and make sure it is deleted when out of scope.
TEST(ScopedTempPathTest,OneFile)71 TEST(ScopedTempPathTest, OneFile) {
72   string path;
73   {
74     ScopedTempFile temp_file;
75     path = temp_file.path();
76     EXPECT_TRUE(PathExists(path)) << path;
77     EXPECT_EQ(strlen(kTempPathTemplatePrefix) + kTemplateSuffixSize,
78               path.size());
79     EXPECT_EQ(kTempPathTemplatePrefix,
80               path.substr(0, strlen(kTempPathTemplatePrefix)));
81   }
82   EXPECT_FALSE(PathExists(path)) << path;
83 }
84 
85 // Create a file with a custom template filename.
TEST(ScopedTempPathTest,CustomFileTemplate)86 TEST(ScopedTempPathTest, CustomFileTemplate) {
87   string path;
88   {
89     const string prefix = "/tmp/foobar.";
90     ScopedTempFile temp_file(prefix);
91     path = temp_file.path();
92     EXPECT_TRUE(PathExists(path)) << path;
93     EXPECT_EQ(prefix.size() + kTemplateSuffixSize, path.size());
94     EXPECT_EQ(prefix, path.substr(0, prefix.size()));
95   }
96   EXPECT_FALSE(PathExists(path)) << path;
97 }
98 
99 // Create many files and make sure they are deleted when out of scope.
TEST(ScopedTempPathTest,MultipleFiles)100 TEST(ScopedTempPathTest, MultipleFiles) {
101   std::vector<string> paths(kNumMultiplePaths);
102   {
103     std::vector<ScopedTempFile> temp_files(kNumMultiplePaths);
104     for (size_t i = 0; i < kNumMultiplePaths; ++i) {
105       paths[i] = temp_files[i].path();
106       EXPECT_TRUE(PathExists(paths[i])) << paths[i];
107     }
108   }
109   for (size_t i = 0; i < kNumMultiplePaths; ++i) {
110     EXPECT_FALSE(PathExists(paths[i])) << paths[i];
111   }
112 }
113 
114 // Create one empty directory and make sure it is deleted when out of scope.
TEST(ScopedTempPathTest,OneEmptyDir)115 TEST(ScopedTempPathTest, OneEmptyDir) {
116   string path;
117   {
118     ScopedTempDir temp_path;
119     path = temp_path.path();
120     EXPECT_TRUE(PathExists(path)) << path;
121     EXPECT_EQ('/', path.back()) << "Should append a slash";
122     EXPECT_EQ(strlen(kTempPathTemplatePrefix) + kTemplateSuffixSize + 1,
123               path.size());
124     EXPECT_EQ(kTempPathTemplatePrefix,
125               path.substr(0, strlen(kTempPathTemplatePrefix)));
126   }
127   EXPECT_FALSE(PathExists(path)) << path;
128 }
129 
130 // Create a file with a custom template dirname.
TEST(ScopedTempPathTest,CustomDirTemplate)131 TEST(ScopedTempPathTest, CustomDirTemplate) {
132   string path;
133   {
134     const string prefix = "/tmp/foobar.";
135     ScopedTempDir temp_path(prefix);
136     path = temp_path.path();
137     EXPECT_TRUE(PathExists(path)) << path;
138     EXPECT_EQ('/', path.back()) << "Should append a slash";
139     // Check prefix matches:
140     EXPECT_EQ(prefix.size() + kTemplateSuffixSize + 1, path.size());
141     EXPECT_EQ(prefix, path.substr(0, prefix.size()));
142   }
143   EXPECT_FALSE(PathExists(path)) << path;
144 }
145 
146 // Create many empty directories and make sure they are deleted when out of
147 // scope.
TEST(ScopedTempPathTest,MultipleEmptyDirs)148 TEST(ScopedTempPathTest, MultipleEmptyDirs) {
149   std::vector<string> paths(kNumMultiplePaths);
150   {
151     std::vector<ScopedTempDir> temp_dirs(kNumMultiplePaths);
152     for (size_t i = 0; i < kNumMultiplePaths; ++i) {
153       paths[i] = temp_dirs[i].path();
154       EXPECT_TRUE(PathExists(paths[i])) << paths[i];
155     }
156   }
157   for (size_t i = 0; i < kNumMultiplePaths; ++i) {
158     EXPECT_FALSE(PathExists(paths[i])) << paths[i];
159   }
160 }
161 
162 // Create a directory with some files in it, and make sure it is deleted when
163 // out of scope.
TEST(ScopedTempPathTest,OneNonEmptyDir)164 TEST(ScopedTempPathTest, OneNonEmptyDir) {
165   string path;
166   {
167     ScopedTempDir temp_path;
168     path = temp_path.path();
169     EXPECT_TRUE(PathExists(path)) << path;
170     // Populate the directory with files.
171     EXPECT_EQ(kNumFilesPerNonEmptyDirectory,
172               PopulateDirectoryWithFiles(path, kNumFilesPerNonEmptyDirectory));
173   }
174   EXPECT_FALSE(PathExists(path)) << path;
175 }
176 
177 // Create many empty directories with files in them, and make sure they are
178 // deleted when out of scope.
TEST(ScopedTempPathTest,MultipleNonEmptyDirs)179 TEST(ScopedTempPathTest, MultipleNonEmptyDirs) {
180   std::vector<string> paths(kNumMultiplePaths);
181   {
182     std::vector<ScopedTempDir> temp_dirs(kNumMultiplePaths);
183     for (size_t i = 0; i < kNumMultiplePaths; ++i) {
184       paths[i] = temp_dirs[i].path();
185       EXPECT_TRUE(PathExists(paths[i])) << paths[i];
186       // Populate the directory with files.
187       EXPECT_EQ(
188           kNumFilesPerNonEmptyDirectory,
189           PopulateDirectoryWithFiles(paths[i], kNumFilesPerNonEmptyDirectory));
190     }
191   }
192   for (size_t i = 0; i < kNumMultiplePaths; ++i) {
193     EXPECT_FALSE(PathExists(paths[i])) << paths[i];
194   }
195 }
196 
197 }  // namespace quipper
198