1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "temporary_subdirectory.hpp"
17 
18 #include <filesystem>
19 #include <fstream>
20 #include <string>
21 #include <utility>
22 
23 #include <gtest/gtest.h>
24 
25 using namespace phosphor::power::util;
26 namespace fs = std::filesystem;
27 
28 TEST(TemporarySubDirectoryTests, DefaultConstructor)
29 {
30     TemporarySubDirectory subdirectory{};
31 
32     fs::path path = subdirectory.getPath();
33     EXPECT_FALSE(path.empty());
34     EXPECT_TRUE(fs::exists(path));
35     EXPECT_TRUE(fs::is_directory(path));
36 
37     fs::path parentDir = path.parent_path();
38     EXPECT_EQ(parentDir, "/tmp");
39 
40     std::string baseName = path.filename();
41     EXPECT_TRUE(baseName.starts_with("phosphor-power-"));
42 }
43 
44 TEST(TemporarySubDirectoryTests, MoveConstructor)
45 {
46     // Create first object and verify subdirectory exists
47     TemporarySubDirectory subdirectory1{};
48     EXPECT_FALSE(subdirectory1.getPath().empty());
49     EXPECT_TRUE(fs::exists(subdirectory1.getPath()));
50 
51     // Save path to subdirectory
52     fs::path path = subdirectory1.getPath();
53 
54     // Create second object by moving first object
55     TemporarySubDirectory subdirectory2{std::move(subdirectory1)};
56 
57     // Verify first object now has an empty path
58     EXPECT_TRUE(subdirectory1.getPath().empty());
59 
60     // Verify second object now owns same subdirectory and subdirectory exists
61     EXPECT_EQ(subdirectory2.getPath(), path);
62     EXPECT_TRUE(fs::exists(subdirectory2.getPath()));
63 }
64 
65 TEST(TemporarySubDirectoryTests, MoveAssignmentOperator)
66 {
67     // Test where works: object is moved
68     {
69         // Create first object and verify subdirectory exists
70         TemporarySubDirectory subdirectory1{};
71         EXPECT_FALSE(subdirectory1.getPath().empty());
72         EXPECT_TRUE(fs::exists(subdirectory1.getPath()));
73 
74         // Save path to first subdirectory
75         fs::path path1 = subdirectory1.getPath();
76 
77         // Create second object and verify subdirectory exists
78         TemporarySubDirectory subdirectory2{};
79         EXPECT_FALSE(subdirectory2.getPath().empty());
80         EXPECT_TRUE(fs::exists(subdirectory2.getPath()));
81 
82         // Save path to second subdirectory
83         fs::path path2 = subdirectory2.getPath();
84 
85         // Verify temporary subdirectories are different
86         EXPECT_NE(path1, path2);
87 
88         // Move first object into the second
89         subdirectory2 = std::move(subdirectory1);
90 
91         // Verify first object now has an empty path
92         EXPECT_TRUE(subdirectory1.getPath().empty());
93 
94         // Verify second object now owns first subdirectory and subdirectory
95         // exists
96         EXPECT_EQ(subdirectory2.getPath(), path1);
97         EXPECT_TRUE(fs::exists(path1));
98 
99         // Verify second subdirectory was deleted
100         EXPECT_FALSE(fs::exists(path2));
101     }
102 
103     // Test where does nothing: object moved into itself
104     {
105         // Create object and verify subdirectory exists
106         TemporarySubDirectory subdirectory{};
107         EXPECT_FALSE(subdirectory.getPath().empty());
108         EXPECT_TRUE(fs::exists(subdirectory.getPath()));
109 
110         // Save path to subdirectory
111         fs::path path = subdirectory.getPath();
112 
113         // Try to move object into itself; should do nothing
114         subdirectory = static_cast<TemporarySubDirectory&&>(subdirectory);
115 
116         // Verify object still owns same subdirectory and subdirectory exists
117         EXPECT_EQ(subdirectory.getPath(), path);
118         EXPECT_TRUE(fs::exists(path));
119     }
120 
121     // Test where fails: Cannot delete subdirectory
122     {
123         // Create first object and verify subdirectory exists
124         TemporarySubDirectory subdirectory1{};
125         EXPECT_FALSE(subdirectory1.getPath().empty());
126         EXPECT_TRUE(fs::exists(subdirectory1.getPath()));
127 
128         // Save path to first subdirectory
129         fs::path path1 = subdirectory1.getPath();
130 
131         // Create second object and verify subdirectory exists
132         TemporarySubDirectory subdirectory2{};
133         EXPECT_FALSE(subdirectory2.getPath().empty());
134         EXPECT_TRUE(fs::exists(subdirectory2.getPath()));
135 
136         // Save path to second subdirectory
137         fs::path path2 = subdirectory2.getPath();
138 
139         // Verify temporary subdirectories are different
140         EXPECT_NE(path1, path2);
141 
142         // Change second subdirectory to unreadable so it cannot be removed
143         fs::permissions(path2, fs::perms::none);
144 
145         try
146         {
147             // Try to move first object into the second; should throw exception
148             subdirectory2 = std::move(subdirectory1);
149             ADD_FAILURE() << "Should not have reached this line.";
150         }
151         catch (const std::exception& e)
152         {
153             // This is expected.  Exception message will vary.
154         }
155 
156         // Change second subdirectory to readable/writable so it can be removed
157         fs::permissions(path2, fs::perms::owner_all);
158 
159         // Verify first object has not changed and first subdirectory exists
160         EXPECT_EQ(subdirectory1.getPath(), path1);
161         EXPECT_TRUE(fs::exists(path1));
162 
163         // Verify second object has not changed and second subdirectory exists
164         EXPECT_EQ(subdirectory2.getPath(), path2);
165         EXPECT_TRUE(fs::exists(path2));
166     }
167 }
168 
169 TEST(TemporarySubDirectoryTests, Destructor)
170 {
171     // Test where works: Subdirectory is deleted
172     {
173         fs::path path{};
174         {
175             TemporarySubDirectory subdirectory{};
176             path = subdirectory.getPath();
177             EXPECT_TRUE(fs::exists(path));
178         }
179         EXPECT_FALSE(fs::exists(path));
180     }
181 
182     // Test where works: Subdirectory was already deleted
183     {
184         fs::path path{};
185         {
186             TemporarySubDirectory subdirectory{};
187             path = subdirectory.getPath();
188             EXPECT_TRUE(fs::exists(path));
189             subdirectory.remove();
190             EXPECT_FALSE(fs::exists(path));
191         }
192         EXPECT_FALSE(fs::exists(path));
193     }
194 
195     // Test where fails: Cannot delete subdirectory: No exception thrown
196     {
197         fs::path path{};
198         try
199         {
200             TemporarySubDirectory subdirectory{};
201             path = subdirectory.getPath();
202             EXPECT_TRUE(fs::exists(path));
203 
204             // Change subdirectory to unreadable so it cannot be removed
205             fs::permissions(path, fs::perms::none);
206         }
207         catch (...)
208         {
209             ADD_FAILURE() << "Should not have caught exception.";
210         }
211 
212         // Change subdirectory to readable/writable so it can be removed
213         fs::permissions(path, fs::perms::owner_all);
214 
215         // Subdirectory should still exist
216         EXPECT_TRUE(fs::exists(path));
217 
218         // Delete subdirectory
219         fs::remove_all(path);
220     }
221 }
222 
223 TEST(TemporarySubDirectoryTests, Remove)
224 {
225     // Test where works
226     {
227         // Create object and verify subdirectory exists
228         TemporarySubDirectory subdirectory{};
229         EXPECT_FALSE(subdirectory.getPath().empty());
230         EXPECT_TRUE(fs::exists(subdirectory.getPath()));
231 
232         // Save path to subdirectory
233         fs::path path = subdirectory.getPath();
234 
235         // Delete subdirectory
236         subdirectory.remove();
237 
238         // Verify path is cleared and subdirectory does not exist
239         EXPECT_TRUE(subdirectory.getPath().empty());
240         EXPECT_FALSE(fs::exists(path));
241 
242         // Delete subdirectory again; should do nothing
243         subdirectory.remove();
244         EXPECT_TRUE(subdirectory.getPath().empty());
245         EXPECT_FALSE(fs::exists(path));
246     }
247 
248     // Test where fails
249     {
250         // Create object and verify subdirectory exists
251         TemporarySubDirectory subdirectory{};
252         EXPECT_FALSE(subdirectory.getPath().empty());
253         EXPECT_TRUE(fs::exists(subdirectory.getPath()));
254 
255         // Save path to subdirectory
256         fs::path path = subdirectory.getPath();
257 
258         // Change subdirectory to unreadable so it cannot be removed
259         fs::permissions(path, fs::perms::none);
260 
261         try
262         {
263             // Try to delete subdirectory; should fail with exception
264             subdirectory.remove();
265             ADD_FAILURE() << "Should not have reached this line.";
266         }
267         catch (const std::exception& e)
268         {
269             // This is expected.  Exception message will vary.
270         }
271 
272         // Change subdirectory to readable/writable so it can be deleted by
273         // destructor
274         fs::permissions(path, fs::perms::owner_all);
275     }
276 }
277 
278 TEST(TemporarySubDirectoryTests, GetPath)
279 {
280     TemporarySubDirectory subdirectory{};
281     EXPECT_FALSE(subdirectory.getPath().empty());
282     EXPECT_EQ(subdirectory.getPath().parent_path(), "/tmp");
283     EXPECT_TRUE(fs::exists(subdirectory.getPath()));
284 }
285