xref: /openbmc/phosphor-power/test/temporary_subdirectory_tests.cpp (revision 8b38b177315d40f1f9bc1e4d0784d45ea17cbd5c)
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 // This is undefined behavior in C++, but suppress the warning
114 // to observe how the class handles it.
115 #ifdef __clang__
116 #pragma clang diagnostic push
117 #pragma clang diagnostic ignored "-Wself-move"
118 #endif
119         // Try to move object into itself; should do nothing
120         subdirectory = static_cast<TemporarySubDirectory&&>(subdirectory);
121 #ifdef __clang__
122 #pragma clang diagnostic pop
123 #endif
124 
125         // Verify object still owns same subdirectory and subdirectory exists
126         EXPECT_EQ(subdirectory.getPath(), path);
127         EXPECT_TRUE(fs::exists(path));
128     }
129 
130     // Test where fails: Cannot delete subdirectory
131     {
132         // Create first object and verify subdirectory exists
133         TemporarySubDirectory subdirectory1{};
134         EXPECT_FALSE(subdirectory1.getPath().empty());
135         EXPECT_TRUE(fs::exists(subdirectory1.getPath()));
136 
137         // Save path to first subdirectory
138         fs::path path1 = subdirectory1.getPath();
139 
140         // Create second object and verify subdirectory exists
141         TemporarySubDirectory subdirectory2{};
142         EXPECT_FALSE(subdirectory2.getPath().empty());
143         EXPECT_TRUE(fs::exists(subdirectory2.getPath()));
144 
145         // Save path to second subdirectory
146         fs::path path2 = subdirectory2.getPath();
147 
148         // Verify temporary subdirectories are different
149         EXPECT_NE(path1, path2);
150 
151         // Change second subdirectory to unreadable so it cannot be removed
152         fs::permissions(path2, fs::perms::none);
153 
154         try
155         {
156             // Try to move first object into the second; should throw exception
157             subdirectory2 = std::move(subdirectory1);
158             ADD_FAILURE() << "Should not have reached this line.";
159         }
160         catch (const std::exception& e)
161         {
162             // This is expected.  Exception message will vary.
163         }
164 
165         // Change second subdirectory to readable/writable so it can be removed
166         fs::permissions(path2, fs::perms::owner_all);
167 
168         // Verify first object has not changed and first subdirectory exists
169         EXPECT_EQ(subdirectory1.getPath(), path1);
170         EXPECT_TRUE(fs::exists(path1));
171 
172         // Verify second object has not changed and second subdirectory exists
173         EXPECT_EQ(subdirectory2.getPath(), path2);
174         EXPECT_TRUE(fs::exists(path2));
175     }
176 }
177 
178 TEST(TemporarySubDirectoryTests, Destructor)
179 {
180     // Test where works: Subdirectory is deleted
181     {
182         fs::path path{};
183         {
184             TemporarySubDirectory subdirectory{};
185             path = subdirectory.getPath();
186             EXPECT_TRUE(fs::exists(path));
187         }
188         EXPECT_FALSE(fs::exists(path));
189     }
190 
191     // Test where works: Subdirectory was already deleted
192     {
193         fs::path path{};
194         {
195             TemporarySubDirectory subdirectory{};
196             path = subdirectory.getPath();
197             EXPECT_TRUE(fs::exists(path));
198             subdirectory.remove();
199             EXPECT_FALSE(fs::exists(path));
200         }
201         EXPECT_FALSE(fs::exists(path));
202     }
203 
204     // Test where fails: Cannot delete subdirectory: No exception thrown
205     {
206         fs::path path{};
207         try
208         {
209             TemporarySubDirectory subdirectory{};
210             path = subdirectory.getPath();
211             EXPECT_TRUE(fs::exists(path));
212 
213             // Change subdirectory to unreadable so it cannot be removed
214             fs::permissions(path, fs::perms::none);
215         }
216         catch (...)
217         {
218             ADD_FAILURE() << "Should not have caught exception.";
219         }
220 
221         // Change subdirectory to readable/writable so it can be removed
222         fs::permissions(path, fs::perms::owner_all);
223 
224         // Subdirectory should still exist
225         EXPECT_TRUE(fs::exists(path));
226 
227         // Delete subdirectory
228         fs::remove_all(path);
229     }
230 }
231 
232 TEST(TemporarySubDirectoryTests, Remove)
233 {
234     // Test where works
235     {
236         // Create object and verify subdirectory exists
237         TemporarySubDirectory subdirectory{};
238         EXPECT_FALSE(subdirectory.getPath().empty());
239         EXPECT_TRUE(fs::exists(subdirectory.getPath()));
240 
241         // Save path to subdirectory
242         fs::path path = subdirectory.getPath();
243 
244         // Delete subdirectory
245         subdirectory.remove();
246 
247         // Verify path is cleared and subdirectory does not exist
248         EXPECT_TRUE(subdirectory.getPath().empty());
249         EXPECT_FALSE(fs::exists(path));
250 
251         // Delete subdirectory again; should do nothing
252         subdirectory.remove();
253         EXPECT_TRUE(subdirectory.getPath().empty());
254         EXPECT_FALSE(fs::exists(path));
255     }
256 
257     // Test where fails
258     {
259         // Create object and verify subdirectory exists
260         TemporarySubDirectory subdirectory{};
261         EXPECT_FALSE(subdirectory.getPath().empty());
262         EXPECT_TRUE(fs::exists(subdirectory.getPath()));
263 
264         // Save path to subdirectory
265         fs::path path = subdirectory.getPath();
266 
267         // Change subdirectory to unreadable so it cannot be removed
268         fs::permissions(path, fs::perms::none);
269 
270         try
271         {
272             // Try to delete subdirectory; should fail with exception
273             subdirectory.remove();
274             ADD_FAILURE() << "Should not have reached this line.";
275         }
276         catch (const std::exception& e)
277         {
278             // This is expected.  Exception message will vary.
279         }
280 
281         // Change subdirectory to readable/writable so it can be deleted by
282         // destructor
283         fs::permissions(path, fs::perms::owner_all);
284     }
285 }
286 
287 TEST(TemporarySubDirectoryTests, GetPath)
288 {
289     TemporarySubDirectory subdirectory{};
290     EXPECT_FALSE(subdirectory.getPath().empty());
291     EXPECT_EQ(subdirectory.getPath().parent_path(), "/tmp");
292     EXPECT_TRUE(fs::exists(subdirectory.getPath()));
293 }
294