From 3b95dd5a341d37a1bf09434b0107bcae628e431b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Fri, 24 Jul 2026 17:15:26 +0200 Subject: [PATCH 1/3] Add tests for Statement::RowIterator to fix coverage regression Add unit tests for Statement::RowIterator operator++(int) and operator== that were not covered by the range-based for loop tests in PR #545. --- tests/Statement_test.cpp | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index 2762e9ab..df03c415 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -1102,6 +1102,67 @@ TEST(Statement, rangeBasedForWithBind) EXPECT_EQ(2, rowCount); } +TEST(Statement, rowIteratorDirectUsage) +{ + // Create a new database + SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, val INTEGER)")); + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (1, 10)")); + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (2, 20)")); + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (3, 30)")); + + SQLite::Statement query(db, "SELECT id, val FROM test ORDER BY id"); + + // Test direct usage of begin() and end() + auto it = query.begin(); + auto endIt = query.end(); + + // Test operator!= (already covered by range-based for, but explicit test for clarity) + int count = 0; + while (it != endIt) + { + ++count; + EXPECT_EQ(count, (*it).getColumn(0).getInt()); + ++it; + } + EXPECT_EQ(3, count); + + // Reset and test post-increment operator + it = query.begin(); + count = 0; + while (it != endIt) + { + ++count; + EXPECT_EQ(count, (*it).getColumn(0).getInt()); + it++; + } + EXPECT_EQ(3, count); + + // Test operator== with end iterator + it = query.end(); + EXPECT_TRUE(it == endIt); + EXPECT_FALSE(it != endIt); + + // Test operator== and operator!= with end iterator obtained from a different call + SQLite::Statement query2(db, "SELECT id, val FROM test ORDER BY id"); + auto it2 = query2.end(); + EXPECT_TRUE(it == it2); + EXPECT_FALSE(it != it2); + + // Test operator!= with different statements + SQLite::Statement query3(db, "SELECT id, val FROM test ORDER BY id"); + auto it3 = query3.begin(); + auto endIt3 = query3.end(); + EXPECT_TRUE(it3 != endIt3); + EXPECT_FALSE(it3 == endIt3); + + // Advance to end and check equality + while (it3 != endIt3) + ++it3; + EXPECT_TRUE(it3 == endIt3); + EXPECT_FALSE(it3 != endIt3); +} + #endif // C++11 TEST(Statement, getBindParameterCount) From 01e0866c24ec16b8a7664d88ce86e8003646b30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Fri, 24 Jul 2026 17:23:07 +0200 Subject: [PATCH 2/3] Update CHANGELOG for PR #562 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a54f738..de914232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -313,3 +313,4 @@ Version 3.4.0 - 2026 ??? - Fix Transaction destructor to catch all exceptions to avoid std::terminate (#559) - Fix the Meson build when the SQLITECPP_DISABLE_STD_FILESYSTEM option is enabled (#560) - Add Statement::RowIterator to support range-based for loops over query results (#181) +- Add unit tests for Statement::RowIterator to fix coverage regression (#562) From b9a400fa659319cd3c3409bfbe9a238747a0aed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Fri, 24 Jul 2026 17:23:41 +0200 Subject: [PATCH 3/3] Clarify CHANGELOG update workflow in sqlitecpp-workflow skill - Emphasize that CHANGELOG updates must be in a separate commit - Add explicit workflow steps for when to update CHANGELOG - Clarify that PR number must be known before committing CHANGELOG --- .claude/skills/sqlitecpp-workflow/SKILL.md | 27 +++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/.claude/skills/sqlitecpp-workflow/SKILL.md b/.claude/skills/sqlitecpp-workflow/SKILL.md index e33eb720..b8ed00e6 100644 --- a/.claude/skills/sqlitecpp-workflow/SKILL.md +++ b/.claude/skills/sqlitecpp-workflow/SKILL.md @@ -11,14 +11,14 @@ description: >- - [ ] Public API has Doxygen (`@brief`, `@param`, `@return`, `@throw`). - [ ] Tests added under `tests/`. - [ ] Build files updated (`CMakeLists.txt`, `meson.build`). -- [ ] `CHANGELOG.md` updated for user-facing changes. +- [ ] `CHANGELOG.md` updated for user-facing changes (in a **separate commit** after opening the PR). ## CHANGELOG conventions -Update `CHANGELOG.md` in the same PR that makes the change, not in a later batch. Add one line per -PR under the current unreleased version heading (`Version X.Y.Z - ???`). Create that heading -if it does not exist yet. +Update `CHANGELOG.md` in the same PR that makes the change, but **in a separate commit** created after +the PR is opened so the PR number is known. Add one line per PR under the current unreleased +version heading (`Version X.Y.Z - ???`). Create that heading if it does not exist yet. -- One bullet per PR: `- (#NNN)`. The PR number is the last token, in parentheses. +- One bullet per PR: `- (#NNN)`. The PR number is the **last token**, in parentheses. - Write in the imperative mood, present tense: "Add", "Fix", "Update", "Remove". Not "Added", "Fixes", or "Adding". - Keep each entry to a single line that names the user-facing effect, not the internal mechanics. @@ -32,6 +32,15 @@ if it does not exist yet. Finalizing the version heading and tagging belong to the release process: see [[sqlitecpp-release]]. +**Workflow for CHANGELOG updates:** +1. Commit source code changes (tests, implementation, etc.) in one or more atomic commits +2. Push the branch and open the PR to obtain the PR number +3. Create a separate commit adding only the CHANGELOG entry with the PR number +4. Push the CHANGELOG commit to the same branch + +This keeps commits atomic (CHANGELOG is separate from code) and allows the PR number to be +included in the CHANGELOG entry. + ## Pull requests - Open PRs with `gh pr create` against `master`. - The maintainer wants a **short and tight** PR description: one or two sentences on what the PR @@ -40,6 +49,7 @@ Finalizing the version heading and tagging belong to the release process: see ## Git commits and pushing - Make **small, atomic commits** that each address a single logical change. Do not mix unrelated changes (e.g., bug fix + feature + formatting) in one commit. +- **CHANGELOG.md updates must be in a separate commit** from source code changes, created after the PR is opened so the PR number can be included. - Each commit should be **complete and self-contained**: it must compile and pass tests independently. - Before pushing a branch to the remote, **ask the user for explicit permission** stating the branch name and action (e.g., "Push branch `update-sqlite-3.52.2` to origin?"). Push only after receiving approval. @@ -47,7 +57,9 @@ Finalizing the version heading and tagging belong to the release process: see 1. Declare in `include/SQLiteCpp/.h` with Doxygen. 2. Implement in `src/.cpp`. 3. Add tests in `tests/_test.cpp`. -4. Update `CHANGELOG.md`. +4. Commit the changes from steps 1-3. +5. Push the branch and open the PR. +6. Add CHANGELOG entry with the PR number in a separate commit. ## Add a class 1. Create `include/SQLiteCpp/NewClass.h` and `src/NewClass.cpp`. @@ -56,3 +68,6 @@ Finalizing the version heading and tagging belong to the release process: see 4. Include in `SQLiteCpp.h` if public API. 5. Create `tests/NewClass_test.cpp`. 6. Add test to `CMakeLists.txt` and `meson.build`. +7. Commit all changes from steps 1-6. +8. Push the branch and open the PR. +9. Add CHANGELOG entry with the PR number in a separate commit.