-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This was caused by my stupidity to not correctly use the C API. I didn't call `cppIni_close` before leaving the test cases. This caused some dangling pointers and open file handles ultimately resulting in a crash of the test executable.
- Loading branch information
Showing
6 changed files
with
122 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,28 @@ | ||
// cppIni - A C++20 library for reading and writing INI files | ||
// Copyright (C) 2023-2024 Nils Hofmann <[email protected]> | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
/* | ||
* cppIni - A C++20 library for reading and writing INI files | ||
* Copyright (C) 2023-2024 Nils Hofmann <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <array> | ||
#include <filesystem> | ||
#include <format> | ||
|
||
#include <cppIni/cppIni_c.h> | ||
#include <doctest/doctest.h> | ||
#include "utils.h" | ||
|
||
static const std::string fileName = std::format("{}{}", WORKING_DIR, "/res/test.ini");; | ||
|
||
|
@@ -33,67 +36,50 @@ TEST_CASE("Construction of File object") | |
CHECK_NOTHROW(cppIni_close(&file)); | ||
} | ||
|
||
struct ScopeGuard | ||
{ | ||
ScopeGuard(pFile file) : file(file){}; | ||
~ScopeGuard(){ cppIni_close(&file); }; | ||
pFile file; | ||
}; | ||
|
||
TEST_CASE("Read a string entry") | ||
{ | ||
void* file = cppIni_open(fileName.c_str()); | ||
ScopeGuard guard{file}; | ||
auto file = utils::ScopeGuard<void*, cppIni_close>(cppIni_open(fileName.c_str())); | ||
|
||
std::array<char, 64> buffer{0}; | ||
cppIni_gets(file, "Section1", "Entry1", buffer.data(), buffer.size()); | ||
cppIni_gets(*file, "Section1", "Entry1", buffer.data(), buffer.size()); | ||
|
||
CHECK_EQ(std::string_view{buffer.data()}, "Value1"); | ||
} | ||
|
||
TEST_CASE("Try to read a non-existing entry") | ||
{ | ||
void* file = cppIni_open(fileName.c_str()); | ||
ScopeGuard guard{file}; | ||
auto file = utils::ScopeGuard<void*, cppIni_close>(cppIni_open(fileName.c_str())); | ||
|
||
std::array<char, 64> buffer{0}; | ||
CHECK_EQ(cppIni_gets(file, "Section1", "NonExistingEntry", buffer.data(), buffer.size()), buffer.data()); | ||
CHECK_EQ(cppIni_gets(*file, "Section1", "NonExistingEntry", buffer.data(), buffer.size()), buffer.data()); | ||
CHECK_EQ(buffer[0], '\0'); | ||
} | ||
|
||
TEST_CASE("Change a value") | ||
{ | ||
constexpr auto tempFileName = "tmp.ini"; | ||
std::filesystem::copy_file(fileName, tempFileName); | ||
|
||
{ | ||
constexpr auto newValue = 1337; | ||
void* file = cppIni_open(tempFileName); | ||
ScopeGuard guard{file}; | ||
constexpr auto newValue = 1337; | ||
|
||
const auto previousValue = cppIni_geti(file, "Section1", "IntEntry"); | ||
CHECK_NE(previousValue, newValue); | ||
cppIni_set(file, "Section1", "IntEntry", std::to_string(newValue).c_str()); | ||
CHECK_EQ(cppIni_geti(file, "Section1", "IntEntry"), newValue); | ||
} | ||
utils::TempFile tmpFile(fileName); | ||
auto file = utils::ScopeGuard<void*, cppIni_close>(cppIni_open(tmpFile.filename().data())); | ||
|
||
std::filesystem::remove(tempFileName); | ||
const auto previousValue = cppIni_geti(*file, "Section1", "IntEntry"); | ||
CHECK_NE(previousValue, newValue); | ||
cppIni_set(*file, "Section1", "IntEntry", std::to_string(newValue).c_str()); | ||
CHECK_EQ(cppIni_geti(*file, "Section1", "IntEntry"), newValue); | ||
} | ||
|
||
TEST_CASE("Read an integer entry") | ||
{ | ||
void* file = cppIni_open(fileName.c_str()); | ||
ScopeGuard guard{file}; | ||
auto file = utils::ScopeGuard<void*, cppIni_close>(cppIni_open(fileName.c_str())); | ||
|
||
CHECK_EQ(cppIni_geti(file, "Section1", "IntEntry"), 42); | ||
CHECK_EQ(cppIni_geti(*file, "Section1", "IntEntry"), 42); | ||
} | ||
|
||
TEST_CASE("Read a floating point value entry") | ||
{ | ||
void* file = cppIni_open(fileName.c_str()); | ||
ScopeGuard guard{file}; | ||
auto file = utils::ScopeGuard<void*, cppIni_close>(cppIni_open(fileName.c_str())); | ||
|
||
CHECK_LT(std::abs(cppIni_getf(file, "Section1.Subsection1", "DoubleEntry") - 3.1415), 0.001); | ||
CHECK_LT(std::abs(cppIni_getf(*file, "Section1.Subsection1", "DoubleEntry") - 3.1415), 0.001); | ||
} | ||
|
||
TEST_SUITE_END(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* | ||
* cppIni - A C++20 library for reading and writing INI files | ||
* Copyright (C) 2023 Nils Hofmann <[email protected]> | ||
* Copyright (C) 2023-2024 Nils Hofmann <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|
@@ -21,26 +21,14 @@ | |
#include <doctest/doctest.h> | ||
|
||
#include <cppIni/File.h> | ||
#include "utils.h" | ||
|
||
using namespace std::literals; | ||
|
||
static const std::string fileName = std::format("{}{}", WORKING_DIR, "/res/test.ini"); | ||
|
||
TEST_SUITE_BEGIN("File"); | ||
|
||
class FileFixture | ||
{ | ||
public: | ||
FileFixture() { | ||
std::filesystem::copy_file(::fileName, fileName); | ||
} | ||
~FileFixture() { | ||
std::filesystem::remove(fileName); | ||
} | ||
protected: | ||
const std::string fileName = std::format("{}{}", WORKING_DIR, "/res/tmp.ini"); | ||
}; | ||
|
||
TEST_CASE("Failing construction of an empty File object") | ||
{ | ||
CHECK_THROWS(File{""}); | ||
|
@@ -145,15 +133,16 @@ TEST_CASE("Equality operator") | |
CHECK_EQ(f, f2); | ||
} | ||
|
||
TEST_CASE_FIXTURE(FileFixture, "Change a value with set") | ||
TEST_CASE("Change a value with set") | ||
{ | ||
constexpr auto newValue = "NewValue"sv; | ||
|
||
auto f = File{fileName}; | ||
utils::TempFile tmpFile(fileName); | ||
auto f = File{tmpFile.filename()}; | ||
f.set("Section1", "Entry1", "NewValue"); | ||
CHECK_EQ(f.get<std::string_view>("Section1", "Entry1"), newValue); | ||
|
||
const auto f2 = File{fileName}; | ||
const auto f2 = File{tmpFile.filename()}; | ||
CHECK_EQ(f.get<std::string_view>("Section1", "Entry1"), newValue); | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* cppIni - A C++20 library for reading and writing INI files | ||
* Copyright (C) 2024 Nils Hofmann <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <filesystem> | ||
|
||
namespace utils | ||
{ | ||
|
||
/// \brief Class for managing lifetime of a pointer | ||
/// | ||
/// \details This class is a RAII wrapper for raw pointers. It is intended to be used as automatic variable in a function | ||
/// or as non-static data member in a class. It takes ownership of the pointer and deletes the managed object | ||
/// when it goes out of scope. | ||
/// | ||
/// \tparam T The type of the object managed by the pointer | ||
template<class T, void(* Deleter)(T*)> | ||
class ScopeGuard | ||
{ | ||
public: | ||
explicit ScopeGuard(T obj) : m_obj(obj) {} | ||
~ScopeGuard() { Deleter(&m_obj); } | ||
|
||
T& operator*() { return m_obj; } | ||
|
||
private: | ||
T m_obj; | ||
}; | ||
|
||
/// \brief Class for managing the lifetime of a temporary copy of a file | ||
/// | ||
/// \details This class is a RAII wrapper for a temporary file. It is intended to be used as automatic variable in a | ||
/// function or as non-static data member in a class. It takes ownership of the file and deletes the file | ||
/// when it goes out of scope. The file is copied during construction. | ||
class TempFile | ||
{ | ||
public: | ||
explicit TempFile(const std::string& fileName) | ||
{ | ||
std::filesystem::copy(fileName, filename()); | ||
} | ||
~TempFile() | ||
{ | ||
std::filesystem::remove(filename()); | ||
} | ||
|
||
constexpr static std::string_view filename() { return "tmp.ini"; } | ||
}; | ||
} |