Skip to content

test: add coverage for readTemplates, writeTemplates, getFolderTemplate#1496

Merged
annejan merged 5 commits into
mainfrom
test/util-template-tests
May 16, 2026
Merged

test: add coverage for readTemplates, writeTemplates, getFolderTemplate#1496
annejan merged 5 commits into
mainfrom
test/util-template-tests

Conversation

@nogeenharrie
Copy link
Copy Markdown
Contributor

@nogeenharrie nogeenharrie commented May 16, 2026

Summary

Three Util methods had zero test coverage despite non-trivial parsing logic:

readTemplates (5 tests) — INI-style .templates file parser:

  • Missing file → empty hash
  • Single section with fields parsed correctly
  • Multiple sections parsed into separate entries
  • Empty section name [] ignored (triggers expected qWarning)
  • Comment lines starting with # skipped

writeTemplates (3 tests) — writes templates hash to disk:

  • Round-trip: writeread yields identical data
  • Empty hash writes cleanly and reads back empty
  • Sections written in alphabetical key order

getFolderTemplate (4 tests) — walks directory tree for .default_template:

  • Found in current directory
  • Found in parent directory (tree walk)
  • Not found anywhere → empty string
  • File containing only a comment → empty string

Test plan

  • make check passes locally: 123 → 136 tests, 0 failures (4 skipped = existing Unix-only socket tests)
  • clang-format --style=file applied

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added comprehensive unit tests for template file handling: missing files, single/multiple sections, ignoring empty sections and comments, write/read round-trips and empty writes, ensuring written sections are sorted, and folder-level default-template lookup (current folder, parent, none found, comment-only ignored).
  • Bug Fixes

    • Made folder-level default-template lookup more consistent across platforms by normalizing directory path comparisons.

Review Change Stack

