ocornut/imgui_test_engine

Unmangle child ids

mgerhardy opened this issue · 7 comments

It looks like I really can't get this running.. The item ##_top_selector_neo is not found

I have the following path copied from Stack Tool

// /Animation###animationtimeline\/##neo-sequencer-child_EEF00089\/####neo-sequencer_child_wrapper_D29EAF74/##neo-sequencer/##_top_selector_neo
ctx->SetRef("Animation###animationtimeline");
ctx->SetRef(ctx->WindowInfo("##neo-sequencer-child")->ID);
ctx->SetRef(ctx->WindowInfo("####neo-sequencer_child_wrapper")->ID);
ctx->MouseMove("##neo-sequencer/##_top_selector_neo");
ctx->MouseDragWithDelta({10.0f, 0.0f});
ctx->ItemClick("###Add");

These are the logs

[0000] Test: 'animationtimeline' 'create keyframe'..
[0000] -- SetInputMode 1
[0001] -- ItemClick '###viewport0' > 00000000
[0016] -- WindowFocus('22585415 > 'NULL'')
[0017] -- SetRef ' Animation###animationtimeline' 22585415
[0017] OK AnimationTimelineTest.cpp:20 'focusWindow(ctx, title)'
[0017] -- WindowInfo: by path: '##neo-sequencer-child'
[0018] -- SetRef 'NULL' 4226E3F2
[0018] -- WindowInfo: by path: '####neo-sequencer_child_wrapper'
[0019] -- SetRef 'NULL' AAFE48E8
[0023] Error 'Unable to locate item: '/##neo-sequencer/##_top_selector_neo''
[0023] -- MouseMove to '##neo-sequencer/##_top_selector_neo' > 00000000
[0023] create keyframe test failed.

side note - the mentioned focusWindow function in the logs looks like this

bool Panel::focusWindow(ImGuiTestContext *ctx, const char *title) {
	IM_CHECK_SILENT_RETV(title != nullptr, false);
	ImGuiWindow* window = ImGui::FindWindowByName(title);
	if (window == nullptr) {
		ctx->LogError("Error: could not find window with title/id %s", title);
		IM_CHECK_SILENT_RETV(window != nullptr, false);
	}
	ctx->WindowFocus(window->ID);
	ctx->SetRef(window);
	return true;
}

As a sidenote - I've also tried to use //**/##neo-sequencer-child and //**/**/##neo-sequencer-child (up to 5 times **/ out of ignorance ;) )

And last but not least a screenshot of the "problem" ;)

Bildschirmfoto vom 2024-04-20 18-03-41

Sorry I am confused by the issue as posted.

  • The logs don't seem to match the test case posted above it.
  • I don't have a repro for the Gui code and given the amount of windows and usage of ## and ### operators it's not trivial to parse.
  • Why not using WindowInfo("window/child/child") syntax?

I'll try to post an update here with the updated and cleaned-up id handing (also with one child less)

void AnimationTimeline::registerUITests(ImGuiTestEngine *engine, const char *title) {
	// Copied path: / Animation###animationtimeline\/##sequencer_child_wrapper_C173513F/sequencer/##_top_selector_neo
	//
	// ----logs
	// [0000] Test: 'animationtimeline' 'create keyframe'..
	// [0000] -- SetInputMode 1
	// [0001] -- ItemClick '###viewport0' > 00000000
	// [0001] --   MouseMove to '###viewport0' > 00000000
	// [0001] --     WindowBringToFront()->FocusWindow('Free SceneMode###viewport0')
	// [0003] --     MouseMoveToPos from (2358,858) to (947,654)
	// [0005] --     BringWindowToDisplayFront('Free SceneMode###viewport0') (window.back=##Combo_00)
	// [0010] --   MouseClick 0
	// [0014] -- WindowFocus('22585415')
	// [0015] -- SetRef ' Animation###animationtimeline' 22585415
	// [0015] OK AnimationTimelineTest.cpp:23 'focusWindow(ctx, title)'
	// [0015] -- WindowInfo: by path: '##sequencer_child_wrapper'
	// [0016] -- SetRef 'NULL' 7B448F59
	// [0020] Error 'Unable to locate item: '/sequencer/##_top_selector_neo''
	// [0020] -- MouseMove to 'sequencer/##_top_selector_neo' > 00000000
	// [0020] create keyframe test failed.

	IM_REGISTER_TEST(engine, testCategory(), "create keyframe")->TestFunc = [=](ImGuiTestContext *ctx) {
		const int viewportId = viewportSceneMode(ctx, _app);
		IM_CHECK_SILENT(viewportId != -1);
		const core::String id = Viewport::viewportId(viewportId);
		ctx->ItemClick(id.c_str());

		IM_CHECK(focusWindow(ctx, title)); // line 0015 in logs
		ctx->SetRef(ctx->WindowInfo("##sequencer_child_wrapper").ID);
                // even without "sequencer" id being pushed - a single "##_top_selector_neo" is not found here
		ctx->MouseMove("sequencer/##_top_selector_neo"); // sequencer is pushed via PushID(), ##_top_selector_neo is an ItemHoverable()
		[...]
	};
}
  • The logs don't seem to match the test case posted above it.
    Matches now - sorry for this
  • I don't have a repro for the Gui code and given the amount of windows and usage of ## and ### operators it's not trivial to parse.
    It's not easy to extract. ##_top_selector_neo is submitted like this ItemHoverable(pointerRect, GetCurrentWindow()->GetID("##_top_selector_neo"), 0);
  • Why not using WindowInfo("window/child/child") syntax?
    my IM_CHECK(focusWindow(ctx, title)); is also setting the focus to that window and the next call ctx->SetRef(ctx->WindowInfo("##sequencer_child_wrapper").ID); works (as far as I can tell from the logs). This approach works in all other tests, too. I'm not sure if you are proposing to do ctx->SetRef(ctx->WindowInfo(title + "/##sequencer_child_wrapper").ID); here?

I hope that this might help a little bit more. If not, I don't want to waste your time any further - I'm sure the error is on my side and I'll fiddle it out.

Thanks a lot

I'm not sure if you are proposing to do ctx->SetRef(ctx->WindowInfo(title + "/##sequencer_child_wrapper").ID); here?

Yes was suggesting that (or you can use .Window as well).

If not, I don't want to waste your time any further - I'm sure the error is on my side and I'll fiddle it out.

Dealing with child windows can get abnormally confusing or tricky. There are reasons for this but it shouldn't be an excuse (aka I should improve the system). I'd rather have you share your pain here so we can improve the situation.

(Although fuller wildcard support is difficult to support for widgets (e.g. "*world") it's technically more at reach for windows since we do carry retained representation of them along with their hierarchy. So perhaps adding support for those may be another good tool we can implement as well.)

this works, too (only setting the reference - not getting the child item for ##_top_selector_neo)

core::String fullPathId = core::string::format("//%s/##sequencer_child_wrapper", title); // title is the full label of the window as given in the log output above
ctx->SetRef(ctx->WindowInfo(fullPathId.c_str()).ID);

but no matter which string path I give to ctx->ItemInfo() - I can't find that item - even by simple brute-forcing..:

ctx->SetRef(ctx->WindowInfo("//$FOCUSED/##sequencer_child_wrapper").ID); // works - according to the logs
ctx->ItemInfo("/sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("//sequencer/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("//##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("**/##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;

And even after re-reading the code and https://github.com/ocornut/imgui_test_engine/wiki/Named-References I can't get it...


As a side-note: I wonder whether it would make sense to print the string from ItemInfoErrorLog() in trace log at least.

maybe an edge case - but useful when just brute forcing the different attempts

ctx->ItemInfo(fullItemPathId.c_str(),);
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("##_top_selector_neo");
ctx->TestOutput->Status = ImGuiTestStatus_Success;
ctx->ItemInfo("**/##_top_selector_neo");

would be easier like this:

ctx->ItemInfo(fullItemPathId.c_str(), ImGuiTestOpFlags_NoError);
ctx->ItemInfo("##_top_selector_neo", ImGuiTestOpFlags_NoError);
ctx->ItemInfo("**/##_top_selector_neo", ImGuiTestOpFlags_NoError);

I can’t really help you if i don’t know what the Begin/BeginChild code structure is.

Just to clarify, I would really like to help, and I would really like to do anything I can to improve and simplify this.
But I'm also overwhelmed in requests so it sometimes can be difficult to track bundled requests (many different ideas in a same thread) or if it's not obvious how to repro.

would be easier like this:
ctx->ItemInfo(fullItemPathId.c_str(), ImGuiTestOpFlags_NoError);

I'm not sure I understand what you are suggesting. This normally DOES work to be passing ImGuiTestOpFlags_NoError to make a failed lookup not alter status. So yeah you can do that. What are you suggesting?

ctx->TestOutput->Status = ImGuiTestStatus_Success;

Please don't do this :D

It's not easy to extract. ##_top_selector_neo is submitted like this ItemHoverable(pointerRect, GetCurrentWindow()->GetID("##_top_selector_neo"), 0);

It's been hard to help because you never submitted even pseudo-code about what those items were.
But this line suggest that ##_top_selector_neo is a custom widget?
For the item to be seen by test engine, you need to either call ItemAdd() or IMGUI_TEST_ENGINE_ITEM_ADD() (the later is called by ItemAdd).