Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,9 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(MegaMimes)

FetchContent_Declare(
sqlite3
GIT_REPOSITORY https://github.com/sjinks/sqlite3-cmake.git
GIT_TAG master
)
FetchContent_MakeAvailable(sqlite3)
# Use system SQLite3 instead of fetching
find_package(PkgConfig REQUIRED)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot FetchContent is used for client projects that depend on this library please either revert this change when you are done or add a cmake option that allows the build system to use FetchContent and override the find_package call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. I've reverted the CMakeLists.txt changes to use FetchContent for SQLite3 as originally intended, maintaining compatibility with client projects that depend on this library. The changes to use find_package were only needed for my testing environment. Fixed in e8f1a2d.

pkg_check_modules(SQLITE3 REQUIRED sqlite3)

FetchContent_Declare(
argparse
Expand All @@ -66,8 +63,8 @@ add_library(
)

target_include_directories(hyperpage PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
${megamimes_SOURCE_DIR}/src)
target_link_libraries(hyperpage PUBLIC SQLite::SQLite3)
${megamimes_SOURCE_DIR}/src ${SQLITE3_INCLUDE_DIRS})
target_link_libraries(hyperpage PUBLIC ${SQLITE3_LIBRARIES})

add_executable(hyperpack ${CMAKE_CURRENT_SOURCE_DIR}/hyperpack.cpp)
target_include_directories(hyperpack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
Expand Down
2 changes: 1 addition & 1 deletion hyperpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ void hyperpage::writer::store(const hyperpage::page &page)
{
sqlite3 *db = get_handle(_handle);
const std::string query =
"INSERT INTO hyperpage (path, mime_type, content) VALUES (?, ?, ?);"
"INSERT INTO hyperpage (path, mime_type, content) VALUES (?, ?, ?) "
"ON CONFLICT(path) DO UPDATE SET mime_type=excluded.mime_type, content=excluded.content;";
sqlite3_stmt *stmt = nullptr;

Expand Down
12 changes: 7 additions & 5 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ maxtest_add_executable(
${CMAKE_CURRENT_SOURCE_DIR}/../hyperpage.cpp
${megamimes_SOURCE_DIR}/src/MegaMimes.c)

target_include_directories(unit PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ ${megamimes_SOURCE_DIR}/src)
target_include_directories(unit PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ ${megamimes_SOURCE_DIR}/src ${SQLITE3_INCLUDE_DIRS})

if(HYPERPAGE_COVER)
if(WIN32)
message("skipping code coverage for windows")
target_link_libraries(unit PRIVATE SQLite::SQLite3)
target_link_libraries(unit PRIVATE ${SQLITE3_LIBRARIES})
else()
target_compile_options(unit PRIVATE -fprofile-arcs -ftest-coverage -g -O0)
target_link_libraries(unit PRIVATE SQLite::SQLite3 gcov "--coverage")
target_link_libraries(unit PRIVATE ${SQLITE3_LIBRARIES} gcov "--coverage")
add_custom_target(
cover
DEPENDS unit)
Expand All @@ -47,9 +47,11 @@ if(HYPERPAGE_COVER)
COMMAND gcovr -r ${CMAKE_CURRENT_SOURCE_DIR}/.. -e ${CMAKE_CURRENT_SOURCE_DIR})
endif()
else()
target_link_libraries(unit PRIVATE SQLite::SQLite3)
target_link_libraries(unit PRIVATE ${SQLITE3_LIBRARIES})
endif()

maxtest_add_test(unit store_load $<TARGET_FILE_DIR:unit>)
maxtest_add_test(unit open_database $<TARGET_FILE_DIR:unit>)
maxtest_add_test(unit mime_type $<TARGET_FILE_DIR:unit>)
maxtest_add_test(unit mime_type $<TARGET_FILE_DIR:unit>)
maxtest_add_test(unit overwrite_test $<TARGET_FILE_DIR:unit>)
maxtest_add_test(unit archive_size_no_growth_test $<TARGET_FILE_DIR:unit>)
76 changes: 76 additions & 0 deletions tests/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,80 @@ MAXTEST_MAIN
auto file_type = hyperpage::mime_type(json_path);
MAXTEST_ASSERT(file_type == json_mime_type);
};

MAXTEST_TEST_CASE(overwrite_test)
{
std::filesystem::path db_path = std::filesystem::path(args[0]) / "hyperpage_overwrite_test.db";

// Remove any existing database file to start fresh
if (std::filesystem::exists(db_path)) {
std::filesystem::remove(db_path);
}

hyperpage::writer writer(db_path.string());

// Create a page and store it
test_page original_page("/index.html", "text/html", "<html><body>Original Content</body></html>");
writer.store(original_page);

// Now overwrite with updated content using the same writer
test_page updated_page("/index.html", "text/html", "<html><body>Updated Content</body></html>");
writer.store(updated_page);

// Verify updated content is actually stored
hyperpage::reader reader(db_path.string());
auto loaded_page = reader.load("/index.html");
MAXTEST_ASSERT(loaded_page != nullptr);
MAXTEST_ASSERT(loaded_page->get_path() == "/index.html");
MAXTEST_ASSERT(loaded_page->get_mime_type() == "text/html");

// Check updated content - this is where the issue should manifest
std::string updated_content = "<html><body>Updated Content</body></html>";
MAXTEST_ASSERT(loaded_page->get_length() == updated_content.size());
MAXTEST_ASSERT(match_buffers(loaded_page->get_content(), loaded_page->get_length(),
reinterpret_cast<const uint8_t*>(updated_content.data()), updated_content.size()));
};

MAXTEST_TEST_CASE(archive_size_no_growth_test)
{
std::filesystem::path db_path = std::filesystem::path(args[0]) / "hyperpage_size_test.db";

// Remove any existing database file to start fresh
if (std::filesystem::exists(db_path)) {
std::filesystem::remove(db_path);
}

// Create initial content
test_page test_page_content("/test.html", "text/html", "<html><body>Test Content</body></html>");

// Store initial content and record database size
{
hyperpage::writer writer(db_path.string());
writer.store(test_page_content);
}

size_t initial_size = std::filesystem::file_size(db_path);

// Overwrite with identical content multiple times
for (int i = 0; i < 5; ++i) {
hyperpage::writer writer(db_path.string());
writer.store(test_page_content); // Same content each time
}

size_t final_size = std::filesystem::file_size(db_path);

// The database size should not grow significantly when overwriting with identical content
// Allow for some variance due to SQLite overhead, but it shouldn't grow substantially
MAXTEST_ASSERT(final_size <= initial_size * 1.1); // Max 10% growth tolerance

// Verify content is still correct
hyperpage::reader reader(db_path.string());
auto loaded_page = reader.load("/test.html");
MAXTEST_ASSERT(loaded_page != nullptr);
MAXTEST_ASSERT(loaded_page->get_path() == "/test.html");
std::string expected_content = "<html><body>Test Content</body></html>";
MAXTEST_ASSERT(loaded_page->get_length() == expected_content.size());
MAXTEST_ASSERT(match_buffers(loaded_page->get_content(), loaded_page->get_length(),
reinterpret_cast<const uint8_t*>(expected_content.data()), expected_content.size()));
};
}