readTemplates (4 tests):
- missing .templates file returns empty hash
- single section with multiple fields parsed correctly
- multiple sections parsed into separate hash entries
- empty section name [] is ignored with a warning
- comment lines (#) are skipped

writeTemplates (3 tests):
- round-trip: write then read yields identical data
- empty hash writes successfully and reads back empty
- sections are written in alphabetical key order

getFolderTemplate (4 tests):
- .default_template in the current directory is found
- .default_template in a parent directory is found
- no .default_template anywhere returns empty string
- .default_template containing only a comment returns empty string

Total util tests: 123 → 136

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: c38c1876-e439-488c-84c4-e1a2c53b76d4

📥 Commits

Reviewing files that changed from the base of the PR and between ccbf891 and 816e7f6.

📒 Files selected for processing (1)
  • tests/auto/mainwindow/mainwindow.pro

📝 Walkthrough

Walkthrough

Adds 12 unit tests covering Util::readTemplates, Util::writeTemplates, and Util::getFolderTemplate, and changes a path-prefix check in Util::getFolderTemplate to use a hard-coded forward slash.

Changes

Template Utility Tests & getFolderTemplate tweak

Layer / File(s) Summary
Test slot declarations
tests/auto/util/tst_util.cpp
Declared private Qt test slots for .templates parsing/writing and .default_template folder-resolution scenarios.
getFolderTemplate path-prefix tweak
src/util.cpp
Removed use of platform QDir::separator() and changed the store-boundary prefix check to use "/" when testing whether a path is inside the store.
readTemplates / writeTemplates tests
tests/auto/util/tst_util.cpp
Added tests verifying .templates parsing (missing file, single/multiple sections, empty-section ignored, comments ignored) and writing (round-trip, empty hash, alphabetical key ordering).
getFolderTemplate tests
tests/auto/util/tst_util.cpp
Added tests verifying .default_template resolution in current and parent folders, not-found behavior, and ignoring comment-only files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • IJHack/QtPass#1142: The main PR adds unit tests for Util::readTemplates/Util::getFolderTemplate (template parsing and default-template resolution) that directly underpin PR #1142’s new logic to load templates and determine the folder default when creating a new password.
  • IJHack/QtPass#1141: The main PR extends unit tests for the new template utilities and also tweaks Util::getFolderTemplate() path-prefix logic—directly overlapping with the retrieved PR’s introduction of Util::readTemplates, Util::writeTemplates, and Util::getFolderTemplate for .templates/.default_template handling.

Suggested labels

size:M

Suggested reviewers

  • annejan

Poem

🐰 I hopped through templates, lines and keys,
wrote fixtures, read back with nimble ease.
Sections found and comments left behind,
defaults in parents I did find.
A carrot cheer for tests aligned!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and accurately describes the main change: adding unit test coverage for three template-related Util functions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/util-template-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/auto/util/tst_util.cpp`:
- Around line 2567-2568: The current QVERIFY2 check using
content.indexOf("[alpha]") < content.indexOf("[zebra]") can falsely pass if one
or both markers are missing (indexOf returns -1); update the test in
tst_util.cpp to first assert both markers exist (e.g.,
QVERIFY(content.indexOf("[alpha]") != -1) and QVERIFY(content.indexOf("[zebra]")
!= -1) or a combined QVERIFY2 that checks presence) and only then perform the
ordering assertion using content.indexOf("[alpha]") < content.indexOf("[zebra]")
so the test fails if either section is missing.
- Around line 2501-2514: Add an explicit expectation for the warning emitted
when an empty section is encountered: before calling
Util::readTemplates(tmp.path()) in tst_util::readTemplatesEmptySectionIgnored(),
call QTest::ignoreMessage(...) (e.g. QtWarningMsg) with the warning text or a
substring that the Util::readTemplates implementation emits for empty section
names so the test asserts the warning side-effect as well as the parsed output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6e3d3a01-c8b8-43f1-9982-7d54fdfe752f

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc3bd0 and f649819.

📒 Files selected for processing (1)
  • tests/auto/util/tst_util.cpp

Comment thread tests/auto/util/tst_util.cpp
Comment thread tests/auto/util/tst_util.cpp
writeTemplatesSortedKeys: indexOf returns -1 for missing markers, so
-1 < positivePos would silently pass. Add explicit presence checks for
both [alpha] and [zebra] before the ordering assertion.

readTemplatesEmptySectionIgnored: add QTest::ignoreMessage(QtWarningMsg)
before calling readTemplates so the expected qWarning is asserted as a
test side-effect rather than just leaking to stderr.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coveralls
Copy link
Copy Markdown

coveralls commented May 16, 2026

Coverage Status

coverage: 54.868% (+0.9%) from 53.977% — test/util-template-tests into main

QDir::cleanPath() normalizes separators to '/' on all platforms, but
QDir::separator() returns '\' on Windows, causing the startsWith guard
to never match on Windows and preventing parent-directory traversal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/util.cpp`:
- Around line 684-685: The ancestry check incorrectly appends "/" to
cleanStoreAbs unconditionally, causing double slashes for root store paths and
breaking currentPath.startsWith; update the guard in the loop (where
currentPath, cleanStoreAbs and startsWith are used) to allow either currentPath
== cleanStoreAbs or currentPath.startsWith(cleanStoreAbs + "/") (or equivalently
check startsWith(cleanStoreAbs) and then ensure either equal or the next
character is '/'), so root paths like "/" or "C:/" are handled correctly without
producing "//" or "C://".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: ed5f3f1f-7d96-4f8e-8a44-6bc7f8a188bc

📥 Commits

Reviewing files that changed from the base of the PR and between f0523f5 and 6a8798f.

📒 Files selected for processing (1)
  • src/util.cpp

Comment thread src/util.cpp Outdated
Appending "/" to cleanStoreAbs produces "//" when the store is at the
filesystem root ("/"), causing startsWith to never match. Check the
character at cleanStoreAbs.length() instead to safely distinguish a
proper subdirectory from a sibling with a longer name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/util.cpp (1)

684-686: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Root store paths still break the ancestry check.

The new approach still fails when cleanStoreAbs is a filesystem root like "/" or "C:/". For example, if the password store is at "/" and the current path is "/passwords":

  • Line 684: currentPath.startsWith("/") → true
  • Line 685: 10 <= 1 → false
  • Line 686: currentPath.at(1)'p''p' != '/' → true

The condition evaluates to true and breaks, incorrectly stopping the search even though "/passwords" is a valid descendant of "/".

The issue is that for root paths, cleanStoreAbs.length() points to the first character of the subdirectory name, not a separator. As per coding guidelines, boundary checks must correctly prevent sibling-path matches across all valid store locations.

🐛 Proposed fix using conditional storePrefix
-    if (!currentPath.startsWith(cleanStoreAbs) ||
-        currentPath.length() <= cleanStoreAbs.length() ||
-        currentPath.at(cleanStoreAbs.length()) != QChar('/')) {
+    const QString storePrefix = cleanStoreAbs.endsWith(QLatin1Char('/'))
+                                    ? cleanStoreAbs
+                                    : cleanStoreAbs + QLatin1Char('/');
+    if (!currentPath.startsWith(storePrefix)) {
       break;
     }

This ensures that root paths like "/" use "/" as the prefix (no double-slash), while non-root paths like "/home/user/store" correctly use "/home/user/store/".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/util.cpp` around lines 684 - 686, The ancestry check fails for root
stores because it indexes at cleanStoreAbs.length() assuming a separator there;
instead construct a storePrefix that guarantees a trailing separator
(storePrefix = cleanStoreAbs.endsWith('/') ? cleanStoreAbs : cleanStoreAbs +
'/') and then replace the current three-part condition with a single check that
currentPath is either exactly cleanStoreAbs or startsWith(storePrefix) (i.e. if
(!(currentPath == cleanStoreAbs || currentPath.startsWith(storePrefix)) ) { ...
}). Update the check around currentPath and cleanStoreAbs/currentPath.startsWith
to use these symbols so root paths like "/" or "C:/" are handled correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/util.cpp`:
- Around line 684-686: The ancestry check fails for root stores because it
indexes at cleanStoreAbs.length() assuming a separator there; instead construct
a storePrefix that guarantees a trailing separator (storePrefix =
cleanStoreAbs.endsWith('/') ? cleanStoreAbs : cleanStoreAbs + '/') and then
replace the current three-part condition with a single check that currentPath is
either exactly cleanStoreAbs or startsWith(storePrefix) (i.e. if (!(currentPath
== cleanStoreAbs || currentPath.startsWith(storePrefix)) ) { ... }). Update the
check around currentPath and cleanStoreAbs/currentPath.startsWith to use these
symbols so root paths like "/" or "C:/" are handled correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 420e20bd-1b8f-4020-9a94-cbe763e9643f

📥 Commits

Reviewing files that changed from the base of the PR and between 6a8798f and ccbf891.

📒 Files selected for processing (1)
  • src/util.cpp

All other test .pro files use 'LIBS = ... $$LIBS' so that -lqtpass
comes before the Windows system libs (-lmpr, -lbcrypt) accumulated from
qtpass.pri. mainwindow.pro used 'LIBS +=' which placed the system libs
first, causing 'undefined reference to WNetUseConnectionA' on MinGW.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 49.86%. Comparing base (2bc3bd0) to head (816e7f6).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1496      +/-   ##
==========================================
+ Coverage   48.60%   49.86%   +1.25%     
==========================================
  Files          44       44              
  Lines        4386     4386              
==========================================
+ Hits         2132     2187      +55     
+ Misses       2254     2199      -55     
Flag Coverage Δ
qtpass 49.86% <100.00%> (+1.25%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@annejan annejan merged commit b2df519 into main May 16, 2026
27 checks passed
@annejan annejan deleted the test/util-template-tests branch May 16, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants