regulators: Make TmpFile class common
A TmpFile class was implemented in two different test cases to
automatically create and delete temporary files.
Moved the TmpFile class into a standalone file so that the code could be
common among test cases. Improved the error handling.
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: Ifa8ddd3b442bcf8fbf0dc4d0a39dd9fc5f233e3f
diff --git a/phosphor-regulators/test/config_file_parser_tests.cpp b/phosphor-regulators/test/config_file_parser_tests.cpp
index 490cac7..83d5699 100644
--- a/phosphor-regulators/test/config_file_parser_tests.cpp
+++ b/phosphor-regulators/test/config_file_parser_tests.cpp
@@ -20,10 +20,9 @@
#include "pmbus_utils.hpp"
#include "pmbus_write_vout_command_action.hpp"
#include "rule.hpp"
+#include "tmp_file.hpp"
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <sys/stat.h> // for chmod()
#include <nlohmann/json.hpp>
@@ -46,41 +45,6 @@
using namespace phosphor::power::regulators::config_file_parser::internal;
using json = nlohmann::json;
-/**
- * @class TmpFile
- *
- * Temporary file.
- *
- * File is deleted automatically by the destructor when the object goes out of
- * scope.
- */
-class TmpFile
-{
- public:
- TmpFile()
- {
- int fd = mkstemp(fileName);
- if (fd == -1)
- {
- throw std::runtime_error{"Unable to create temporary file"};
- }
- close(fd);
- }
-
- std::string getName()
- {
- return fileName;
- }
-
- ~TmpFile()
- {
- unlink(fileName);
- }
-
- private:
- char fileName[17] = "/tmp/temp-XXXXXX";
-};
-
void writeConfigFile(const std::filesystem::path& pathName,
const std::string& contents)
{
diff --git a/phosphor-regulators/test/tmp_file.hpp b/phosphor-regulators/test/tmp_file.hpp
new file mode 100644
index 0000000..dd0a66c
--- /dev/null
+++ b/phosphor-regulators/test/tmp_file.hpp
@@ -0,0 +1,99 @@
+/**
+ * Copyright © 2020 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <errno.h> // for errno
+#include <stdio.h> // for perror()
+#include <stdlib.h> // for mkstemp()
+#include <string.h> // for strerror()
+#include <unistd.h> // for close(), unlink()
+
+#include <stdexcept>
+#include <string>
+
+namespace phosphor::power::regulators
+{
+
+/**
+ * @class TmpFile
+ *
+ * Temporary file.
+ *
+ * File is created by the constructor and deleted by the destructor. The file
+ * name can be obtained from getName().
+ */
+class TmpFile
+{
+ public:
+ // Specify which compiler-generated methods we want
+ TmpFile(const TmpFile&) = delete;
+ TmpFile(TmpFile&&) = delete;
+ TmpFile& operator=(const TmpFile&) = delete;
+ TmpFile& operator=(TmpFile&&) = delete;
+
+ /**
+ * Constructor.
+ *
+ * Creates the temporary file.
+ */
+ TmpFile()
+ {
+ // Generate unique file name, create file, and open it. The XXXXXX
+ // characters are replaced by mkstemp() to make the file name unique.
+ char fileNameTemplate[17] = "/tmp/temp-XXXXXX";
+ int fd = mkstemp(fileNameTemplate);
+ if (fd == -1)
+ {
+ // If mkstemp() fails, throw an exception. No temporary file has
+ // been created and calling getName() would not work.
+ throw std::runtime_error{"Unable to create temporary file: " +
+ std::string{strerror(errno)}};
+ }
+
+ // Close file
+ if (close(fd) == -1)
+ {
+ // If close() fails, write a message to standard error but do not
+ // throw an exception. If an exception is thrown, the destructor
+ // will not be run and the temporary file will not be deleted.
+ perror("Unable to close temporary file");
+ }
+
+ // Save file name
+ fileName = fileNameTemplate;
+ }
+
+ const std::string& getName()
+ {
+ return fileName;
+ }
+
+ ~TmpFile()
+ {
+ // Delete temporary file
+ if (unlink(fileName.c_str()) == -1)
+ {
+ // If unlink() fails, write a message to standard error but do not
+ // throw an exception. Destructors must not throw exceptions.
+ perror("Unable to delete temporary file");
+ }
+ }
+
+ private:
+ std::string fileName{};
+};
+
+} // namespace phosphor::power::regulators
diff --git a/phosphor-regulators/test/validate-regulators-config_tests.cpp b/phosphor-regulators/test/validate-regulators-config_tests.cpp
index 2b915b9..987a492 100644
--- a/phosphor-regulators/test/validate-regulators-config_tests.cpp
+++ b/phosphor-regulators/test/validate-regulators-config_tests.cpp
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
+#include "tmp_file.hpp"
+
+#include <stdio.h> // for popen(), pclose(), fgets()
+#include <sys/stat.h> // for chmod()
+#include <sys/wait.h> // for WEXITSTATUS
#include <nlohmann/json.hpp>
+#include <cstdio>
#include <fstream>
#include <gtest/gtest.h>
@@ -35,6 +36,7 @@
expectJsonInvalid(configFileJson, expectedErrorMessage, \
expectedOutputMessage)
+using namespace phosphor::power::regulators;
using json = nlohmann::json;
const json validConfigFile = R"(
@@ -103,33 +105,6 @@
}
)"_json;
-class TmpFile
-{
- public:
- TmpFile()
- {
- int fd = mkstemp(fileName);
- if (fd == -1)
- {
- perror("Can't create temporary file");
- }
- close(fd);
- }
-
- std::string getName()
- {
- return fileName;
- }
-
- ~TmpFile()
- {
- unlink(fileName);
- }
-
- private:
- char fileName[17] = "/tmp/temp-XXXXXX";
-};
-
std::string getValidationToolCommand(const std::string& configFileName)
{
std::string command =