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