Improve test coverage to ~80-85% with 230+ new tests#177
Improve test coverage to ~80-85% with 230+ new tests#177fernandotonon merged 6 commits intomasterfrom
Conversation
The curl installer places sentry-cli in /usr/local/bin which is not in Git Bash's PATH on Windows runners. Use the full path instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 3 new test files and expand 14 existing test files with ~4170 lines of new test code covering previously untested functions and branches: - MaterialEditorQML: 43 signal/property tests, LLM stubs, edge cases - MCPServer: 15 protocol, resource, and tool handler tests - PrimitivesWidget: 34 UI state, selection, parameter, and edge case tests - mainwindow: 21 drag-drop, keyboard, action, and viewport tests - AnimationWidget: 15 null-state, toggle, and polling tests - Manager: 10 scene cleanup, auto-numbering, and entity tests - TransformOperator: 11 state cycling, signal, and multi-node tests - FBXExporter: 8 round-trip export, error handling, and edge case tests - BoneWeightOverlay: 8 visibility, bone selection, and overlay tests - NormalVisualizer: 6 signal integration and multi-entity tests - SkeletonDebug: 5 material, toggle, and scale tests - ModelDownloader: 5 state, signal, and lifecycle tests - LLMManager: 5 path, state, and settings tests - animationcontrolslider (new): 10 widget tests - QMLMaterialHighlighter (new): 7 document/signal tests - SelectionBoxObject (new): 7 construction and draw tests - SpaceCamera: fix pre-existing crash by guarding mouse-move tests that dereference null mTarget with tryInitOgre() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdds ~5,000 lines of test-only code across many test files, introducing new fixtures and extensive unit/integration tests for animation, overlays, FBX/mesh I/O, scene/manager behavior, UI widgets, server/LLM components, and Ogre-dependent scenarios. No production API or signature changes. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/SpaceCamera_test.cpp (1)
276-297:⚠️ Potential issue | 🔴 Critical
tryInitOgre()still doesn't giveMockSpaceCameraa valid target.Lines 199-201 already note that
mCameraNode/mTargetare only initialized through theOgreWidgetconstructor path. These new tests still constructMockSpaceCameradirectly, somouseMoveEvent()can keep hitting the same null-dereference that originally crashed the suite. Drive these cases through a widget-backed camera, or inject a valid target before sending move events.Also applies to: 325-341, 363-389
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/SpaceCamera_test.cpp` around lines 276 - 297, The tests construct MockSpaceCamera directly so mCameraNode/mTarget remain null (tryInitOgre() doesn't initialize them); update the tests to either create the camera via the OgreWidget constructor (drive through the widget-backed camera path) or explicitly inject a valid target/camera node on the MockSpaceCamera before calling mousePressEvent/mouseMoveEvent (e.g., call the existing setter or initialization routine that populates mTarget/mCameraNode) so mouseMoveEvent() no longer dereferences a null mTarget.
🧹 Nitpick comments (2)
src/MCPServer_test.cpp (2)
2606-2617: Test comments describe resource protocol but test tool calls.The test name and comments suggest testing resource protocol (
handleResourcesList), but the actual test callsget_scene_infotool. While testing indirectly is valid since the methods are private, the test nameHandleResourcesList_ReturnsResourcesis misleading since it doesn't actually test resource listing.Consider renaming to reflect what's actually being tested, or add a comment clarifying the indirect testing approach.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2606 - 2617, The test named HandleResourcesList_ReturnsResources is misleading because it doesn't call handleResourcesList directly; update the test to clarify intent by either renaming the TEST_F identifier (e.g., to GetSceneInfo_ExposesResourceData or ToolCall_VerifiesResourceAccess) or add a concise comment above the TEST_F explaining that handleResourcesList is private and the test verifies resource exposure indirectly via server->callTool("get_scene_info", ...) and the expectation on getResultText(result); ensure references to handleResourcesList, callTool, and get_scene_info are mentioned so future readers know this is an indirect verification.
2545-2545: Hardcoded tool count may become stale.The assertion
EXPECT_EQ(allTools.size(), 26)will fail silently if new tools are added to the list but the count isn't updated, or vice versa. Consider removing this assertion since the loop already verifies each tool individually.Suggested fix
}; - EXPECT_EQ(allTools.size(), 26); - for (const QString &tool : allTools) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` at line 2545, The test contains a brittle hardcoded size check EXPECT_EQ(allTools.size(), 26) that will break when tools are added/removed; remove that EXPECT_EQ assertion and rely on the existing loop that validates each tool (referencing the allTools container and the loop that iterates over its elements) so the test asserts properties per-tool rather than a fixed count.
🤖 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/FBX/FBXExporter_test.cpp`:
- Around line 2327-2328: The test uses POSIX-only hard-coded paths (e.g.,
"/tmp/fbx_inmem_%1.fbx") which breaks Windows CI; update the FBXExporter tests
to use QTemporaryFile or QTemporaryDir to produce a cross-platform temporary
file path for the success case and construct the invalid path by creating a temp
dir/file and then removing it (or appending a non-existent child name) to ensure
an intentionally-invalid path; change uses of meshCounter-based outPath and any
other hard-coded paths referenced around FBXExporter::exportFBX (also fix the
similar occurrences noted at the other ranges) to build paths via
QTemporaryFile/QTemporaryDir so tests are platform-independent.
In `@src/mainwindow_test.cpp`:
- Around line 1015-1071: These tests directly construct QDragEnterEvent (in
tests DragEnterEvent_AcceptsMeshFiles, DragEnterEvent_AcceptsFBXFiles,
DragEnterEvent_AcceptsOBJFiles, DragEnterEvent_AcceptsDAEFiles,
DragEnterEvent_AcceptsNonMeshFiles, DragEnterEvent_AcceptsEmptyUrls), which is
unsafe; instead either (A) drive a real drag by using QTest mouse events/QDrag
so the Qt drag-and-drop state is initialized, or (B) refactor the acceptance
logic out of MainWindow::dragEnterEvent into a testable helper (e.g.
MainWindow::canAcceptMimeData or a static function taking QMimeData*) and call
that helper from these tests with constructed QMimeData; update the tests to
remove direct QDragEnterEvent construction and assert the helper or real drag
result.
In `@src/MCPServer_test.cpp`:
- Around line 2770-2785: The test uses a hardcoded
"/tmp/mcp_export_temp_test.obj" which is not portable; update the export path
construction to use QDir::tempPath() (as in ExportMeshWithInMemoryEntity) when
creating exportPath and the corresponding material/mtl filenames, e.g. build
exportDir = QDir::tempPath() and join with "mcp_export_temp_test.obj" to form
exportPath, then adjust the QFile::remove calls to remove the same derived
paths; modify the block around the export_mesh call where exportPath,
exportedFile, and cleanup are handled to use these QDir-based paths instead of
"/tmp/".
In `@src/PrimitivesWidget_test.cpp`:
- Around line 502-537: The test uses QWidget::isVisible() which returns false
because the PrimitivesWidget isn't shown; update the assertions in TEST_F
PrimitivesWidgetTest::SetUiEmptyHidesAllFields to call isVisibleTo(&widget)
(e.g., edit_type->isVisibleTo(&widget), gb_Geometry->isVisibleTo(&widget),
edit_sizeX->isVisibleTo(&widget), pb_switchUV->isVisibleTo(&widget), etc.) so
the checks reflect each child's own visibility as set by setUiEmpty(), or
alternatively call widget.show() and process events before asserting—apply the
same change to the related assertions covering lines 539–579.
In `@src/SkeletonDebug_test.cpp`:
- Around line 212-240: The test currently masks missing materials because of the
"|| true" in the EXPECT_TRUE for boneMat and because it uses conditional "if
(boneMat)" instead of assertions, so it can succeed without actual materials;
remove the "|| true" in the EXPECT_TRUE line and replace the `if (boneMat) { ...
}` checks with hard assertions (e.g., ASSERT_TRUE(boneMat) or
ASSERT_FALSE(boneMat.isNull())) before accessing boneMat->getNumTechniques(),
getTechnique(), getNumPasses(), and getLightingEnabled(), and likewise replace
the `if (axisMat)` and `if (selectedMat)` guards with ASSERT_TRUE(axisMat) /
ASSERT_TRUE(selectedMat) (or ASSERT_GT(getNumTechniques(), 0u) immediately after
asserting) so the test fails when materials are missing; use the existing
symbols boneMat, axisMat, selectedMat, getByName, getNumTechniques,
getTechnique, getNumPasses, and getLightingEnabled to locate the changes.
In `@src/TransformOperator_test.cpp`:
- Around line 596-620: The test fixture leaves the SelectionSet singleton in a
stale state across tests; update TransformOperatorTestFixture::SetUp() (and
optionally TearDown()) to explicitly clear the selection by calling
SelectionSet::getSingleton()->clear() (or the project’s equivalent
clearSelection/reset method) and assert SelectionSet::getSingleton()->isEmpty()
before running tests so AllOperations_EmptyScene is order-independent; ensure
the fixture uses these calls (and remove any reliance on external tests to reset
SelectionSet).
---
Outside diff comments:
In `@src/SpaceCamera_test.cpp`:
- Around line 276-297: The tests construct MockSpaceCamera directly so
mCameraNode/mTarget remain null (tryInitOgre() doesn't initialize them); update
the tests to either create the camera via the OgreWidget constructor (drive
through the widget-backed camera path) or explicitly inject a valid
target/camera node on the MockSpaceCamera before calling
mousePressEvent/mouseMoveEvent (e.g., call the existing setter or initialization
routine that populates mTarget/mCameraNode) so mouseMoveEvent() no longer
dereferences a null mTarget.
---
Nitpick comments:
In `@src/MCPServer_test.cpp`:
- Around line 2606-2617: The test named HandleResourcesList_ReturnsResources is
misleading because it doesn't call handleResourcesList directly; update the test
to clarify intent by either renaming the TEST_F identifier (e.g., to
GetSceneInfo_ExposesResourceData or ToolCall_VerifiesResourceAccess) or add a
concise comment above the TEST_F explaining that handleResourcesList is private
and the test verifies resource exposure indirectly via
server->callTool("get_scene_info", ...) and the expectation on
getResultText(result); ensure references to handleResourcesList, callTool, and
get_scene_info are mentioned so future readers know this is an indirect
verification.
- Line 2545: The test contains a brittle hardcoded size check
EXPECT_EQ(allTools.size(), 26) that will break when tools are added/removed;
remove that EXPECT_EQ assertion and rely on the existing loop that validates
each tool (referencing the allTools container and the loop that iterates over
its elements) so the test asserts properties per-tool rather than a fixed count.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 67af571f-d25c-49b3-aeb2-3d1c2f77bfcc
📒 Files selected for processing (17)
src/AnimationWidget_test.cppsrc/BoneWeightOverlay_test.cppsrc/FBX/FBXExporter_test.cppsrc/LLMManager_test.cppsrc/MCPServer_test.cppsrc/Manager_test.cppsrc/MaterialEditorQML_test.cppsrc/ModelDownloader_test.cppsrc/NormalVisualizer_test.cppsrc/PrimitivesWidget_test.cppsrc/QMLMaterialHighlighter_test.cppsrc/SelectionBoxObject_test.cppsrc/SkeletonDebug_test.cppsrc/SpaceCamera_test.cppsrc/TransformOperator_test.cppsrc/animationcontrolslider_test.cppsrc/mainwindow_test.cpp
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsMeshFiles) { | ||
| auto mimeData = new QMimeData(); | ||
| mimeData->setUrls({QUrl::fromLocalFile("/tmp/test.mesh")}); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } | ||
|
|
||
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsFBXFiles) { | ||
| auto mimeData = new QMimeData(); | ||
| mimeData->setUrls({QUrl::fromLocalFile("/tmp/model.fbx")}); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } | ||
|
|
||
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsOBJFiles) { | ||
| auto mimeData = new QMimeData(); | ||
| mimeData->setUrls({QUrl::fromLocalFile("/tmp/scene.obj")}); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } | ||
|
|
||
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsDAEFiles) { | ||
| auto mimeData = new QMimeData(); | ||
| mimeData->setUrls({QUrl::fromLocalFile("/tmp/animation.dae")}); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| // dragEnterEvent accepts all proposed actions unconditionally | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } | ||
|
|
||
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsNonMeshFiles) { | ||
| // The current implementation accepts all drag events unconditionally | ||
| // (filtering happens in dropEvent). Verify this behavior. | ||
| auto mimeData = new QMimeData(); | ||
| mimeData->setUrls({QUrl::fromLocalFile("/tmp/readme.txt"), | ||
| QUrl::fromLocalFile("/tmp/program.exe")}); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } | ||
|
|
||
| TEST_F(MainWindowTest, DragEnterEvent_AcceptsEmptyUrls) { | ||
| // Even with no URLs the drag enter is accepted (filtering in dropEvent) | ||
| auto mimeData = new QMimeData(); | ||
| QDragEnterEvent event(QPoint(0, 0), Qt::CopyAction, mimeData, Qt::LeftButton, Qt::NoModifier); | ||
| QApplication::sendEvent(mainWindow.get(), &event); | ||
| EXPECT_TRUE(event.isAccepted()); | ||
| delete mimeData; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Qt QDragEnterEvent documentation warning: "Do not create a QDragEnterEvent yourself"
💡 Result:
In Qt’s drag-and-drop system, QDragEnterEvent instances are created and populated by Qt during an active drag operation. Even though the class has a public constructor, the docs warn you not to instantiate it because the event’s behavior depends on Qt’s internal drag-and-drop state (the drag manager / current drag context), which your manually-created event won’t set up correctly—so results are undefined or incomplete. [1]
If your goal is testing or simulating drag & drop:
- Prefer simulating the real user interaction that triggers
QDrag::exec()(e.g., withQTest::mousePress/mouseMove/mouseRelease) rather than fabricatingQDragEnterEvent. [2][3] - If you do post synthetic
QDragEnterEvent/QDropEventto a widget, it may only cover limited logic (and can fail for anything that relies onevent->source()/ actual drag lifecycle). [3]
Sources:
[1] Qt 6.10 QDragEnterEvent docs (warning about internal state) (doc.qt.io)
[2] Stack Overflow discussion noting manual construction is discouraged due to internal state (stackoverflow.com)
[3] Qt Forum thread on testing drag & drop (limitations of posting events; suggests QTest mouse simulation) (forum.qt.io)
Citations:
- 1: https://doc.qt.io/qt-6/qdragenterevent.html
- 2: https://stackoverflow.com/questions/24144482/how-to-test-drag-and-drop-behavior-in-pyqt?utm_source=openai
- 3: https://forum.qt.io/topic/135108/testing-drag-drop?utm_source=openai
Avoid constructing QDragEnterEvent directly in tests.
Qt's documentation explicitly warns against manually instantiating QDragEnterEvent because the event depends on Qt's internal drag-and-drop state, which manual construction does not establish. This results in undefined behavior and incomplete event state, making tests fragile and platform-dependent.
At lines 1018, 1027, 1036, 1045, 1058, 1067, and 1293, the tests construct QDragEnterEvent directly. Instead, drive real drag interactions using QTest::mousePress/mouseMove/mouseRelease or extract and unit-test the acceptance logic independently.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/mainwindow_test.cpp` around lines 1015 - 1071, These tests directly
construct QDragEnterEvent (in tests DragEnterEvent_AcceptsMeshFiles,
DragEnterEvent_AcceptsFBXFiles, DragEnterEvent_AcceptsOBJFiles,
DragEnterEvent_AcceptsDAEFiles, DragEnterEvent_AcceptsNonMeshFiles,
DragEnterEvent_AcceptsEmptyUrls), which is unsafe; instead either (A) drive a
real drag by using QTest mouse events/QDrag so the Qt drag-and-drop state is
initialized, or (B) refactor the acceptance logic out of
MainWindow::dragEnterEvent into a testable helper (e.g.
MainWindow::canAcceptMimeData or a static function taking QMimeData*) and call
that helper from these tests with constructed QMimeData; update the tests to
remove direct QDragEnterEvent construction and assert the helper or real drag
result.
- PrimitivesWidget: Replace isVisible() with !isHidden() for headless testing (isVisible requires parent chain to be shown) - MCPServer: Fix entity/node name mismatch in GetMeshInfo and ExportMesh tests, fix assertion to match actual tool output format - FBXExporter: Fix expected vertex count for multi-submesh shared vertex data (18 doubles not 9) - MaterialEditorQML: Create fresh material for reset test instead of re-loading mutated BaseWhite - NormalVisualizer: Add VES_NORMAL to createAnimatedTestEntity helper so overlay builder finds normals to visualize - AnimationControlWidget: Fix entity/node name mismatch in MultipleAnimationsInTree test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/FBX/FBXExporter_test.cpp (1)
2327-2328:⚠️ Potential issue | 🟠 MajorHard-coded
/tmp/paths break Windows CI.These tests use POSIX-only paths like
/tmp/fbx_inmem_%1.fbxand/nonexistent_directory_xyz/sub/test.fbx. Windows CI will fail before exercising the actual export logic. UseQTemporaryDir/QTemporaryFileto construct portable paths.Also applies to: 2421-2422, 2427-2429, 2448-2454
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/FBX/FBXExporter_test.cpp` around lines 2327 - 2328, Replace POSIX-only hardcoded temp paths with Qt temporary-file utilities: use QTemporaryFile or QTemporaryDir to create a portable file path and pass that to FBXExporter::exportFBX instead of QString("/tmp/..."). Locate the failing test lines that build outPath and call ASSERT_TRUE(FBXExporter::exportFBX(entity, outPath)) (and the similar cases around the other mentioned blocks) and change them to create a QTemporaryFile/QTemporaryDir, ensure it has a .fbx suffix or construct a filename inside the temp directory, call file.fileName() (or dir.path() + "/...") for the export path, and clean up the temporary file/dir after the assertion.src/MCPServer_test.cpp (1)
2759-2788:⚠️ Potential issue | 🟠 MajorUse
QDir::tempPath()here instead of hardcoding/tmp.This suite is expected to run in cross-platform CI, and
"/tmp/..."will fail on Windows. Reuse the portable temp-base pattern already used byExportMeshWithInMemoryEntityso the export path and cleanup are derived from the same location.Suggested fix
- QString exportPath = "/tmp/mcp_export_temp_test.mesh"; + const QString exportBase = QDir(QDir::tempPath()).filePath("mcp_export_temp_test"); + QString exportPath = exportBase + ".mesh"; QJsonObject args; args["path"] = exportPath; QJsonObject result = server->callTool("export_mesh", args); EXPECT_FALSE(isError(result)); @@ - QFile::remove(exportPath); - QFile::remove("/tmp/mcp_export_temp_test.material"); + QFile::remove(exportPath); + QFile::remove(exportBase + ".material");Based on learnings, CI builds for Windows (MinGW), macOS, and Linux.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2759 - 2788, The test ExportMesh_ToTempFile hardcodes "/tmp/..." which breaks cross-platform CI; change it to use QDir::tempPath() like the ExportMeshWithInMemoryEntity test: build exportPath by concatenating QDir::tempPath() with the filename (e.g., QDir::tempPath() + "/mcp_export_temp_test.mesh"), use that same base when removing the .mesh and .material files during cleanup, and ensure any QFile/export checks use the new exportPath variable and SelectionSet::getSingleton()->clear() remains unchanged.
🤖 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/MCPServer_test.cpp`:
- Around line 2606-2651: The tests are false positives because they call
server->callTool("get_scene_info"/"get_material"/"nonexistent_resource_tool")
instead of exercising the actual JSON-RPC resource endpoints; update the tests
to invoke the MCP resource RPC methods (e.g., "resources/list" and
"resources/read") so they exercise handleResourcesList and handleResourcesRead
end-to-end: call "resources/list" and assert the returned array contains the
expected URIs ("qtmesheditor://material/current", "qtmesheditor://scene/info"),
then call "resources/read" with a valid URI (e.g., "qtmesheditor://scene/info")
and assert the body contains "Scene Information"/"Scene Nodes", and also test
invalid/empty URIs via "resources/read" to assert proper error messages instead
of using server->callTool.
- Around line 2518-2552: The tests HandleInitialize_ReturnsServerInfo,
HandleToolsList_ContainsAllTools (and the DoubleInitialize case) currently call
callTool() or construct MCPServer directly and thus bypass the real protocol
handlers; update these tests to exercise the actual initialize and tools/list
protocol paths (e.g., invoke processMessage or the server's
handleToolsCall/handleInitialize entry points with an "initialize" request and a
"tools/list" request) so they validate server info, tool metadata/capabilities,
and initialize idempotency as returned by the protocol handlers (not just by
callTool()), and remove or merge the duplicate smoke test to avoid redundancy.
Ensure assertions inspect the protocol response fields (IDs, capabilities, tool
list) rather than inferred behavior from callTool().
---
Duplicate comments:
In `@src/FBX/FBXExporter_test.cpp`:
- Around line 2327-2328: Replace POSIX-only hardcoded temp paths with Qt
temporary-file utilities: use QTemporaryFile or QTemporaryDir to create a
portable file path and pass that to FBXExporter::exportFBX instead of
QString("/tmp/..."). Locate the failing test lines that build outPath and call
ASSERT_TRUE(FBXExporter::exportFBX(entity, outPath)) (and the similar cases
around the other mentioned blocks) and change them to create a
QTemporaryFile/QTemporaryDir, ensure it has a .fbx suffix or construct a
filename inside the temp directory, call file.fileName() (or dir.path() +
"/...") for the export path, and clean up the temporary file/dir after the
assertion.
In `@src/MCPServer_test.cpp`:
- Around line 2759-2788: The test ExportMesh_ToTempFile hardcodes "/tmp/..."
which breaks cross-platform CI; change it to use QDir::tempPath() like the
ExportMeshWithInMemoryEntity test: build exportPath by concatenating
QDir::tempPath() with the filename (e.g., QDir::tempPath() +
"/mcp_export_temp_test.mesh"), use that same base when removing the .mesh and
.material files during cleanup, and ensure any QFile/export checks use the new
exportPath variable and SelectionSet::getSingleton()->clear() remains unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ea364b9e-92cc-46a6-a7ba-32427747f806
📒 Files selected for processing (6)
src/FBX/FBXExporter_test.cppsrc/MCPServer_test.cppsrc/MaterialEditorQML_test.cppsrc/PrimitivesWidget_test.cppsrc/TestHelpers.hsrc/animationcontrolwidget_test.cpp
src/MCPServer_test.cpp
Outdated
| TEST_F(MCPServerTest, HandleInitialize_ReturnsServerInfo) | ||
| { | ||
| // Call handleInitialize indirectly via processMessage / handleToolsCall | ||
| // Since handleInitialize is private, we test through the public callTool | ||
| // and verify the server responds to known tools after initialization. | ||
| // We can verify the server's state by checking that tools work. | ||
|
|
||
| // The server should respond to tools without explicit initialize call | ||
| QJsonObject result = server->callTool("list_materials", QJsonObject()); | ||
| EXPECT_FALSE(isError(result)); | ||
| // Server is functional, which means Ogre initialized correctly | ||
| EXPECT_FALSE(getResultText(result).isEmpty()); | ||
| } | ||
|
|
||
| TEST_F(MCPServerTest, HandleToolsList_ContainsAllTools) | ||
| { | ||
| // Verify every known tool name is recognized (not "Unknown tool") | ||
| QStringList allTools = { | ||
| "create_material", "modify_material", "get_material", "list_materials", | ||
| "apply_material", "load_mesh", "get_mesh_info", "transform_mesh", | ||
| "list_textures", "set_texture", "export_mesh", "get_scene_info", | ||
| "take_screenshot", "create_primitive", "animate", | ||
| "list_skeletal_animations", "get_animation_info", "set_animation_length", | ||
| "set_animation_time", "add_keyframe", "remove_keyframe", | ||
| "play_animation", "toggle_skeleton_debug", "toggle_bone_weights", | ||
| "toggle_normals", "merge_animations" | ||
| }; | ||
| EXPECT_EQ(allTools.size(), 26); | ||
|
|
||
| for (const QString &tool : allTools) { | ||
| QJsonObject result = server->callTool(tool, QJsonObject()); | ||
| EXPECT_FALSE(getResultText(result).contains("Unknown tool")) | ||
| << "Tool should be recognized: " << tool.toStdString(); | ||
| } | ||
| } |
There was a problem hiding this comment.
These “protocol edge case” tests bypass the protocol handlers they’re named after.
HandleInitialize_ReturnsServerInfo and HandleToolsList_ContainsAllTools only use callTool(), and DoubleInitialize just constructs a second MCPServer. None of them send an initialize or tools/list request, so regressions in server info/capabilities, tool metadata, or initialize idempotency would still pass. HandleToolsList_ContainsAllTools also duplicates the earlier HandleToolsList smoke test.
Also applies to: 2589-2600
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MCPServer_test.cpp` around lines 2518 - 2552, The tests
HandleInitialize_ReturnsServerInfo, HandleToolsList_ContainsAllTools (and the
DoubleInitialize case) currently call callTool() or construct MCPServer directly
and thus bypass the real protocol handlers; update these tests to exercise the
actual initialize and tools/list protocol paths (e.g., invoke processMessage or
the server's handleToolsCall/handleInitialize entry points with an "initialize"
request and a "tools/list" request) so they validate server info, tool
metadata/capabilities, and initialize idempotency as returned by the protocol
handlers (not just by callTool()), and remove or merge the duplicate smoke test
to avoid redundancy. Ensure assertions inspect the protocol response fields
(IDs, capabilities, tool list) rather than inferred behavior from callTool().
src/MCPServer_test.cpp
Outdated
| TEST_F(MCPServerTest, HandleResourcesList_ReturnsResources) | ||
| { | ||
| // We can't call handleResourcesList directly (it's private), but we can | ||
| // verify the server exposes resources by testing the resource-related | ||
| // tools indirectly. The resources are "qtmesheditor://material/current" | ||
| // and "qtmesheditor://scene/info". | ||
| // Since handleResourcesList is part of the MCP JSON-RPC flow, we verify | ||
| // the underlying data is accessible through callTool. | ||
| QJsonObject result = server->callTool("get_scene_info", QJsonObject()); | ||
| EXPECT_FALSE(isError(result)); | ||
| EXPECT_TRUE(getResultText(result).contains("Scene Information")); | ||
| } | ||
|
|
||
| TEST_F(MCPServerTest, HandleResourcesRead_ValidURI) | ||
| { | ||
| // The "scene/info" resource is backed by toolGetSceneInfo. | ||
| // Verify the scene info tool returns valid data (same as resource read). | ||
| QJsonObject result = server->callTool("get_scene_info", QJsonObject()); | ||
| EXPECT_FALSE(isError(result)); | ||
| QString text = getResultText(result); | ||
| EXPECT_TRUE(text.contains("Scene Information")); | ||
| EXPECT_TRUE(text.contains("Scene Nodes")); | ||
| } | ||
|
|
||
| TEST_F(MCPServerTest, HandleResourcesRead_InvalidURI) | ||
| { | ||
| // An invalid resource URI would return empty contents in handleResourcesRead. | ||
| // We verify that the server handles unknown tools gracefully. | ||
| QJsonObject result = server->callTool("nonexistent_resource_tool", QJsonObject()); | ||
| EXPECT_TRUE(isError(result)); | ||
| EXPECT_TRUE(getResultText(result).contains("Unknown tool")); | ||
| } | ||
|
|
||
| TEST_F(MCPServerTest, HandleResourcesRead_EmptyURI) | ||
| { | ||
| // Verify that tools handle empty/missing string params correctly | ||
| QJsonObject args; | ||
| args["uri"] = ""; | ||
| // There's no direct "read_resource" tool, but we can verify | ||
| // material read with empty name returns proper error | ||
| QJsonObject args2; | ||
| args2["name"] = ""; | ||
| QJsonObject result = server->callTool("get_material", args2); | ||
| EXPECT_TRUE(isError(result)); | ||
| EXPECT_TRUE(getResultText(result).contains("Material name is required")); | ||
| } |
There was a problem hiding this comment.
The new resource-protocol coverage here is a false positive.
These cases only hit normal tool calls and the unknown-tool branch; they never exercise resources/list / resources/read with an actual resource URI. A break in resource registration, URI parsing, or resource dispatch would still let this block pass.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MCPServer_test.cpp` around lines 2606 - 2651, The tests are false
positives because they call
server->callTool("get_scene_info"/"get_material"/"nonexistent_resource_tool")
instead of exercising the actual JSON-RPC resource endpoints; update the tests
to invoke the MCP resource RPC methods (e.g., "resources/list" and
"resources/read") so they exercise handleResourcesList and handleResourcesRead
end-to-end: call "resources/list" and assert the returned array contains the
expected URIs ("qtmesheditor://material/current", "qtmesheditor://scene/info"),
then call "resources/read" with a valid URI (e.g., "qtmesheditor://scene/info")
and assert the body contains "Scene Information"/"Scene Nodes", and also test
invalid/empty URIs via "resources/read" to assert proper error messages instead
of using server->callTool.
Adds comprehensive test coverage for: - MCPServer: 28 animation tool success path tests (play/stop/pause, set length/time, add/remove keyframes, get info, merge animations) - MaterialEditorQML: deeper Ogre property tests, undo/redo, validation - MeshImporterExporter: skeleton/animated entity exports in 6 formats - mainwindow: frame rendering, merge animations, recent files - AnimationWidget: table click handlers, skeleton debug toggles - LLMManager: prompt building, validation, cleanup edge cases - NormalVisualizer: animated overlays, show/hide cycles - BoneWeightOverlay: timer updates, bone selection polling - SpaceCamera: Ogre-dependent mouse/keyboard input tests - TransformWidget: spin box ranges, value change triggers - AnimationControlSlider: mouse clicks, setValue, paint edge cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/SpaceCamera_test.cpp (1)
277-297:⚠️ Potential issue | 🔴 CriticalNull pointer dereference in Ogre interaction tests.
MockSpaceCamerais constructed with the default constructor, which leavesmCameraNodeandmTargetasnullptr. WhenmouseMoveEvent()orwheelEvent()are called, they invokearcBall(),pan(), orzoom()which immediately dereference these null pointers. Initialize the camera nodes in the test setup (e.g., by constructing with a validOgreWidget*parent or by manually populating the nodes in the fixture), or guard the handler calls with null checks.Applies to: lines 277–297, 325–389, 428–494.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/SpaceCamera_test.cpp` around lines 277 - 297, The tests call MockSpaceCamera::mouseMoveEvent and wheelEvent while MockSpaceCamera's mCameraNode and mTarget are null, causing dereferences in arcBall(), pan(), and zoom(); fix by ensuring the test fixture initializes valid nodes before invoking input handlers (e.g., construct MockSpaceCamera with a valid OgreWidget parent or assign/populate mCameraNode and mTarget in the test setup/fixture) or add early null guards in MockSpaceCamera::mouseMoveEvent, wheelEvent, arcBall, pan, and zoom to return early if mCameraNode or mTarget is nullptr; update the tests referencing MockSpaceCamera, mouseMoveEvent, wheelEvent, arcBall, pan, zoom, mCameraNode, and mTarget accordingly.
♻️ Duplicate comments (4)
src/MCPServer_test.cpp (3)
2518-2600:⚠️ Potential issue | 🟠 MajorThese “initialize/tools-list” tests still bypass the protocol handlers they’re named after.
HandleInitialize_ReturnsServerInfoandHandleToolsList_ContainsAllToolsonly exercisecallTool(), andDoubleInitializejust constructs anotherMCPServer. Regressions ininitialize, server capabilities, ortools/listmetadata would still pass here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2518 - 2600, The tests are bypassing the protocol handlers by calling callTool() directly; update these tests to exercise the actual handlers: send the initialize and tools/list protocol messages through MCPServer::processMessage (or the public handleToolsCall entry point) instead of server->callTool, invoking the "initialize" and "tools/list" RPC payloads so handleInitialize and the tools-list handler run; ensure DoubleInitialize constructs a second MCPServer and sends an "initialize" message to it (and optionally to the original) to validate real initialization paths and metadata, and assert on the returned JSON fields (server info and tools metadata) rather than just non-empty results.
2759-2789:⚠️ Potential issue | 🟠 MajorUse
QDir::tempPath()here instead of/tmp.This export path and the cleanup filenames are Unix-specific, so this success-path test is likely to fail or behave oddly on the Windows CI job.
Based on learnings, tests run on Linux with SonarCloud coverage; CI builds for Windows (MinGW), macOS, and Linux.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2759 - 2789, The test ExportMesh_ToTempFile uses a hardcoded Unix /tmp path; change it to use QDir::tempPath() when building exportPath and cleanup filenames so the test is cross-platform (locate the exportPath variable in TEST_F(MCPServerTest, ExportMesh_ToTempFile)), construct the full paths with QDir/QFileInfo join/clean utilities instead of string concatenation, and update the cleanup QFile::remove calls to remove the same constructed paths (including the .material path) so Windows and macOS CI run correctly.
2606-2651:⚠️ Potential issue | 🟠 MajorThe new resource-protocol coverage is still a false positive.
These cases only hit normal tool calls or the unknown-tool branch, so they won’t catch breakage in
resources/list, URI parsing, orresources/readdispatch.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2606 - 2651, The tests currently only exercise tool calls and the unknown-tool path, so add direct coverage for the MCP JSON-RPC resource endpoints by sending real "resources/list" and "resources/read" requests through the server's JSON-RPC dispatch (or, if the dispatch is private, add a test-only friend/helper to call handleResourcesList and handleResourcesRead). Specifically: invoke resources/list and assert the returned URIs include "qtmesheditor://material/current" and "qtmesheditor://scene/info"; invoke resources/read with "qtmesheditor://scene/info" and assert the body contains "Scene Information"/"Scene Nodes"; also test resources/read with an unknown URI and with an empty URI and assert the appropriate error messages are returned. Use the existing server test fixture (server) and reference handleResourcesList, handleResourcesRead, resources/list, resources/read and callTool to locate related code.src/mainwindow_test.cpp (1)
1015-1071:⚠️ Potential issue | 🟠 MajorStop constructing
QDragEnterEventdirectly in these tests.Sending a stack-constructed
QDragEnterEventdoes not exercise a real Qt drag lifecycle, so these cases are platform-fragile and can pass without validating the production path. Either drive an actual drag withQTest, or extract the acceptance logic into a helper and test that helper directly.As per coding guidelines,
**/*_test.cpp: Tests must work under Xvfb (headless X11) and avoid assumptions about a real display.Also applies to: 1287-1297
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mainwindow_test.cpp` around lines 1015 - 1071, Tests are creating QDragEnterEvent instances directly (in tests like DragEnterEvent_AcceptsMeshFiles, DragEnterEvent_AcceptsFBXFiles, etc.), which is fragile and bypasses Qt's real drag lifecycle; refactor by moving the acceptance logic out of MainWindow::dragEnterEvent into a testable helper (e.g. MainWindow::shouldAcceptDrag(const QMimeData*) or MainWindow::canAcceptUrls(const QList<QUrl>&)), update dragEnterEvent to call that helper, and change the unit tests to call the new helper directly (or drive a real drag with QTest if preferred) so they no longer construct QDragEnterEvent on the stack and will run reliably under Xvfb.
🤖 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/LLMManager_test.cpp`:
- Around line 1152-1163: The test LoadModel_NonExistentModel doesn't assert the
failure path; replace the fixed QThread::msleep with a proper wait/assert using
QSignalSpy or QTRY_* utilities: use QSignalSpy errorSpy(manager,
&LLMManager::modelLoadError) and call manager->loadModel(...), then wait for the
signal (e.g. errorSpy.wait(timeout) or QTRY_VERIFY(errorSpy.count() > 0)) and
assert the expected failure (errorSpy.count() > 0) or alternatively assert the
manager reports no loaded model (e.g. verify manager->isModelLoaded() is false
or manager->currentModel() is empty) so the test deterministically verifies the
error path instead of only relying on no crash.
- Around line 983-1001: Make the test deterministic by forcing a fresh temp
models directory and disabling auto-load before exercising the singleton: in the
test (LLMManagerTest) capture the current singleton via manager =
LLMManager::instance(), save/backup the original auto-load setting and models
directory, then call manager->setAutoLoadOnStartup(false) and
manager->setModelsDirectory(tempDir.path()) (or use the manager/settings API
available) so tryAutoLoadModel() cannot find real models; run the assertions
(isModelLoaded(), isLoading(), isGenerating(), currentModelName()), and finally
restore the original auto-load setting and models directory to avoid global test
pollution.
In `@src/mainwindow_test.cpp`:
- Around line 1411-1443: The test TEST_F(MainWindowTest,
MergeAnimationsButton_EnabledWithTwoCompatibleEntities) currently creates two
entities via createAnimatedTestEntity that produce distinct skeletons and then
discards the checked value of actionMerge->isEnabled(), so it doesn't actually
verify the enabled state; either rename the test to reflect
"NoCrash_SelectionRecalc" and assert only that update/selection changes don't
crash and that the button becomes disabled after clearing the selection, or
modify the setup to produce two truly compatible entities (e.g., create one
skeleton instance and pass it into a second entity or clone the same Skeleton
pointer used by createAnimatedTestEntity) then select both via
SelectionSet::getSingleton()->selectOne/append, call app->processEvents(), and
assert EXPECT_TRUE(actionMerge->isEnabled()) before clearing the selection and
EXPECT_FALSE(actionMerge->isEnabled()) afterwards so the intent of
actionMerge->isEnabled() is actually verified.
In `@src/MaterialEditorQML_test.cpp`:
- Around line 2322-2348: The test ApplyMaterial_ColorsReflectedInOgrePass
currently only checks shininess; after reloading the material via
editor->loadMaterial(editor->materialName()) you must also assert that the
ambient/diffuse/specular/emissive colors round-trip by comparing
editor->ambientColor(), editor->diffuseColor(), editor->specularColor(), and
editor->emissiveColor() to the originally set QColor values (red, green, blue,
yellow) using appropriate equality/fuzzy color checks (e.g., EXPECT_EQ or color
component comparisons) so the test actually verifies color serialization in
addition to shininess; alternatively, if you don’t want to add asserts, rename
the TEST_F to reflect it only verifies shininess round-trip.
- Around line 2285-2304: The test TEST_F(MaterialEditorQMLWithOgreTest,
ExportAndImportMaterial_RoundTrip) uses a hard-coded exportPath
"/tmp/round_trip_test.material" which breaks on non-Linux CI; replace this with
a portable temporary file/dir approach (e.g., QTemporaryFile or QTemporaryDir or
QDir::tempPath()) to produce a writable path, use that path when calling
editor->exportMaterial(...) and editor->importMaterialFile(...), ensure the
QTemporaryFile is closed if necessary before export and remove the temp file in
cleanup instead of QFile::remove("/tmp/..."); this change should be applied
around the exportPath variable and calls to exportMaterial/importMaterialFile.
In `@src/MeshImporterExporter_test.cpp`:
- Around line 656-685: The test ExportImport_FBX_WithSkeleton_RoundTrip
currently only checks file creation and node count; after reimport it should
locate the newly added scene node/entity (use
Manager::getSingleton()->getSceneNodes().last() and scene manager via
Manager::getSingleton()->getSceneMgr()), retrieve the entity for that node
(sceneMgr->getEntity(sn->getName())), and assert entity->hasSkeleton() (and
optionally assert presence of animations via entity or skeleton animation APIs
you use elsewhere) so the round-trip actually verifies the skeleton was
preserved; add analogous assertions in the similar test referenced (lines
689-717).
In `@src/TransformWidget_test.cpp`:
- Around line 214-220: The test TransformWidgetTests::ScaleSpinBoxMinimum only
asserts scaleX non-null but immediately dereferences scaleY and scaleZ; add
explicit null assertions for both (e.g., ASSERT_NE(scaleY, nullptr);
ASSERT_NE(scaleZ, nullptr);) before the EXPECT_GT checks so the test fails
cleanly if either is missing rather than crashing—place these ASSERT_NE calls
alongside the existing ASSERT_NE(scaleX, nullptr) at the top of the test.
---
Outside diff comments:
In `@src/SpaceCamera_test.cpp`:
- Around line 277-297: The tests call MockSpaceCamera::mouseMoveEvent and
wheelEvent while MockSpaceCamera's mCameraNode and mTarget are null, causing
dereferences in arcBall(), pan(), and zoom(); fix by ensuring the test fixture
initializes valid nodes before invoking input handlers (e.g., construct
MockSpaceCamera with a valid OgreWidget parent or assign/populate mCameraNode
and mTarget in the test setup/fixture) or add early null guards in
MockSpaceCamera::mouseMoveEvent, wheelEvent, arcBall, pan, and zoom to return
early if mCameraNode or mTarget is nullptr; update the tests referencing
MockSpaceCamera, mouseMoveEvent, wheelEvent, arcBall, pan, zoom, mCameraNode,
and mTarget accordingly.
---
Duplicate comments:
In `@src/mainwindow_test.cpp`:
- Around line 1015-1071: Tests are creating QDragEnterEvent instances directly
(in tests like DragEnterEvent_AcceptsMeshFiles, DragEnterEvent_AcceptsFBXFiles,
etc.), which is fragile and bypasses Qt's real drag lifecycle; refactor by
moving the acceptance logic out of MainWindow::dragEnterEvent into a testable
helper (e.g. MainWindow::shouldAcceptDrag(const QMimeData*) or
MainWindow::canAcceptUrls(const QList<QUrl>&)), update dragEnterEvent to call
that helper, and change the unit tests to call the new helper directly (or drive
a real drag with QTest if preferred) so they no longer construct QDragEnterEvent
on the stack and will run reliably under Xvfb.
In `@src/MCPServer_test.cpp`:
- Around line 2518-2600: The tests are bypassing the protocol handlers by
calling callTool() directly; update these tests to exercise the actual handlers:
send the initialize and tools/list protocol messages through
MCPServer::processMessage (or the public handleToolsCall entry point) instead of
server->callTool, invoking the "initialize" and "tools/list" RPC payloads so
handleInitialize and the tools-list handler run; ensure DoubleInitialize
constructs a second MCPServer and sends an "initialize" message to it (and
optionally to the original) to validate real initialization paths and metadata,
and assert on the returned JSON fields (server info and tools metadata) rather
than just non-empty results.
- Around line 2759-2789: The test ExportMesh_ToTempFile uses a hardcoded Unix
/tmp path; change it to use QDir::tempPath() when building exportPath and
cleanup filenames so the test is cross-platform (locate the exportPath variable
in TEST_F(MCPServerTest, ExportMesh_ToTempFile)), construct the full paths with
QDir/QFileInfo join/clean utilities instead of string concatenation, and update
the cleanup QFile::remove calls to remove the same constructed paths (including
the .material path) so Windows and macOS CI run correctly.
- Around line 2606-2651: The tests currently only exercise tool calls and the
unknown-tool path, so add direct coverage for the MCP JSON-RPC resource
endpoints by sending real "resources/list" and "resources/read" requests through
the server's JSON-RPC dispatch (or, if the dispatch is private, add a test-only
friend/helper to call handleResourcesList and handleResourcesRead).
Specifically: invoke resources/list and assert the returned URIs include
"qtmesheditor://material/current" and "qtmesheditor://scene/info"; invoke
resources/read with "qtmesheditor://scene/info" and assert the body contains
"Scene Information"/"Scene Nodes"; also test resources/read with an unknown URI
and with an empty URI and assert the appropriate error messages are returned.
Use the existing server test fixture (server) and reference handleResourcesList,
handleResourcesRead, resources/list, resources/read and callTool to locate
related code.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 870965a7-4e36-4cd6-b684-3b0aae246cd4
📒 Files selected for processing (11)
src/AnimationWidget_test.cppsrc/BoneWeightOverlay_test.cppsrc/LLMManager_test.cppsrc/MCPServer_test.cppsrc/MaterialEditorQML_test.cppsrc/MeshImporterExporter_test.cppsrc/NormalVisualizer_test.cppsrc/SpaceCamera_test.cppsrc/TransformWidget_test.cppsrc/animationcontrolslider_test.cppsrc/mainwindow_test.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
- src/NormalVisualizer_test.cpp
| TEST_F(LLMManagerTest, InitialStateQueries) | ||
| { | ||
| // isModelLoaded: no model loaded during tests (no real model file available) | ||
| // The call should not crash regardless of the return value | ||
| bool loaded = manager->isModelLoaded(); | ||
| // Without a real model file, this should be false | ||
| // (unless autoload succeeded, but typically no model is available in test env) | ||
| (void)loaded; // Suppress unused variable warning | ||
|
|
||
| // isGenerating: should be false when idle | ||
| EXPECT_FALSE(manager->isGenerating()); | ||
|
|
||
| // isLoading: should be false when no model loading is in progress | ||
| EXPECT_FALSE(manager->isLoading()); | ||
|
|
||
| // currentModelName: should be empty or a valid string (no crash) | ||
| QString modelName = manager->currentModelName(); | ||
| (void)modelName; // Just verify no crash | ||
| } |
There was a problem hiding this comment.
Make these singleton-state tests deterministic.
These cases still depend on whatever LLMManager::instance() picked up from persisted settings and the real models directory. On a machine that already has auto-load enabled or a local .gguf, EXPECT_FALSE(manager->isLoading()) can flip and tryAutoLoadModel() can load a real model instead of exercising the “no models available” path. Please force a fresh temp models directory and explicitly disable/restore auto-load inside the test.
Also applies to: 1169-1175
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/LLMManager_test.cpp` around lines 983 - 1001, Make the test deterministic
by forcing a fresh temp models directory and disabling auto-load before
exercising the singleton: in the test (LLMManagerTest) capture the current
singleton via manager = LLMManager::instance(), save/backup the original
auto-load setting and models directory, then call
manager->setAutoLoadOnStartup(false) and
manager->setModelsDirectory(tempDir.path()) (or use the manager/settings API
available) so tryAutoLoadModel() cannot find real models; run the assertions
(isModelLoaded(), isLoading(), isGenerating(), currentModelName()), and finally
restore the original auto-load setting and models directory to avoid global test
pollution.
src/mainwindow_test.cpp
Outdated
| TEST_F(MainWindowTest, MergeAnimationsButton_EnabledWithTwoCompatibleEntities) { | ||
| if (!canLoadMeshFiles()) { | ||
| GTEST_SKIP() << "Skipping: mesh loading not supported in headless mode"; | ||
| } | ||
|
|
||
| auto actionMerge = mainWindow->findChild<QAction*>("actionMerge_Animations"); | ||
| ASSERT_NE(actionMerge, nullptr); | ||
|
|
||
| // Note: createAnimatedTestEntity creates entities with unique skeletons, | ||
| // so they may not be "compatible" for merge (different skeleton instances). | ||
| // We can at least verify the button state is recalculated on selection change. | ||
| auto* entity1 = createAnimatedTestEntity("mainwin_merge_ent1"); | ||
| auto* entity2 = createAnimatedTestEntity("mainwin_merge_ent2"); | ||
| ASSERT_NE(entity1, nullptr); | ||
| ASSERT_NE(entity2, nullptr); | ||
|
|
||
| // Select both entities | ||
| SelectionSet::getSingleton()->selectOne(entity1); | ||
| SelectionSet::getSingleton()->append(entity2); | ||
| if (app) app->processEvents(); | ||
|
|
||
| // The merge button state depends on skeleton compatibility. | ||
| // Since these have different skeletons, it should be disabled. | ||
| // The main test is that the updateMergeAnimationsButton code runs without crash. | ||
| // We just check it's a bool value: | ||
| bool mergeEnabled = actionMerge->isEnabled(); | ||
| (void)mergeEnabled; // The actual value depends on skeleton compatibility | ||
|
|
||
| // Clear and verify disabled | ||
| SelectionSet::getSingleton()->clear(); | ||
| if (app) app->processEvents(); | ||
| EXPECT_FALSE(actionMerge->isEnabled()); | ||
| } |
There was a problem hiding this comment.
This test never verifies the enabled state it claims to cover.
The setup explicitly uses entities that may be incompatible, then discards actionMerge->isEnabled(). If the button never becomes enabled for two compatible entities, this still passes. Please either rename this to a no-crash/selection-recalc test or build two actually compatible entities and assert true.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/mainwindow_test.cpp` around lines 1411 - 1443, The test
TEST_F(MainWindowTest, MergeAnimationsButton_EnabledWithTwoCompatibleEntities)
currently creates two entities via createAnimatedTestEntity that produce
distinct skeletons and then discards the checked value of
actionMerge->isEnabled(), so it doesn't actually verify the enabled state;
either rename the test to reflect "NoCrash_SelectionRecalc" and assert only that
update/selection changes don't crash and that the button becomes disabled after
clearing the selection, or modify the setup to produce two truly compatible
entities (e.g., create one skeleton instance and pass it into a second entity or
clone the same Skeleton pointer used by createAnimatedTestEntity) then select
both via SelectionSet::getSingleton()->selectOne/append, call
app->processEvents(), and assert EXPECT_TRUE(actionMerge->isEnabled()) before
clearing the selection and EXPECT_FALSE(actionMerge->isEnabled()) afterwards so
the intent of actionMerge->isEnabled() is actually verified.
| TEST_F(MaterialEditorQMLWithOgreTest, ApplyMaterial_ColorsReflectedInOgrePass) { | ||
| editor->loadMaterial("BaseWhite"); | ||
| ASSERT_FALSE(editor->passList().isEmpty()); | ||
|
|
||
| // Set distinct colors | ||
| QColor red(255, 0, 0); | ||
| QColor green(0, 255, 0); | ||
| QColor blue(0, 0, 255); | ||
| QColor yellow(255, 255, 0); | ||
|
|
||
| editor->setAmbientColor(red); | ||
| editor->setDiffuseColor(green); | ||
| editor->setSpecularColor(blue); | ||
| editor->setEmissiveColor(yellow); | ||
| editor->setShininess(50.0f); | ||
|
|
||
| // Apply the material | ||
| bool result = editor->applyMaterial(); | ||
| EXPECT_TRUE(result); | ||
|
|
||
| // Reload to verify Ogre actually parsed the applied script | ||
| editor->loadMaterial(editor->materialName()); | ||
| ASSERT_FALSE(editor->passList().isEmpty()); | ||
|
|
||
| // The shininess should be close to what we set | ||
| EXPECT_NEAR(editor->shininess(), 50.0f, 1.0f); | ||
| } |
There was a problem hiding this comment.
The “colors reflected” test never asserts any color state.
Right now this only proves shininess round-trips. If ambient/diffuse/specular/emissive serialization breaks, the test still passes. Please either assert the reloaded colors explicitly or rename the test to match what it actually verifies.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MaterialEditorQML_test.cpp` around lines 2322 - 2348, The test
ApplyMaterial_ColorsReflectedInOgrePass currently only checks shininess; after
reloading the material via editor->loadMaterial(editor->materialName()) you must
also assert that the ambient/diffuse/specular/emissive colors round-trip by
comparing editor->ambientColor(), editor->diffuseColor(),
editor->specularColor(), and editor->emissiveColor() to the originally set
QColor values (red, green, blue, yellow) using appropriate equality/fuzzy color
checks (e.g., EXPECT_EQ or color component comparisons) so the test actually
verifies color serialization in addition to shininess; alternatively, if you
don’t want to add asserts, rename the TEST_F to reflect it only verifies
shininess round-trip.
- Replace hard-coded /tmp/ paths with QDir::tempPath() for cross-platform compatibility (FBXExporter, MCPServer, MaterialEditorQML tests) - Strengthen SkeletonDebug assertions: ASSERT_TRUE instead of if-guards, remove || true that made assertions always pass - Add SelectionSet::clear() in TransformOperator SetUp/TearDown for test isolation - Add missing null checks for scaleY/scaleZ in TransformWidget test - Add skeleton verification after FBX/Collada reimport round-trips - Add color assertions in MaterialEditorQML ApplyMaterial test - Rename misleading MCPServer protocol tests to reflect actual behavior - Add EXPECT_FALSE assertions in LLMManager tests instead of (void) casts - Rename mainwindow MergeAnimationsButton test to match actual coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (8)
src/MCPServer_test.cpp (2)
2518-2551:⚠️ Potential issue | 🟠 MajorThese “protocol edge case” tests still bypass the protocol handlers.
They only call
callTool()or construct a secondMCPServer, so regressions ininitialize/tools/listmetadata or initialize idempotency would still pass. This also overlaps the earlierHandleToolsListsmoke test instead of covering the protocol path it is named after.Also applies to: 2588-2600
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2518 - 2551, The tests callTool()/constructing a second MCPServer bypass the actual protocol handlers (e.g., handleInitialize, HandleToolsList) so they miss regressions in initialize/tools metadata and duplicate the existing HandleToolsList test; update ServerFunctionalAfterConstruction and AllToolNamesAreRecognized to send real protocol requests through the protocol entry point (invoke the server method that processes JSON-RPC/protocol requests rather than callTool), simulate an "initialize" request where appropriate to test idempotency, and exercise the "tools/list" protocol handler (HandleToolsList) to verify tool metadata is served and names are recognized; ensure the new tests use the same request format as production protocol messages and remove/merge duplicate assertions that overlap the existing HandleToolsList smoke test.
2605-2641:⚠️ Potential issue | 🟠 MajorThis resource-protocol block still never exercises the resource RPCs.
callTool("get_scene_info"),callTool("get_material"), and the unknown-tool branch only retest tool dispatch. A break inresources/list/resources/read, URI parsing, or resource registration would still leave these tests green.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MCPServer_test.cpp` around lines 2605 - 2641, Tests only exercise tool dispatch via callTool("get_scene_info") / callTool("get_material") and miss the actual resource RPCs; add assertions that call the resource RPC endpoints directly (e.g., invoke the server's resource RPCs "resources/list" and "resources/read" with the same URIs like "qtmesheditor://scene/info" and the material URI) so URI parsing, resource registration, and the resources/list/read handlers are exercised. In practice, extend the existing tests (e.g., the GetSceneInfo_* and GetMaterial* cases) to call the resource RPCs instead of or in addition to callTool, verify isError(false) for valid URIs and that the returned payload contains the expected "Scene Information" / "Scene Nodes" or material data, and add a negative test that calls resources/read with a nonexistent URI to assert the proper error path. Ensure you reference and exercise the same identifiers used by the server (resources/list, resources/read, the resource URIs) and adjust any test setup to register or mock the resource provider so the resource handlers are actually invoked.src/LLMManager_test.cpp (2)
983-1001:⚠️ Potential issue | 🟠 MajorThese singleton-state tests are still environment-dependent.
They assume no saved auto-load setting and no real model files in the configured models directory, but
LLMManager::instance()is reused as-is. On a machine that already has auto-load enabled or a local.gguf, bothEXPECT_FALSE(loaded)and the “no models available” path can flip nondeterministically.Also applies to: 1169-1175
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/LLMManager_test.cpp` around lines 983 - 1001, The tests are flaky because they rely on global singleton state from LLMManager::instance() (affecting isModelLoaded(), isGenerating(), isLoading(), currentModelName()); make the tests deterministic by resetting or isolating the singleton before each test: either add and call a test-only LLMManager::resetInstance() (or similar) to recreate a fresh instance, or provide test hooks to override autoload and models directory (e.g., setAutoLoad(false) and setModelsDirectory(tempDir)) and ensure the fixture calls them before obtaining manager->isModelLoaded(); update the InitialStateQueries test (and the similar block at 1169-1175) to use the reset/isolation hook so the assertions are not environment-dependent.
1152-1163:⚠️ Potential issue | 🟡 MinorThe failure path is still not asserted.
errorSpyis created but never checked, and the fixedmsleep(100)only adds timing sensitivity. This can pass even ifloadModel()stops emittingmodelLoadError.Suggested fix
TEST_F(LLMManagerTest, LoadModel_NonExistentModel) { QSignalSpy errorSpy(manager, &LLMManager::modelLoadError); manager->loadModel("completely_nonexistent_model_xyz_999"); - // Allow some time for the async operation to report an error - QThread::msleep(100); - if (QCoreApplication::instance()) { - QCoreApplication::instance()->processEvents(); - } + if (errorSpy.isEmpty()) { + ASSERT_TRUE(errorSpy.wait(1000)); + } + EXPECT_FALSE(errorSpy.isEmpty()); // Verify no model became loaded EXPECT_FALSE(manager->isModelLoaded()); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/LLMManager_test.cpp` around lines 1152 - 1163, The test creates a QSignalSpy (errorSpy) for LLMManager::modelLoadError but never asserts it; replace the fixed QThread::msleep with a robust wait that asserts the error signal was emitted (e.g., use QTRY_COMPARE or QTRY_VERIFY on errorSpy.count() > 0) after calling manager->loadModel("completely_nonexistent_model_xyz_999"), then assert the expected number of error signals (e.g., EXPECT_EQ(errorSpy.count(), 1)) and optionally inspect the signal arguments, and finally keep the existing EXPECT_FALSE(manager->isModelLoaded()) to ensure no model loaded.src/mainwindow_test.cpp (1)
1015-1071:⚠️ Potential issue | 🟠 MajorAvoid constructing
QDragEnterEventdirectly in tests.Qt expects drag-enter events to be created during a real drag lifecycle. Manually instantiating them skips that internal state, so these acceptance checks are brittle and platform-dependent. Prefer driving an actual drag interaction or extracting the acceptance logic behind
dragEnterEvent()into a helper that can be tested fromQMimeData.Also applies to: 1287-1297
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mainwindow_test.cpp` around lines 1015 - 1071, The tests create QDragEnterEvent instances directly which is brittle; refactor the drag acceptance logic into a testable helper (e.g., MainWindow::acceptsDrag(const QMimeData*) or MainWindow::isAcceptableMimeData) and have dragEnterEvent() call that helper, then update the tests DragEnterEvent_AcceptsMeshFiles, DragEnterEvent_AcceptsFBXFiles, DragEnterEvent_AcceptsOBJFiles, DragEnterEvent_AcceptsDAEFiles, DragEnterEvent_AcceptsNonMeshFiles and DragEnterEvent_AcceptsEmptyUrls to construct QMimeData and call the new helper instead of constructing QDragEnterEvent; ensure the helper signature is public or test-visible and that dragEnterEvent still uses the same semantics so behavior remains unchanged.src/FBX/FBXExporter_test.cpp (1)
2359-2410:⚠️ Potential issue | 🟠 MajorThese new parser-based tests still depend on a POSIX-only helper.
FBXExporterCoverageTest::exportAndParse()still writes to"/tmp/fbx_coverage_%1.fbx", so the added tests that call it remain Windows-incompatible even though the direct smoke tests were switched toQDir::tempPath(). Please make the helper portable as well.Also applies to: 2467-2540
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/FBX/FBXExporter_test.cpp` around lines 2359 - 2410, The tests fail on Windows because FBXExporterCoverageTest::exportAndParse still writes to a hardcoded "/tmp/fbx_coverage_%1.fbx"; update that helper to use a portable temp location (e.g., QDir::tempPath() or QTemporaryFile) to create the temporary FBX file name and ensure proper cleanup, so all tests (including those at the later range) no longer depend on POSIX-only paths; locate exportAndParse in FBXExporterCoverageTest and replace the hardcoded path logic with a cross-platform temp-file creation approach.src/MaterialEditorQML_test.cpp (1)
2323-2355:⚠️ Potential issue | 🟡 MinorAssert all round-tripped colors, including emissive.
This still only checks one channel for ambient/diffuse/specular, and
emissiveColor()is never checked. The test can pass even when most of the color serialization is wrong.Strengthen the round-trip assertions
// The shininess should be close to what we set EXPECT_NEAR(editor->shininess(), 50.0f, 1.0f); - // Verify the colors round-tripped - // Note: Ogre may adjust color precision, so we use component comparison - EXPECT_NEAR(editor->ambientColor().redF(), 1.0, 0.1); - EXPECT_NEAR(editor->diffuseColor().greenF(), 1.0, 0.1); - EXPECT_NEAR(editor->specularColor().blueF(), 1.0, 0.1); + auto expectColorNear = [](const QColor& actual, const QColor& expected) { + EXPECT_NEAR(actual.redF(), expected.redF(), 0.1); + EXPECT_NEAR(actual.greenF(), expected.greenF(), 0.1); + EXPECT_NEAR(actual.blueF(), expected.blueF(), 0.1); + }; + + expectColorNear(editor->ambientColor(), red); + expectColorNear(editor->diffuseColor(), green); + expectColorNear(editor->specularColor(), blue); + expectColorNear(editor->emissiveColor(), yellow);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MaterialEditorQML_test.cpp` around lines 2323 - 2355, The test ApplyMaterial_ColorsReflectedInOgrePass only asserts a single channel per color and never checks emissive; update the test (TEST_F MaterialEditorQMLWithOgreTest ApplyMaterial_ColorsReflectedInOgrePass) to verify all color components for each property returned by ambientColor(), diffuseColor(), specularColor(), and emissiveColor() (compare redF(), greenF(), blueF(), and alpha if relevant) using EXPECT_NEAR against the original QColor components (red/green/blue mapped to 0..1) with an appropriate tolerance (e.g. 0.01–0.1) so the round-trip fully validates serialization, and keep the existing shininess() EXPECT_NEAR check.src/MeshImporterExporter_test.cpp (1)
682-687:⚠️ Potential issue | 🟡 MinorMake the reimported entity/skeleton checks mandatory.
These guarded blocks let the tests pass when reimport never creates an entity or never attaches a skeleton. Use
ASSERT_TRUE(sceneMgr->hasEntity(...))/ASSERT_NE(...), and in the XML pathASSERT_TRUE(reimportedEntity->hasSkeleton()), before the final assertions.Fail fast when the reimport target is missing
- if (sceneMgr->hasEntity(reimportedNode->getName())) { - auto* reimportedEntity = sceneMgr->getEntity(reimportedNode->getName()); - EXPECT_TRUE(reimportedEntity->hasSkeleton()); - } + ASSERT_TRUE(sceneMgr->hasEntity(reimportedNode->getName())); + auto* reimportedEntity = sceneMgr->getEntity(reimportedNode->getName()); + ASSERT_NE(reimportedEntity, nullptr); + ASSERT_TRUE(reimportedEntity->hasSkeleton());Also applies to: 721-726, 1001-1011
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/MeshImporterExporter_test.cpp` around lines 682 - 687, The test currently uses conditional checks that let the test continue when the reimported entity or its skeleton is missing; replace those guarded EXPECT checks with hard assertions so the test fails fast: in the block using Manager::getSingleton()->getSceneNodes().last() change the scene existence check to ASSERT_TRUE(sceneMgr->hasEntity(reimportedNode->getName())) (or ASSERT_NE(sceneMgr->getEntity(reimportedNode->getName()), nullptr)) and then assert the skeleton with ASSERT_TRUE(reimportedEntity->hasSkeleton()) instead of EXPECT_TRUE; apply the same replacement pattern to the other similar blocks around the regions referencing getSceneNodes(), sceneMgr->hasEntity/getEntity and reimportedEntity->hasSkeleton (notably the blocks you flagged at 721-726 and 1001-1011).
🧹 Nitpick comments (1)
src/TransformWidget_test.cpp (1)
204-211: Consider testing all three axes for consistency.This test only validates
positionXproperties, whileScaleSpinBoxMinimumvalidates all three axes. If the ranges/decimals should be identical across X/Y/Z, consider adding assertions forpositionYandpositionZfor completeness.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/TransformWidget_test.cpp` around lines 204 - 211, The PositionSpinBoxRanges test only checks positionX; extend it to assert the same properties for positionY and positionZ to ensure consistency: verify positionY and positionZ are non-null and that their minimum() <= -10000.0, maximum() >= 10000.0, and decimals() == 4 (same checks currently applied to positionX); update the TEST_F(TransformWidgetTests, PositionSpinBoxRanges) to include these assertions referencing positionY and positionZ.
🤖 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/mainwindow_test.cpp`:
- Around line 1303-1339: The test reads anim times but never asserts they
changed; update TEST_F(MainWindowTest,
FrameRenderingQueued_WithAnimatedEntity_AdvancesAnimation) to assert that the
animation progressed after rendering by adding an assertion comparing timeAfter
and timeBefore (e.g., EXPECT_NE(timeAfter, timeBefore) or EXPECT_GT(timeAfter,
timeBefore) with a small epsilon if you prefer), and assert that stopping
playback does not reset the animation by checking timeAfterStop is not less than
timeAfter (e.g., EXPECT_GE(timeAfterStop, timeAfter - 1e-6f)); use the existing
createAnimatedTestEntity, animState (getAnimationState / getTimePosition),
mainWindow->setPlaying and renderOneFrame calls to locate where to insert these
assertions.
In `@src/MaterialEditorQML_test.cpp`:
- Around line 2286-2304: The test calls editor->importMaterialFile(exportPath)
but never verifies the import succeeded; after the import call, add a concrete
assertion such as re-loading the material and checking the editor state: call
editor->loadMaterial("RoundTripTestMat") and then
ASSERT_FALSE(editor->techniqueList().isEmpty()) (or ASSERT_TRUE if there is a
boolean return from importMaterialFile) to ensure the imported material is
present and valid; update TEST_F(MaterialEditorQMLWithOgreTest,
ExportAndImportMaterial_RoundTrip) accordingly so the import step has an
observable postcondition.
In `@src/MCPServer_test.cpp`:
- Around line 2686-2707: The stop branch isn't actually exercised and no
post-stop assertion exists: in TEST_F(MCPServerTest, PlayAnimation_StartAndStop)
replace stopArgs["stop"] = true with the API's actual stop flag
(stopArgs["play"] = false) so the test covers the same parameter used elsewhere,
then after server->callTool("play_animation", stopArgs) add a check that
playback was disabled by querying the animation state (e.g., call
server->callTool("get_animation_state" or equivalent with entity
"MCPPlayStopAnimEntity" / animation "TestAnim") and ASSERT/EXPECT that the
returned playing flag is false) while still asserting no error via
isError(stopResult).
In `@src/MeshImporterExporter_test.cpp`:
- Around line 1021-1038: The tests ExportOBJNoMTL and
ExportOBJNoMTL_FromImportedMesh currently only check that the exported .objnomtl
file exists but don't assert that no .mtl sidecar was produced; update both
TEST_F functions (MeshImporterExporterTest::ExportOBJNoMTL and
::ExportOBJNoMTL_FromImportedMesh) to additionally assert that
QFile::exists("./nomtl_export.mtl") is false (or use EXPECT_FALSE/QVERIFY)
immediately after verifying the main file, and keep the cleanup that removes
"./nomtl_export.mtl" and "./nomtl_export.material" to be safe.
In `@src/TransformOperator_test.cpp`:
- Around line 598-622: The test sets up TransformOperator and runs a batch of
no-op transform calls before attaching QSignalSpy objects, so emitted signals
are missed; to fix, move the QSignalSpy creations (posSpy, orientSpy, deleteSpy)
to directly after obtaining TransformOperator::getSingleton() and before calling
setSelectedPosition/translateSelected/setSelectedScale/scaleSelected/setSelectedOrientation/rotateSelected/removeSelected
so you capture any emissions from those operations, then assert posSpy.count(),
orientSpy.count(), and deleteSpy.count() are zero after the no-op sequence to
validate no signals were emitted.
---
Duplicate comments:
In `@src/FBX/FBXExporter_test.cpp`:
- Around line 2359-2410: The tests fail on Windows because
FBXExporterCoverageTest::exportAndParse still writes to a hardcoded
"/tmp/fbx_coverage_%1.fbx"; update that helper to use a portable temp location
(e.g., QDir::tempPath() or QTemporaryFile) to create the temporary FBX file name
and ensure proper cleanup, so all tests (including those at the later range) no
longer depend on POSIX-only paths; locate exportAndParse in
FBXExporterCoverageTest and replace the hardcoded path logic with a
cross-platform temp-file creation approach.
In `@src/LLMManager_test.cpp`:
- Around line 983-1001: The tests are flaky because they rely on global
singleton state from LLMManager::instance() (affecting isModelLoaded(),
isGenerating(), isLoading(), currentModelName()); make the tests deterministic
by resetting or isolating the singleton before each test: either add and call a
test-only LLMManager::resetInstance() (or similar) to recreate a fresh instance,
or provide test hooks to override autoload and models directory (e.g.,
setAutoLoad(false) and setModelsDirectory(tempDir)) and ensure the fixture calls
them before obtaining manager->isModelLoaded(); update the InitialStateQueries
test (and the similar block at 1169-1175) to use the reset/isolation hook so the
assertions are not environment-dependent.
- Around line 1152-1163: The test creates a QSignalSpy (errorSpy) for
LLMManager::modelLoadError but never asserts it; replace the fixed
QThread::msleep with a robust wait that asserts the error signal was emitted
(e.g., use QTRY_COMPARE or QTRY_VERIFY on errorSpy.count() > 0) after calling
manager->loadModel("completely_nonexistent_model_xyz_999"), then assert the
expected number of error signals (e.g., EXPECT_EQ(errorSpy.count(), 1)) and
optionally inspect the signal arguments, and finally keep the existing
EXPECT_FALSE(manager->isModelLoaded()) to ensure no model loaded.
In `@src/mainwindow_test.cpp`:
- Around line 1015-1071: The tests create QDragEnterEvent instances directly
which is brittle; refactor the drag acceptance logic into a testable helper
(e.g., MainWindow::acceptsDrag(const QMimeData*) or
MainWindow::isAcceptableMimeData) and have dragEnterEvent() call that helper,
then update the tests DragEnterEvent_AcceptsMeshFiles,
DragEnterEvent_AcceptsFBXFiles, DragEnterEvent_AcceptsOBJFiles,
DragEnterEvent_AcceptsDAEFiles, DragEnterEvent_AcceptsNonMeshFiles and
DragEnterEvent_AcceptsEmptyUrls to construct QMimeData and call the new helper
instead of constructing QDragEnterEvent; ensure the helper signature is public
or test-visible and that dragEnterEvent still uses the same semantics so
behavior remains unchanged.
In `@src/MaterialEditorQML_test.cpp`:
- Around line 2323-2355: The test ApplyMaterial_ColorsReflectedInOgrePass only
asserts a single channel per color and never checks emissive; update the test
(TEST_F MaterialEditorQMLWithOgreTest ApplyMaterial_ColorsReflectedInOgrePass)
to verify all color components for each property returned by ambientColor(),
diffuseColor(), specularColor(), and emissiveColor() (compare redF(), greenF(),
blueF(), and alpha if relevant) using EXPECT_NEAR against the original QColor
components (red/green/blue mapped to 0..1) with an appropriate tolerance (e.g.
0.01–0.1) so the round-trip fully validates serialization, and keep the existing
shininess() EXPECT_NEAR check.
In `@src/MCPServer_test.cpp`:
- Around line 2518-2551: The tests callTool()/constructing a second MCPServer
bypass the actual protocol handlers (e.g., handleInitialize, HandleToolsList) so
they miss regressions in initialize/tools metadata and duplicate the existing
HandleToolsList test; update ServerFunctionalAfterConstruction and
AllToolNamesAreRecognized to send real protocol requests through the protocol
entry point (invoke the server method that processes JSON-RPC/protocol requests
rather than callTool), simulate an "initialize" request where appropriate to
test idempotency, and exercise the "tools/list" protocol handler
(HandleToolsList) to verify tool metadata is served and names are recognized;
ensure the new tests use the same request format as production protocol messages
and remove/merge duplicate assertions that overlap the existing HandleToolsList
smoke test.
- Around line 2605-2641: Tests only exercise tool dispatch via
callTool("get_scene_info") / callTool("get_material") and miss the actual
resource RPCs; add assertions that call the resource RPC endpoints directly
(e.g., invoke the server's resource RPCs "resources/list" and "resources/read"
with the same URIs like "qtmesheditor://scene/info" and the material URI) so URI
parsing, resource registration, and the resources/list/read handlers are
exercised. In practice, extend the existing tests (e.g., the GetSceneInfo_* and
GetMaterial* cases) to call the resource RPCs instead of or in addition to
callTool, verify isError(false) for valid URIs and that the returned payload
contains the expected "Scene Information" / "Scene Nodes" or material data, and
add a negative test that calls resources/read with a nonexistent URI to assert
the proper error path. Ensure you reference and exercise the same identifiers
used by the server (resources/list, resources/read, the resource URIs) and
adjust any test setup to register or mock the resource provider so the resource
handlers are actually invoked.
In `@src/MeshImporterExporter_test.cpp`:
- Around line 682-687: The test currently uses conditional checks that let the
test continue when the reimported entity or its skeleton is missing; replace
those guarded EXPECT checks with hard assertions so the test fails fast: in the
block using Manager::getSingleton()->getSceneNodes().last() change the scene
existence check to ASSERT_TRUE(sceneMgr->hasEntity(reimportedNode->getName()))
(or ASSERT_NE(sceneMgr->getEntity(reimportedNode->getName()), nullptr)) and then
assert the skeleton with ASSERT_TRUE(reimportedEntity->hasSkeleton()) instead of
EXPECT_TRUE; apply the same replacement pattern to the other similar blocks
around the regions referencing getSceneNodes(), sceneMgr->hasEntity/getEntity
and reimportedEntity->hasSkeleton (notably the blocks you flagged at 721-726 and
1001-1011).
---
Nitpick comments:
In `@src/TransformWidget_test.cpp`:
- Around line 204-211: The PositionSpinBoxRanges test only checks positionX;
extend it to assert the same properties for positionY and positionZ to ensure
consistency: verify positionY and positionZ are non-null and that their
minimum() <= -10000.0, maximum() >= 10000.0, and decimals() == 4 (same checks
currently applied to positionX); update the TEST_F(TransformWidgetTests,
PositionSpinBoxRanges) to include these assertions referencing positionY and
positionZ.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b702086e-ae6d-4b95-8a15-219815bf8b27
📒 Files selected for processing (9)
src/FBX/FBXExporter_test.cppsrc/LLMManager_test.cppsrc/MCPServer_test.cppsrc/MaterialEditorQML_test.cppsrc/MeshImporterExporter_test.cppsrc/SkeletonDebug_test.cppsrc/TransformOperator_test.cppsrc/TransformWidget_test.cppsrc/mainwindow_test.cpp
| TEST_F(MainWindowTest, FrameRenderingQueued_WithAnimatedEntity_AdvancesAnimation) { | ||
| if (!canLoadMeshFiles()) { | ||
| GTEST_SKIP() << "Skipping: mesh loading not supported in headless mode"; | ||
| } | ||
|
|
||
| // Create an animated entity | ||
| auto* entity = createAnimatedTestEntity("mainwin_animated_frame"); | ||
| ASSERT_NE(entity, nullptr); | ||
|
|
||
| // Enable the animation | ||
| auto* animState = entity->getAnimationState("TestAnim"); | ||
| ASSERT_NE(animState, nullptr); | ||
| animState->setEnabled(true); | ||
| animState->setLoop(true); | ||
|
|
||
| float timeBefore = animState->getTimePosition(); | ||
|
|
||
| // Set playing to true and render frames | ||
| mainWindow->setPlaying(true); | ||
| Manager::getSingleton()->getRoot()->renderOneFrame(); | ||
| Manager::getSingleton()->getRoot()->renderOneFrame(); | ||
|
|
||
| float timeAfter = animState->getTimePosition(); | ||
|
|
||
| // Animation time should have advanced (unless render time is exactly 0) | ||
| // In practice, the timeSinceLastFrame might be very small, so we just | ||
| // verify it didn't crash and the animation is still enabled | ||
| EXPECT_TRUE(animState->getEnabled()); | ||
| EXPECT_TRUE(animState->getLoop()); | ||
|
|
||
| // Stop playing | ||
| mainWindow->setPlaying(false); | ||
| Manager::getSingleton()->getRoot()->renderOneFrame(); | ||
|
|
||
| // Animation should remain at its current position (not reset) | ||
| float timeAfterStop = animState->getTimePosition(); | ||
| EXPECT_GE(timeAfterStop, 0.0f); |
There was a problem hiding this comment.
This test never verifies that animation time advanced.
timeBefore, timeAfter, and timeAfterStop are read but never compared, and the only assertions are on flags the test sets itself. A regression where frameRenderingQueued() stops advancing animations would still pass here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/mainwindow_test.cpp` around lines 1303 - 1339, The test reads anim times
but never asserts they changed; update TEST_F(MainWindowTest,
FrameRenderingQueued_WithAnimatedEntity_AdvancesAnimation) to assert that the
animation progressed after rendering by adding an assertion comparing timeAfter
and timeBefore (e.g., EXPECT_NE(timeAfter, timeBefore) or EXPECT_GT(timeAfter,
timeBefore) with a small epsilon if you prefer), and assert that stopping
playback does not reset the animation by checking timeAfterStop is not less than
timeAfter (e.g., EXPECT_GE(timeAfterStop, timeAfter - 1e-6f)); use the existing
createAnimatedTestEntity, animState (getAnimationState / getTimePosition),
mainWindow->setPlaying and renderOneFrame calls to locate where to insert these
assertions.
| TEST_F(MaterialEditorQMLWithOgreTest, ExportAndImportMaterial_RoundTrip) { | ||
| // Create a custom material | ||
| editor->createNewMaterial("RoundTripTestMat"); | ||
| EXPECT_TRUE(editor->applyMaterial()); | ||
|
|
||
| // Load the material via Ogre to set it up properly | ||
| editor->loadMaterial("RoundTripTestMat"); | ||
| ASSERT_FALSE(editor->techniqueList().isEmpty()); | ||
|
|
||
| // Export it | ||
| QString exportPath = QDir(QDir::tempPath()).filePath("round_trip_test.material"); | ||
| editor->exportMaterial(exportPath); | ||
| EXPECT_TRUE(QFile::exists(exportPath)); | ||
|
|
||
| // Now import it -- importMaterialFile reads .material files | ||
| editor->importMaterialFile(exportPath); | ||
|
|
||
| // Clean up | ||
| QFile::remove(exportPath); |
There was a problem hiding this comment.
Round-trip test never validates the import step.
editor->importMaterialFile(exportPath) has no observable postcondition here, so a silent import failure still passes. Either assert a visible import result or rename this to a smoke test.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MaterialEditorQML_test.cpp` around lines 2286 - 2304, The test calls
editor->importMaterialFile(exportPath) but never verifies the import succeeded;
after the import call, add a concrete assertion such as re-loading the material
and checking the editor state: call editor->loadMaterial("RoundTripTestMat") and
then ASSERT_FALSE(editor->techniqueList().isEmpty()) (or ASSERT_TRUE if there is
a boolean return from importMaterialFile) to ensure the imported material is
present and valid; update TEST_F(MaterialEditorQMLWithOgreTest,
ExportAndImportMaterial_RoundTrip) accordingly so the import step has an
observable postcondition.
| TEST_F(MCPServerTest, PlayAnimation_StartAndStop) | ||
| { | ||
| if (!canLoadMeshFiles()) { GTEST_SKIP() << "Skipping: entity creation not supported without render window"; } | ||
|
|
||
| Ogre::Entity* entity = createAnimatedTestEntity("MCPPlayStopAnimEntity"); | ||
| ASSERT_NE(entity, nullptr); | ||
|
|
||
| // Start playing | ||
| QJsonObject playArgs; | ||
| playArgs["entity"] = "MCPPlayStopAnimEntity"; | ||
| playArgs["animation"] = "TestAnim"; | ||
| QJsonObject playResult = server->callTool("play_animation", playArgs); | ||
| EXPECT_FALSE(isError(playResult)); | ||
|
|
||
| // Stop playing | ||
| QJsonObject stopArgs; | ||
| stopArgs["entity"] = "MCPPlayStopAnimEntity"; | ||
| stopArgs["animation"] = "TestAnim"; | ||
| stopArgs["stop"] = true; | ||
| QJsonObject stopResult = server->callTool("play_animation", stopArgs); | ||
| EXPECT_FALSE(isError(stopResult)); | ||
| } |
There was a problem hiding this comment.
Use the actual stop parameter and verify the animation state flips.
This test stops play_animation with stop = true, but the later success-path test uses play = false for the same API. As written, this can pass without ever covering the stop branch, and it never asserts that playback was disabled afterward.
Suggested fix
TEST_F(MCPServerTest, PlayAnimation_StartAndStop)
{
if (!canLoadMeshFiles()) { GTEST_SKIP() << "Skipping: entity creation not supported without render window"; }
Ogre::Entity* entity = createAnimatedTestEntity("MCPPlayStopAnimEntity");
ASSERT_NE(entity, nullptr);
// Start playing
QJsonObject playArgs;
playArgs["entity"] = "MCPPlayStopAnimEntity";
playArgs["animation"] = "TestAnim";
QJsonObject playResult = server->callTool("play_animation", playArgs);
EXPECT_FALSE(isError(playResult));
// Stop playing
QJsonObject stopArgs;
stopArgs["entity"] = "MCPPlayStopAnimEntity";
stopArgs["animation"] = "TestAnim";
- stopArgs["stop"] = true;
+ stopArgs["play"] = false;
QJsonObject stopResult = server->callTool("play_animation", stopArgs);
EXPECT_FALSE(isError(stopResult));
+
+ Ogre::AnimationState* state = entity->getAnimationState("TestAnim");
+ ASSERT_NE(state, nullptr);
+ EXPECT_FALSE(state->getEnabled());
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MCPServer_test.cpp` around lines 2686 - 2707, The stop branch isn't
actually exercised and no post-stop assertion exists: in TEST_F(MCPServerTest,
PlayAnimation_StartAndStop) replace stopArgs["stop"] = true with the API's
actual stop flag (stopArgs["play"] = false) so the test covers the same
parameter used elsewhere, then after server->callTool("play_animation",
stopArgs) add a check that playback was disabled by querying the animation state
(e.g., call server->callTool("get_animation_state" or equivalent with entity
"MCPPlayStopAnimEntity" / animation "TestAnim") and ASSERT/EXPECT that the
returned playing flag is false) while still asserting no error via
isError(stopResult).
| TEST_F(MeshImporterExporterTest, ExportOBJNoMTL) { | ||
| if (!canLoadMeshFiles()) { | ||
| GTEST_SKIP() << "Skipping: mesh loading not supported in headless mode"; | ||
| } | ||
|
|
||
| auto mesh = createInMemoryTriangleMesh("ExportOBJNoMTLTriangle"); | ||
| auto* sceneMgr = Manager::getSingleton()->getSceneMgr(); | ||
| auto* node = Manager::getSingleton()->addSceneNode("ExportOBJNoMTLNode"); | ||
| auto* entity = sceneMgr->createEntity("ExportOBJNoMTLEntity", mesh); | ||
| node->attachObject(entity); | ||
|
|
||
| ASSERT_EQ(MeshImporterExporter::exporter(node, "./nomtl_export.objnomtl", "OBJ without MTL (*.objnomtl)"), 0); | ||
| EXPECT_TRUE(QFile::exists("./nomtl_export.objnomtl")); | ||
|
|
||
| // Clean up | ||
| QFile::remove("./nomtl_export.objnomtl"); | ||
| QFile::remove("./nomtl_export.material"); | ||
| QFile::remove("./nomtl_export.mtl"); |
There was a problem hiding this comment.
Lock down the objnomtl contract.
Both tests only assert that the exported model file exists. If the exporter regresses and writes an .mtl sidecar again, the tests still pass because cleanup just deletes it.
Add the missing no-`.mtl` assertion
ASSERT_EQ(MeshImporterExporter::exporter(node, "./nomtl_export.objnomtl", "OBJ without MTL (*.objnomtl)"), 0);
EXPECT_TRUE(QFile::exists("./nomtl_export.objnomtl"));
+ EXPECT_FALSE(QFile::exists("./nomtl_export.mtl"));Apply the same check in TEST_F(MeshImporterExporterTest, ExportOBJNoMTL_FromImportedMesh).
Also applies to: 1041-1056
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/MeshImporterExporter_test.cpp` around lines 1021 - 1038, The tests
ExportOBJNoMTL and ExportOBJNoMTL_FromImportedMesh currently only check that the
exported .objnomtl file exists but don't assert that no .mtl sidecar was
produced; update both TEST_F functions (MeshImporterExporterTest::ExportOBJNoMTL
and ::ExportOBJNoMTL_FromImportedMesh) to additionally assert that
QFile::exists("./nomtl_export.mtl") is false (or use EXPECT_FALSE/QVERIFY)
immediately after verifying the main file, and keep the cleanup that removes
"./nomtl_export.mtl" and "./nomtl_export.material" to be safe.
| TEST_F(TransformOperatorTestFixture, AllOperations_EmptyScene) { | ||
| TransformOperator* instance = TransformOperator::getSingleton(); | ||
| ASSERT_TRUE(SelectionSet::getSingleton()->isEmpty()); | ||
|
|
||
| // All transform operations on empty selection should be safe | ||
| EXPECT_NO_THROW(instance->setSelectedPosition(Ogre::Vector3(100, 200, 300))); | ||
| EXPECT_NO_THROW(instance->translateSelected(Ogre::Vector3(1, 2, 3))); | ||
| EXPECT_NO_THROW(instance->setSelectedScale(Ogre::Vector3(5, 5, 5))); | ||
| EXPECT_NO_THROW(instance->scaleSelected(Ogre::Vector3(2, 2, 2))); | ||
| EXPECT_NO_THROW(instance->setSelectedOrientation(Ogre::Vector3(90, 180, 270))); | ||
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_X))); | ||
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Vector3(45, 45, 45))); | ||
| EXPECT_NO_THROW(instance->removeSelected()); | ||
|
|
||
| // No signals should have been emitted | ||
| QSignalSpy posSpy(instance, &TransformOperator::selectedPositionChanged); | ||
| QSignalSpy orientSpy(instance, &TransformOperator::selectedOrientationChanged); | ||
| QSignalSpy deleteSpy(instance, &TransformOperator::objectsDeleted); | ||
|
|
||
| instance->setSelectedPosition(Ogre::Vector3(1, 1, 1)); | ||
| EXPECT_EQ(posSpy.count(), 0); | ||
|
|
||
| instance->setSelectedOrientation(Ogre::Vector3(45, 45, 45)); | ||
| EXPECT_EQ(orientSpy.count(), 0); | ||
| } |
There was a problem hiding this comment.
Attach the spies before the empty-scene operations.
The first no-op batch runs before any QSignalSpy is connected, so those emissions are invisible, and deleteSpy is never asserted. This doesn't currently prove the "no signals" claim.
Capture the full no-op sequence
TEST_F(TransformOperatorTestFixture, AllOperations_EmptyScene) {
TransformOperator* instance = TransformOperator::getSingleton();
ASSERT_TRUE(SelectionSet::getSingleton()->isEmpty());
+ QSignalSpy posSpy(instance, &TransformOperator::selectedPositionChanged);
+ QSignalSpy orientSpy(instance, &TransformOperator::selectedOrientationChanged);
+ QSignalSpy deleteSpy(instance, &TransformOperator::objectsDeleted);
+
// All transform operations on empty selection should be safe
EXPECT_NO_THROW(instance->setSelectedPosition(Ogre::Vector3(100, 200, 300)));
EXPECT_NO_THROW(instance->translateSelected(Ogre::Vector3(1, 2, 3)));
EXPECT_NO_THROW(instance->setSelectedScale(Ogre::Vector3(5, 5, 5)));
EXPECT_NO_THROW(instance->scaleSelected(Ogre::Vector3(2, 2, 2)));
@@
- // No signals should have been emitted
- QSignalSpy posSpy(instance, &TransformOperator::selectedPositionChanged);
- QSignalSpy orientSpy(instance, &TransformOperator::selectedOrientationChanged);
- QSignalSpy deleteSpy(instance, &TransformOperator::objectsDeleted);
-
- instance->setSelectedPosition(Ogre::Vector3(1, 1, 1));
EXPECT_EQ(posSpy.count(), 0);
-
- instance->setSelectedOrientation(Ogre::Vector3(45, 45, 45));
EXPECT_EQ(orientSpy.count(), 0);
+ EXPECT_EQ(deleteSpy.count(), 0);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| TEST_F(TransformOperatorTestFixture, AllOperations_EmptyScene) { | |
| TransformOperator* instance = TransformOperator::getSingleton(); | |
| ASSERT_TRUE(SelectionSet::getSingleton()->isEmpty()); | |
| // All transform operations on empty selection should be safe | |
| EXPECT_NO_THROW(instance->setSelectedPosition(Ogre::Vector3(100, 200, 300))); | |
| EXPECT_NO_THROW(instance->translateSelected(Ogre::Vector3(1, 2, 3))); | |
| EXPECT_NO_THROW(instance->setSelectedScale(Ogre::Vector3(5, 5, 5))); | |
| EXPECT_NO_THROW(instance->scaleSelected(Ogre::Vector3(2, 2, 2))); | |
| EXPECT_NO_THROW(instance->setSelectedOrientation(Ogre::Vector3(90, 180, 270))); | |
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_X))); | |
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Vector3(45, 45, 45))); | |
| EXPECT_NO_THROW(instance->removeSelected()); | |
| // No signals should have been emitted | |
| QSignalSpy posSpy(instance, &TransformOperator::selectedPositionChanged); | |
| QSignalSpy orientSpy(instance, &TransformOperator::selectedOrientationChanged); | |
| QSignalSpy deleteSpy(instance, &TransformOperator::objectsDeleted); | |
| instance->setSelectedPosition(Ogre::Vector3(1, 1, 1)); | |
| EXPECT_EQ(posSpy.count(), 0); | |
| instance->setSelectedOrientation(Ogre::Vector3(45, 45, 45)); | |
| EXPECT_EQ(orientSpy.count(), 0); | |
| } | |
| TEST_F(TransformOperatorTestFixture, AllOperations_EmptyScene) { | |
| TransformOperator* instance = TransformOperator::getSingleton(); | |
| ASSERT_TRUE(SelectionSet::getSingleton()->isEmpty()); | |
| QSignalSpy posSpy(instance, &TransformOperator::selectedPositionChanged); | |
| QSignalSpy orientSpy(instance, &TransformOperator::selectedOrientationChanged); | |
| QSignalSpy deleteSpy(instance, &TransformOperator::objectsDeleted); | |
| // All transform operations on empty selection should be safe | |
| EXPECT_NO_THROW(instance->setSelectedPosition(Ogre::Vector3(100, 200, 300))); | |
| EXPECT_NO_THROW(instance->translateSelected(Ogre::Vector3(1, 2, 3))); | |
| EXPECT_NO_THROW(instance->setSelectedScale(Ogre::Vector3(5, 5, 5))); | |
| EXPECT_NO_THROW(instance->scaleSelected(Ogre::Vector3(2, 2, 2))); | |
| EXPECT_NO_THROW(instance->setSelectedOrientation(Ogre::Vector3(90, 180, 270))); | |
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_X))); | |
| EXPECT_NO_THROW(instance->rotateSelected(Ogre::Vector3(45, 45, 45))); | |
| EXPECT_NO_THROW(instance->removeSelected()); | |
| EXPECT_EQ(posSpy.count(), 0); | |
| EXPECT_EQ(orientSpy.count(), 0); | |
| EXPECT_EQ(deleteSpy.count(), 0); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/TransformOperator_test.cpp` around lines 598 - 622, The test sets up
TransformOperator and runs a batch of no-op transform calls before attaching
QSignalSpy objects, so emitted signals are missed; to fix, move the QSignalSpy
creations (posSpy, orientSpy, deleteSpy) to directly after obtaining
TransformOperator::getSingleton() and before calling
setSelectedPosition/translateSelected/setSelectedScale/scaleSelected/setSelectedOrientation/rotateSelected/removeSelected
so you capture any emissions from those operations, then assert posSpy.count(),
orientSpy.count(), and deleteSpy.count() are zero after the no-op sequence to
validate no signals were emitted.
|



Summary
animationcontrolslider_test.cpp,QMLMaterialHighlighter_test.cpp,SelectionBoxObject_test.cppSpaceCamera_test.cppwhere mouse-move tests dereferenced nullmTargetscene node (now guarded withtryInitOgre())Files changed
PrimitivesWidget_test.cppAnimationWidget_test.cppMaterialEditorQML_test.cppmainwindow_test.cppMCPServer_test.cppManager_test.cppBoneWeightOverlay_test.cppNormalVisualizer_test.cppTransformOperator_test.cppFBXExporter_test.cppSkeletonDebug_test.cppanimationcontrolslider_test.cpp(new)SelectionBoxObject_test.cpp(new)LLMManager_test.cppModelDownloader_test.cppQMLMaterialHighlighter_test.cpp(new)SpaceCamera_test.cppTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit