Skip to content

[codex] increase coverage for cli scan and import pipelines - #276

Merged
fernandotonon merged 3 commits into
masterfrom
codex/coverage-over-80-again
Apr 10, 2026
Merged

[codex] increase coverage for cli scan and import pipelines#276
fernandotonon merged 3 commits into
masterfrom
codex/coverage-over-80-again

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Apr 10, 2026

Copy link
Copy Markdown
Owner

Summary

Increase test coverage for CLI scan/import flows, scan-engine rule handling, and Assimp/transform edge cases.

Technical Details

  • Added targeted tests in:
    • src/Assimp/BoneProcessor_test.cpp
    • src/Assimp/MaterialProcessor_test.cpp
    • src/CLIPipeline_test.cpp
    • src/MeshImporterExporter_test.cpp
    • src/ScanEngine_test.cpp
    • src/TransformOperator_test.cpp
  • Added cross-platform missing-path construction in CLI tests (no hardcoded /tmp).
  • Made nonexistent scan-root coverage test platform-portable.
  • Kept animated fixture coverage strict (assert present) to avoid skipped-test CI policy violations.

✨ Features

  • Expanded branch coverage for CLI pose and scan command validation/report paths.
  • Expanded scan-engine formatter/rule/fix/integration coverage.

🐛 Bugfixes

  • Fixed test portability issues across Linux/macOS/Windows by replacing hardcoded POSIX-only paths.
  • Clarified unknown conversion-case expectation in ScanEngine tests.

Validation

  • cmake --build build_cov_local -j$(nproc) --target UnitTests
  • QT_QPA_PLATFORM=offscreen ./build_cov_local/debug/UnitTests --gtest_filter='BoneProcessorTest.*:MaterialProcessorTest.*:CLIPipelineCmdPoseError.*:CLIPipelineCmdScan*.*:ScanEngineTest.*:ScanConfigTest.*:TransformOperatorTests.Pivot*:MeshImporterExporterStandaloneTest.FormatFileURI_HumanReadableUnknownFormatDoesNotAppend:MeshImporterExporterStandaloneTest.FormatFileURI_ShortAliasUppercaseIsAppendedAsGiven'

Summary by CodeRabbit

  • Tests
    • Comprehensive test expansion across multiple components: bone processing, material handling, CLI pipeline operations, mesh import/export functionality, scan engine workflows, and transform operations.
    • Added test coverage for error conditions, file operations, format conversions, naming conventions, case-sensitivity matching, and pivot-mode cycling.
    • Introduced utility helpers for test file generation and data directory resolution.

@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds many unit tests across multiple modules: bone/material processing, CLI pipeline, mesh import/export, scan engine, and transform operator pivot behavior; no public API changes.

Changes

Cohort / File(s) Summary
Assimp Bone Tests
src/Assimp/BoneProcessor_test.cpp
Added tests for bakeZupToYup rotation on root bones and animation-only hierarchies creating animated bones and leaf children.
Assimp Material Tests
src/Assimp/MaterialProcessor_test.cpp
Added tests ensuring existing materials without normal maps are returned unchanged and unnamed materials are imported with sequential importedMaterialN names.
CLI Pipeline Tests
src/CLIPipeline_test.cpp
Added helper writeMinimalObj and many cmdPose/cmdScan error-path and success tests, including report/SARIF generation and --fail-on behavior.
Mesh Importer/Exporter Tests
src/MeshImporterExporter_test.cpp
Extended formatFileURI coverage for unknown format strings and uppercase extension alias handling.
Scan Engine Tests
src/ScanEngine_test.cpp
Large set of tests: naming conventions, missing-directory handling, rule evaluation (including load-error short-circuit), formatters (JSON/text/SARIF), glob ? matching, apply-fixes and run flows, and asset inspection helpers.
Transform Operator Tests
src/TransformOperator_test.cpp
Added pivot-mode cycling/signal tests, empty-selection pivot point, and pivot-point calculations for multiple pivot modes.

Sequence Diagram(s)

(omitted — changes are test additions and do not introduce new multi-component runtime control flow)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nibble through tests late at night,

