git-svn-id: https://svn.microneil.com/svn/SNFUtility/trunk@4 aa37657e-1934-4a5f-aa6d-2d8eab27ff7cmaster
// This file implements the common functionality for the configuration | // This file implements the common functionality for the configuration | ||||
// utilities. | // utilities. | ||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <stdexcept> | #include <stdexcept> | ||||
#include <fstream> | #include <fstream> | ||||
#include <vector> | #include <vector> | ||||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | // Configuration. //////////////////////////////////////////////////////////////////////////////////////// | ||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
const std::string FileBackup::BackupSuffix(".bak"); | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | // End of configuration. ///////////////////////////////////////////////////////////////////////////////// | ||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
FileBackup::FileBackup(std::string Suffix) : | |||||
BackupSuffix(Suffix) { | |||||
} | |||||
void | void | ||||
FileBackup::CopyFile(std::string From, std::string To) { | FileBackup::CopyFile(std::string From, std::string To) { | ||||
} | } | ||||
bool | |||||
void | |||||
FileBackup::RemoveAllBackupFiles() { | FileBackup::RemoveAllBackupFiles() { | ||||
bool ErrorOccurred = false; | bool ErrorOccurred = false; | ||||
std::ostringstream ErrorMessage; | |||||
for (FilenameContainer::iterator iFile = BackedUpFile.begin(); | for (FilenameContainer::iterator iFile = BackedUpFile.begin(); | ||||
iFile != BackedUpFile.end(); | iFile != BackedUpFile.end(); | ||||
if (0 != remove(BackupFileName.c_str())) { // Delete the backup file. | if (0 != remove(BackupFileName.c_str())) { // Delete the backup file. | ||||
std::cerr << "Unable to remove backup file " << BackupFileName | |||||
<< ": " << strerror(errno) << "\n"; | |||||
ErrorMessage << "Unable to remove backup file " << BackupFileName | |||||
<< ": " << strerror(errno) << "\n"; | |||||
ErrorOccurred = true; | ErrorOccurred = true; | ||||
} | } | ||||
return ErrorOccurred; | |||||
if (ErrorOccurred) { | |||||
throw std::runtime_error(ErrorMessage.str()); | |||||
} | |||||
} | } | ||||
bool | |||||
void | |||||
FileBackup::RestoreAllFilesFromBackup() { | FileBackup::RestoreAllFilesFromBackup() { | ||||
bool ErrorOccurred = false; | bool ErrorOccurred = false; | ||||
std::ostringstream ErrorMessage; | |||||
for (FilenameContainer::iterator iFile = BackedUpFile.begin(); | for (FilenameContainer::iterator iFile = BackedUpFile.begin(); | ||||
iFile != BackedUpFile.end(); | iFile != BackedUpFile.end(); | ||||
} catch (std::exception &e) { | } catch (std::exception &e) { | ||||
std::cerr << "Error restoring " << *iFile << " from backup " | |||||
<< BackupFileName << ": " << e.what() << " \n"; | |||||
ErrorMessage << "Error restoring " << *iFile << " from backup " | |||||
<< BackupFileName << ": " << e.what() << " \n"; | |||||
ErrorOccurred = true; | ErrorOccurred = true; | ||||
} | } | ||||
return ErrorOccurred; | |||||
if (ErrorOccurred) { | |||||
throw std::runtime_error(ErrorMessage.str()); | |||||
} | |||||
} | } |
public: | public: | ||||
/// Constructor. | |||||
// | |||||
// \param[in] Suffix is the suffix to append to create the name of | |||||
// the backup file. | |||||
// | |||||
FileBackup(std::string Suffix); | |||||
/// Create a backup of the specified file. | /// Create a backup of the specified file. | ||||
// | // | ||||
// This method creates a backup of the specified file The name of | // This method creates a backup of the specified file The name of | ||||
// | // | ||||
// \param[in] File is the file name to create a backup for. | // \param[in] File is the file name to create a backup for. | ||||
// | // | ||||
// \throws std::runtime_error in case of error. | |||||
// \throws std::runtime_error if an error is encountered. | |||||
// | // | ||||
// \see RestoreAllFilesFromBackup(). | // \see RestoreAllFilesFromBackup(). | ||||
// | // | ||||
// This method removes the backup of the files specified by the | // This method removes the backup of the files specified by the | ||||
// CreateBackup() method. | // CreateBackup() method. | ||||
// | // | ||||
// If an error is encountered, a message is output to std::cerr. | |||||
// \throws std::runtime_error if an error is encountered. | |||||
// | // | ||||
// \returns true if all backups were removed with no error, false otherwise. | |||||
// | |||||
bool RemoveAllBackupFiles(); | |||||
void RemoveAllBackupFiles(); | |||||
/// Restore the all the specified files from the backup. | /// Restore the all the specified files from the backup. | ||||
// | // | ||||
// This method restores the backup of the files specified by the | // This method restores the backup of the files specified by the | ||||
// CreateBackupFile() method. | // CreateBackupFile() method. | ||||
// | // | ||||
// If an error is encountered, a message is output to std::cerr. | |||||
// | |||||
// \returns true if all files were restored with no error, false otherwise. | |||||
// \throws std::runtime_error if an error is encountered. | |||||
// | // | ||||
// \see CreateBackupFile(). | // \see CreateBackupFile(). | ||||
// | // | ||||
bool RestoreAllFilesFromBackup(); | |||||
private: | |||||
void RestoreAllFilesFromBackup(); | |||||
/// Get the name of the backup file. | /// Get the name of the backup file. | ||||
// | // | ||||
// | // | ||||
// \returns the name of the backup file. | // \returns the name of the backup file. | ||||
// | // | ||||
std::string GetBackupFileName(std::string File); | |||||
static std::string GetBackupFileName(std::string File); | |||||
private: | |||||
/// Copy a file. | /// Copy a file. | ||||
// | // | ||||
/// Suffix to append to the file name to obtain the backup file | /// Suffix to append to the file name to obtain the backup file | ||||
/// name. | /// name. | ||||
std::string BackupSuffix; | |||||
static const std::string BackupSuffix; | |||||
/// Typedef for container of names of files. | /// Typedef for container of names of files. | ||||
typedef std::vector<std::string> FilenameContainer; | typedef std::vector<std::string> FilenameContainer; |
## Process this file with automake to produce Makefile.in | |||||
## | |||||
## $Id: Makefile.am,v 1.2 2007/05/29 19:06:09 adeniz Exp $ | |||||
## | |||||
## automake input for the MicroNeil SNFUtility/Common tests. | |||||
## | |||||
## Author: Alban Deniz | |||||
## | |||||
## | |||||
## Copyright (C) 2012 ARM Research Labs, LLC. | |||||
## See www.armresearch.com for the copyright terms. | |||||
## | |||||
AM_CXXFLAGS = -I@top_srcdir@/SNFUtility/Common | |||||
TESTS = \ | |||||
TestFileBackup | |||||
check_PROGRAMS = \ | |||||
TestFileBackup | |||||
TestFileBackup_SOURCES = \ | |||||
TestFileBackup.cpp \ | |||||
@top_srcdir@/SNFUtility/Common/FileBackup.cpp | |||||
clean-local: | |||||
rm -f *.gcno *.gcov *.gcda *~ |
// $Id$ | |||||
// | |||||
// \file TestFileBackup.cpp | |||||
// | |||||
// Copyright (C) 2012, ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This is the unit test for the class FileBackup. | |||||
// | |||||
#include <iostream> | |||||
#include <fstream> | |||||
#include <sstream> | |||||
#include <vector> | |||||
#include <stdexcept> | |||||
#include <map> | |||||
#include <cstdlib> | |||||
#include <cstring> | |||||
#include <cerrno> | |||||
#include "FileBackup.hpp" | |||||
/// Output error. | |||||
#define Error(msg) \ | |||||
{ \ | |||||
std::cerr << "In file " << __FILE__ << ":" << __LINE__ << ": "; \ | |||||
std::cerr << msg; \ | |||||
} | |||||
/// Exit with error. | |||||
#define ErrorExit(msg) \ | |||||
{ \ | |||||
Error(msg) \ | |||||
std::exit(-1); \ | |||||
} | |||||
/// Vector of strings | |||||
typedef std::vector<std::string> StringContainer; | |||||
/// Names of files to back up. | |||||
StringContainer FileName; | |||||
/// Container for the file content. | |||||
typedef std::map<std::string, std::string> ContentContainer; | |||||
/// Content of files to back up. | |||||
ContentContainer FileContent; | |||||
/// Random characters. | |||||
const std::string RandomChar("abcdefghijklmnopqustuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+|=-"); | |||||
std::string::size_type CharLen = RandomChar.length(); | |||||
/// Unit under test. | |||||
FileBackup TestFileBackup; | |||||
/// Initialize test input. | |||||
void | |||||
Initialize() { | |||||
std::vector<int> FileSize; | |||||
FileName.push_back("File1.txt"); | |||||
FileSize.push_back(1024); | |||||
FileName.push_back("File2.txt"); | |||||
FileSize.push_back(4000); | |||||
FileName.push_back("File3.txt"); | |||||
FileSize.push_back(493); | |||||
FileName.push_back("File4.txt"); | |||||
FileSize.push_back(203043); | |||||
const char *CharPtr = RandomChar.data(); | |||||
std::vector<int>::iterator iSize = FileSize.begin(); | |||||
for (StringContainer::iterator iFile = FileName.begin(); // Create random data. | |||||
iFile != FileName.end(); | |||||
iFile++, iSize++) { | |||||
for (int iChar = 0; iChar < *iSize; iChar++) { | |||||
FileContent[*iFile].push_back(RandomChar[static_cast<std::size_t>(std::rand() * (1.0 / (RAND_MAX + 1.0 )) * CharLen)]); | |||||
} | |||||
remove(iFile->c_str()); | |||||
remove(FileBackup::GetBackupFileName(*iFile).c_str()); | |||||
std::ofstream Output; // Write the test file. | |||||
Output.open(iFile->c_str(), std::ios::trunc); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Initialize: Error opening the test file " + *iFile; | |||||
Temp += " to copy to: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output << FileContent[*iFile]; | |||||
if (Output.bad() || Output.fail()) { | |||||
std::string Temp; | |||||
Temp = "Initialize: Error writing the test file " + *iFile; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
} | |||||
} | |||||
bool | |||||
TestBackupRestore() { | |||||
for (int i = 0; i < FileName.size(); i++) { // Back up and overwrite the files. | |||||
TestFileBackup.CreateBackupFile(FileName[i]); | |||||
std::ofstream Output; | |||||
Output.open(FileName[i].c_str(), std::ios::trunc); // Overwrite the test file. | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "TestBackupRestore: Error opening the test file " + FileName[i]; | |||||
Temp += " to overwrite: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
for (int j = 0; j < 223; j++) { | |||||
Output << RandomChar[static_cast<std::size_t>(std::rand() * (1.0 / (RAND_MAX + 1.0 )) * CharLen)]; | |||||
} | |||||
if (Output.bad() || Output.fail()) { | |||||
std::string Temp; | |||||
Temp = "TestBackupRestore: Error overwriting the test file " + FileName[i]; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
} | |||||
TestFileBackup.RestoreAllFilesFromBackup(); | |||||
bool ResultIsPass = true; | |||||
for (int i = 0; i < FileName.size(); i++) { // Check content of restored files. | |||||
std::ifstream Input; | |||||
Input.open(FileName[i].c_str()); | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "TestBackupRestore: Error opening the restored file " + FileName[i]; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
std::string RestoredContent; | |||||
Input >> RestoredContent; | |||||
Input.close(); | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "TestBackupRestore: Error closing the restored file " + FileName[i]; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
if (RestoredContent != FileContent[FileName[i]]) { | |||||
std::string Temp; | |||||
Temp = "***Error--File " + FileName[i]; | |||||
Temp += " was not restored correctly.\n"; | |||||
Error(Temp); | |||||
ResultIsPass = false; | |||||
} | |||||
} | |||||
return ResultIsPass; | |||||
} | |||||
bool | |||||
TestRemoveAllBackupFiles() { | |||||
TestFileBackup.RemoveAllBackupFiles(); | |||||
bool ResultIsPass = true; | |||||
for (int i = 0; i < FileName.size(); i++) { // Check that files don't exist. | |||||
std::ifstream Input; | |||||
std::string BackupFileName; | |||||
BackupFileName = FileBackup::GetBackupFileName(FileName[i]); | |||||
Input.open(BackupFileName.c_str()); | |||||
Input.close(); | |||||
if (Input) { | |||||
std::string Temp; | |||||
Temp = "***Error--Backup file " + BackupFileName; | |||||
Temp += " was not removed.\n"; | |||||
Error(Temp); | |||||
ResultIsPass = false; | |||||
} | |||||
} | |||||
return ResultIsPass; | |||||
} | |||||
void | |||||
Finalize() { | |||||
for (int i = 0; i < FileName.size(); i++) { | |||||
remove(FileName[i].c_str()); | |||||
} | |||||
} | |||||
/// Unit tests for FileBackup. | |||||
// | |||||
// This function creates several files of varying size, and verifies | |||||
// the functionality of the FileBackup backup, restore, and delete | |||||
// functions. | |||||
// | |||||
int main(int argc, char* argv[]) { | |||||
try { // Catch anything that breaks loose. | |||||
Initialize(); // Create test files. | |||||
// Test backup/restore. | |||||
if (!TestBackupRestore()) { | |||||
ErrorExit("TestBackupRestore() failure.\n"); | |||||
} | |||||
// Test cleanup. | |||||
if (!TestRemoveAllBackupFiles()) { | |||||
ErrorExit("TestRemoveAllBackupFiles() failure.\n"); | |||||
} | |||||
Finalize(); // Remove test files. | |||||
} // That's all folks. | |||||
catch(std::exception& e) { // Report any normal exceptions. | |||||
std::cerr << "FileBackup exception: " << e.what() << std::endl; | |||||
return -1; | |||||
} | |||||
catch(...) { // Report any unexpected exceptions. | |||||
std::cerr << "Panic! Unknown Exception!" << std::endl; | |||||
return -1; | |||||
} | |||||
return 0; // Normally we return zero. | |||||
} |