2727#include < pxr/base/vt/value.h>
2828#include < pxr/imaging/hd/materialSchema.h>
2929#include < pxr/imaging/hd/materialBindingsSchema.h>
30+ #include < pxr/imaging/hd/primOriginSchema.h>
3031
3132#include < gtest/gtest.h>
3233
3738#include < QVBoxLayout>
3839#include < iostream>
3940#include < regex>
41+ #include < set>
4042#include < stack>
4143#include < vector>
4244
45+ namespace {
46+
47+ // Matches HduiDataSourceTreeWidget's name ordering.
48+ std::vector<PXR_NS ::TfToken>
49+ GetSortedContainerChildNames (const PXR_NS ::HdContainerDataSourceHandle& container)
50+ {
51+ const PXR_NS ::TfTokenVector names = container->GetNames ();
52+ const std::set<PXR_NS ::TfToken, PXR_NS ::TfDictionaryLessThan> sortedNames (
53+ names.begin (), names.end ());
54+ return std::vector<PXR_NS ::TfToken>(sortedNames.begin (), sortedNames.end ());
55+ }
56+
57+ void PushSortedContainerChildrenOnStack (
58+ const PXR_NS ::HdContainerDataSourceHandle& container,
59+ const PXR_NS ::HdDataSourceLocator& parentLocator,
60+ std::stack<DataSourceEntry>& dataSourceStack)
61+ {
62+ const std::vector<PXR_NS ::TfToken> sortedChildNames = GetSortedContainerChildNames (container);
63+ for (auto itChildNames = sortedChildNames.rbegin (); itChildNames != sortedChildNames.rend ();
64+ ++itChildNames) {
65+ const PXR_NS ::TfToken& childName = *itChildNames;
66+ if (PXR_NS ::HdDataSourceBaseHandle childDataSource = container->Get (childName)) {
67+ dataSourceStack.push (
68+ { childName, childDataSource, parentLocator.Append (childName) });
69+ }
70+ }
71+ }
72+
73+ std::stack<DataSourceEntry> BuildInitialDataSourceStack (
74+ const PXR_NS ::SdfPath& primPath, const PXR_NS ::HdSceneIndexPrim& prim)
75+ {
76+ std::stack<DataSourceEntry> dataSourceStack;
77+
78+ #if PXR_VERSION >= 2511
79+ // HduiDataSourceTreeWidget::SetPrimDataSource lists sorted container children
80+ // as top-level items instead of the prim data source container itself.
81+ if (PXR_NS ::HdContainerDataSourceHandle container
82+ = PXR_NS::HdContainerDataSource::Cast (prim.dataSource )) {
83+ PushSortedContainerChildrenOnStack (
84+ container, PXR_NS::HdDataSourceLocator (), dataSourceStack);
85+ } else if (prim.dataSource ) {
86+ dataSourceStack.push (
87+ { primPath.GetNameToken (), prim.dataSource , PXR_NS::HdDataSourceLocator () });
88+ }
89+ #else
90+ dataSourceStack.push (
91+ { primPath.GetNameToken (), prim.dataSource , PXR_NS::HdDataSourceLocator () });
92+ #endif
93+
94+ return dataSourceStack;
95+ }
96+
97+ } // namespace
98+
4399template <class ChildType > ChildType* FindFirstChild (QObject* qObject)
44100{
45101 for (QObject* child : qObject->children ()) {
@@ -132,31 +188,33 @@ void AdskHydraSceneBrowserTestFixture::ComparePrimHierarchy(
132188 // Compare data source
133189 if (compareDataSourceHierarchy) {
134190 _primHierarchyWidget->setCurrentItem (primQtItem);
135- CompareDataSourceHierarchy ( primPath,
136- { primPath. GetNameToken (), prim. dataSource , PXR_NS::HdDataSourceLocator () }, compareDataSourceValues);
191+ CompareDataSourceHierarchy (primPath, BuildInitialDataSourceStack ( primPath, prim) ,
192+ compareDataSourceValues);
137193 }
138194
139195 // Prepare next step (need to pop the stack before pushing the next elements)
140196 itPrimsTreeWidget++;
141197 primPathsStack.pop ();
142198
143- // Push child paths on the stack
144- PXR_NS ::SdfPathVector childPaths = sceneIndex->GetChildPrimPaths (primPath);
145- for (auto itChildPaths = childPaths.rbegin (); itChildPaths != childPaths.rend ();
146- itChildPaths++) {
199+ // Push child paths on the stack in the same sorted order used by
200+ // HduiSceneIndexTreeWidget.
201+ const PXR_NS ::SdfPathVector childPathVec = sceneIndex->GetChildPrimPaths (primPath);
202+ const PXR_NS ::SdfPathSet sortedChildPaths (childPathVec.begin (), childPathVec.end ());
203+ for (auto itChildPaths = sortedChildPaths.rbegin (); itChildPaths != sortedChildPaths.rend ();
204+ ++itChildPaths) {
147205 primPathsStack.push (*itChildPaths);
148206 }
149207 }
150208}
151209
152210void AdskHydraSceneBrowserTestFixture::CompareDataSourceHierarchy (
153- const PXR_NS ::SdfPath& primPath,
154- DataSourceEntry rootDataSourceEntry ,
155- bool compareValues)
211+ const PXR_NS ::SdfPath& primPath,
212+ std::stack< DataSourceEntry> initialDataSourceStack ,
213+ bool compareValues)
156214{
157215 // Setup traversal data structures (depth-first search)
158216 QTreeWidgetItemIterator itDataSourceTreeWidget = GetIteratorForTree (_dataSourceHierarchyWidget);
159- std::stack<DataSourceEntry> dataSourceStack ({ rootDataSourceEntry } );
217+ std::stack<DataSourceEntry> dataSourceStack = std::move (initialDataSourceStack );
160218
161219 // Traverse hierarchy and compare (depth-first search)
162220 while (*itDataSourceTreeWidget && !dataSourceStack.empty ()) {
@@ -183,15 +241,8 @@ void AdskHydraSceneBrowserTestFixture::CompareDataSourceHierarchy(
183241 // Push child data sources on the stack
184242 if (auto containerDataSource
185243 = PXR_NS::HdContainerDataSource::Cast (dataSourceEntry.dataSource )) {
186- PXR_NS ::TfTokenVector childNames = containerDataSource->GetNames ();
187- for (auto itChildNames = childNames.rbegin (); itChildNames != childNames.rend ();
188- itChildNames++) {
189- PXR_NS ::TfToken dataSourceName = *itChildNames;
190- PXR_NS ::HdDataSourceBaseHandle dataSource = containerDataSource->Get (dataSourceName);
191- if (dataSource) {
192- dataSourceStack.push ({ dataSourceName, dataSource, dataSourceEntry.locator .Append (dataSourceName) });
193- }
194- }
244+ PushSortedContainerChildrenOnStack (
245+ containerDataSource, dataSourceEntry.locator , dataSourceStack);
195246 } else if (
196247 auto vectorDataSource = PXR_NS::HdVectorDataSource::Cast (dataSourceEntry.dataSource )) {
197248 for (size_t iElement = 0 ; iElement < vectorDataSource->GetNumElements (); iElement++) {
@@ -298,8 +349,31 @@ void AdskHydraSceneBrowserTestFixture::CompareValueContent(const PXR_NS::VtValue
298349 for (PXR_NS ::SdfPath const & path : paths) {
299350 valueStream << path << " \n " ;
300351 }
301- }
302- else {
352+ } else if (value.IsHolding <PXR_NS ::HdPrimOriginSchema::OriginPath>()) {
353+ // Special case for HdPrimOriginSchema::OriginPath: mirror the display
354+ // logic in HduiDataSourceValueTreeView, which has always called
355+ // .GetPath() directly to show just the wrapped SdfPath (e.g.
356+ // "/USDCylinder").
357+ //
358+ // Before USD 26.05, HdPrimOriginSchema::OriginPath was not a
359+ // registered core Vt value type, so VtValue::operator<< fell through
360+ // to Vt_StreamOutGeneric and emitted the fallback format
361+ // "<'HdPrimOriginSchema::OriginPath' @ 0x...>". That pattern was
362+ // caught by MatchesFallbackTextOutput and the comparison was skipped.
363+ //
364+ // Starting with USD 26.05, "Hydra Scene Debugger now supports all
365+ // registered core Vt value types rather than a hard-coded subset"
366+ // (see OpenUSD CHANGELOG [26.05]). OriginPath became a registered
367+ // type, so VtValue::operator<< now correctly calls
368+ // operator<<(stream, OriginPath const& p)
369+ // which emits "HdPrimOriginSchema::OriginPath(<path>)". That string
370+ // no longer matches the fallback regex, causing the exact-match
371+ // EXPECT_EQ to fail against the widget's simpler ".GetPath()" output.
372+ //
373+ // The fix is to always compute expectedValue the same way the widget
374+ // does, regardless of how operator<< formats the VtValue.
375+ valueStream << value.UncheckedGet <PXR_NS ::HdPrimOriginSchema::OriginPath>().GetPath ();
376+ } else {
303377 valueStream << value;
304378 }
305379#endif
0 commit comments