Bones that spin and pivots just right,
Scanners sing reports in JSON light,
Meshes named tidy, extensions polite,
I hop, I assert — the suite is bright!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: increasing test coverage for CLI scan and import pipelines, which aligns with the comprehensive test additions across six test files.
Description check ✅ Passed The description is mostly complete with a clear summary, technical details listing all modified files, features, bugfixes, and validation commands. It follows the template structure with all major sections covered.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/coverage-over-80-again

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.

@fernandotonon
fernandotonon marked this pull request as ready for review April 10, 2026 04:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
website/src/data/content.js (1)

61-82: Note: 5 use cases in a 4-column grid will wrap unevenly.

The useCases array has 5 items rendered in a 4-column grid (.useCaseGrid). This results in 4 cards on the first row and 1 orphan card on the second row, which may look visually unbalanced.

This is a minor visual concern — consider whether 4 or 6 items would provide a cleaner layout, or adjust the grid to 5 columns if intentional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/data/content.js` around lines 61 - 82, The useCases array
contains 5 items which renders awkwardly in the 4-column .useCaseGrid causing a
single orphan card; update the UI by either adding or removing an item in the
useCases array to make it 4 or 6 entries, or change the grid layout to
accommodate 5 columns (adjust the .useCaseGrid CSS) so cards align evenly;
locate and edit the useCases export in content.js or the .useCaseGrid rules in
your stylesheet to implement the chosen fix.
website/src/App.jsx (1)

374-381: Consider simplifying the tag assignment logic.

The current includes() checks work but are fragile — they depend on specific substrings appearing in titles. If a future feature title contains "AI" or "MCP" unintentionally, it would get the wrong tag.

♻️ Consider adding a `tag` property directly to highlightFeatures data

In content.js, add the tag to each feature object:

export const highlightFeatures = [
  { title: 'Scene save/load', body: '...', tag: 'Feature' },
  { title: 'Material tools', body: '...', tag: 'Feature' },
  { title: 'REST API', body: '...', tag: 'Feature' },
  { title: 'MCP / AI agent integration', body: '...', tag: 'Advanced' }
];

Then in App.jsx:

-                  tag={feature.title.includes('AI') || feature.title.includes('MCP') ? 'Advanced' : 'Feature'}
+                  tag={feature.tag}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/App.jsx` around lines 374 - 381, The tag assignment is fragile;
update the highlightFeatures data (e.g., in content.js) to include an explicit
tag property for each feature (e.g., tag: 'Advanced' or 'Feature'), then modify
App.jsx where highlightFeatures is mapped to pass feature.tag into the
FeatureCard (replace the title.includes('AI')/includes('MCP') logic with
feature.tag). Ensure FeatureCard continues to accept a tag prop and provide a
sensible default if a feature lacks tag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/CLIPipeline_test.cpp`:
- Around line 1797-1814: The tests CLIPipelineCmdPoseError::NonexistentFile and
CLIPipelineCmdScanError::MissingConfigFile use hardcoded POSIX paths (e.g.
"/tmp/qtmesh_pose_missing_12345.fbx") which breaks Windows portability; update
these tests (locations referencing TestArgv and calls to CLIPipeline::cmdPose
and CLIPipeline::cmdScan) to construct missing-file paths using a
platform-neutral temp location (e.g. QDir::tempPath() or create a QTemporaryDir
and use a child filename) so the path semantics work on Windows, Linux, and
macOS and the tests still point to a non-existent file.

In `@src/ScanEngine_test.cpp`:
- Around line 1298-1303: Replace the hard assertion that the animated fixture
exists with a skip so the test doesn't fail on missing test data: for the
filePath computed from testDataDir() replace
ASSERT_TRUE(QFile::exists(filePath)) << ... with a conditional that calls
GTEST_SKIP() << "Animated fixture missing: " << filePath.toStdString(); (use
QFile::exists(filePath) on the same filePath variable before calling
ScanEngine::inspectAsset) so the test is skipped instead of failing when the
fixture is unavailable.
- Around line 304-311: The test EnumerateFiles_NonexistentRootReturnsEmpty
hardcodes a POSIX path (/tmp/...), making it non-portable; modify the test to
construct a guaranteed-nonexistent path using Qt APIs (e.g., create a
QTemporaryDir or use QDir::tempPath() and append a unique random/nonexistent
child name, then remove it if created) and pass that path into
ScanEngine::enumerateFiles so the test works on Windows, Linux, and macOS while
still asserting files.isEmpty().
- Around line 250-254: The test currently treats camelCase as a no-op which
prevents verifying/fixing camelCase conversion; update the expectation in
TEST(ScanEngineTest, ConvertNameToCase_LowercaseAndUnknown) to assert that
ScanEngine::convertNameToCase("PlayerModel.fbx", "camelCase") returns
"playerModel.fbx" (or remove the camelCase assertion until implementation
exists) so the unit test reflects the intended supported convention; reference
ScanEngine::convertNameToCase and the ConvertNameToCase_LowercaseAndUnknown test
when making the change.

---

Nitpick comments:
In `@website/src/App.jsx`:
- Around line 374-381: The tag assignment is fragile; update the
highlightFeatures data (e.g., in content.js) to include an explicit tag property
for each feature (e.g., tag: 'Advanced' or 'Feature'), then modify App.jsx where
highlightFeatures is mapped to pass feature.tag into the FeatureCard (replace
the title.includes('AI')/includes('MCP') logic with feature.tag). Ensure
FeatureCard continues to accept a tag prop and provide a sensible default if a
feature lacks tag.

In `@website/src/data/content.js`:
- Around line 61-82: The useCases array contains 5 items which renders awkwardly
in the 4-column .useCaseGrid causing a single orphan card; update the UI by
either adding or removing an item in the useCases array to make it 4 or 6
entries, or change the grid layout to accommodate 5 columns (adjust the
.useCaseGrid CSS) so cards align evenly; locate and edit the useCases export in
content.js or the .useCaseGrid rules in your stylesheet to implement the chosen
fix.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba957993-4570-402c-868f-fad2937d7384

📥 Commits

Reviewing files that changed from the base of the PR and between c9bb043 and 21d00bb.

📒 Files selected for processing (10)
  • src/Assimp/BoneProcessor_test.cpp
  • src/Assimp/MaterialProcessor_test.cpp
  • src/CLIPipeline_test.cpp
  • src/MeshImporterExporter_test.cpp
  • src/ScanEngine_test.cpp
  • src/TransformOperator_test.cpp
  • website/index.html
  • website/src/App.jsx
  • website/src/App.module.css
  • website/src/data/content.js

Comment thread src/CLIPipeline_test.cpp
Comment thread src/ScanEngine_test.cpp
Comment thread src/ScanEngine_test.cpp
Comment thread src/ScanEngine_test.cpp
Comment on lines +1298 to +1303
TEST(ScanEngineTest, InspectAsset_AnimatedFixtureCollectsAnimationMetadata)
{
const QString filePath = testDataDir() + "/Twist Dance.fbx";
ASSERT_TRUE(QFile::exists(filePath)) << "Animated fixture missing: " << filePath.toStdString();

const AssetInfo info = ScanEngine::inspectAsset(filePath, QFileInfo(filePath).absolutePath());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Skip when the animated fixture cannot be resolved.

testDataDir() is heuristic, so this hard assertion can turn a layout difference into a false-negative. Other fixture-based tests already skip when media is unavailable; this one should do the same.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ScanEngine_test.cpp` around lines 1298 - 1303, Replace the hard assertion
that the animated fixture exists with a skip so the test doesn't fail on missing
test data: for the filePath computed from testDataDir() replace
ASSERT_TRUE(QFile::exists(filePath)) << ... with a conditional that calls
GTEST_SKIP() << "Animated fixture missing: " << filePath.toStdString(); (use
QFile::exists(filePath) on the same filePath variable before calling
ScanEngine::inspectAsset) so the test is skipped instead of failing when the
fixture is unavailable.

@fernandotonon
fernandotonon force-pushed the codex/coverage-over-80-again branch from 21d00bb to ca4b3b1 Compare April 10, 2026 04:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/CLIPipeline_test.cpp (1)

1892-1940: Consider parsing report/SARIF as JSON instead of substring checks.

Current contains(...) checks can pass even if output is malformed but still includes those tokens. Parsing makes this assertion stricter and less brittle.

♻️ Suggested assertion hardening
-    const QString reportContent = QString::fromUtf8(reportFile.readAll());
-    EXPECT_TRUE(reportContent.contains("\"summary\""));
-    EXPECT_TRUE(reportContent.contains("\"assets\""));
+    const QByteArray reportBytes = reportFile.readAll();
+    QJsonParseError reportErr{};
+    const QJsonDocument reportDoc = QJsonDocument::fromJson(reportBytes, &reportErr);
+    ASSERT_EQ(reportErr.error, QJsonParseError::NoError);
+    ASSERT_TRUE(reportDoc.isObject());
+    const QJsonObject reportObj = reportDoc.object();
+    EXPECT_TRUE(reportObj.contains("summary"));
+    EXPECT_TRUE(reportObj.contains("assets"));

     QFile sarifFile(sarifPath);
     ASSERT_TRUE(sarifFile.open(QIODevice::ReadOnly | QIODevice::Text));
-    const QString sarifContent = QString::fromUtf8(sarifFile.readAll());
-    EXPECT_TRUE(sarifContent.contains("\"runs\""));
-    EXPECT_TRUE(sarifContent.contains("qtmesh scan"));
+    const QByteArray sarifBytes = sarifFile.readAll();
+    QJsonParseError sarifErr{};
+    const QJsonDocument sarifDoc = QJsonDocument::fromJson(sarifBytes, &sarifErr);
+    ASSERT_EQ(sarifErr.error, QJsonParseError::NoError);
+    ASSERT_TRUE(sarifDoc.isObject());
+    const QJsonObject sarifObj = sarifDoc.object();
+    EXPECT_TRUE(sarifObj.contains("runs"));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CLIPipeline_test.cpp` around lines 1892 - 1940, The test
TEST(CLIPipelineCmdScan, WritesJsonAndSarifReports) currently asserts
report/sarif output via substring checks; instead, open and parse reportPath and
sarifPath as JSON (e.g., using QJsonDocument::fromJson) and assert parsing
succeeded (no parse errors), then validate the expected structure: for the
report JSON ensure there is a top-level object containing "summary" and "assets"
keys with the expected types (object/array), and for the SARIF JSON ensure it
parses to an object with a "runs" array and that runs[0].tool.driver.name (or
runs[0].tool.driver.fullName) contains "qtmesh scan"; update assertions in this
test and keep using CLIPipeline::cmdScan(args.argc(), args.argv()) as the
command under test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/CLIPipeline_test.cpp`:
- Around line 1892-1940: The test TEST(CLIPipelineCmdScan,
WritesJsonAndSarifReports) currently asserts report/sarif output via substring
checks; instead, open and parse reportPath and sarifPath as JSON (e.g., using
QJsonDocument::fromJson) and assert parsing succeeded (no parse errors), then
validate the expected structure: for the report JSON ensure there is a top-level
object containing "summary" and "assets" keys with the expected types
(object/array), and for the SARIF JSON ensure it parses to an object with a
"runs" array and that runs[0].tool.driver.name (or runs[0].tool.driver.fullName)
contains "qtmesh scan"; update assertions in this test and keep using
CLIPipeline::cmdScan(args.argc(), args.argv()) as the command under test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e900899e-265a-4975-acfd-9729c69d2df6

📥 Commits

Reviewing files that changed from the base of the PR and between ca4b3b1 and 4cf35fe.

📒 Files selected for processing (2)
  • src/CLIPipeline_test.cpp
  • src/ScanEngine_test.cpp
✅ Files skipped from review due to trivial changes (1)
  • src/ScanEngine_test.cpp

@sonarqubecloud

Copy link
Copy Markdown

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.

1 participant