22// Licensed under the MIT License.
33#include " pch.h"
44#include " Tests.h"
5+ #include " PackageManager.h"
56
67using namespace std ::string_view_literals;
78
8- BOOL CALLBACK CheckForWinGetWindow (HWND hwnd, LPARAM param)
9+ namespace
910{
10- bool * result = reinterpret_cast < bool *>(param);
11+ # define ADVANCE_ARG_PARAMETER if (++i >= argc) { winrt::throw_hresult (E_INVALIDARG); }
1112
12- int textLength = GetWindowTextLengthW (hwnd) + 1 ;
13- std::wstring windowText (textLength, ' \0 ' );
14- textLength = GetWindowTextW (hwnd, &windowText[0 ], textLength);
15- windowText.resize (textLength);
16-
17- if (L" WingetMessageOnlyWindow" sv == windowText)
13+ std::string ToLower (std::string_view in)
1814 {
19- *result = true ;
20- return FALSE ;
15+ std::string result (in);
16+ std::transform (result.begin (), result.end (), result.begin (),
17+ [](unsigned char c) { return static_cast <char >(std::tolower (c)); });
18+ return result;
2119 }
2220
23- return TRUE ;
24- }
21+ #define BEGIN_ENUM_PARSE_FUNC (_type_ ) \
22+ _type_ Parse ## _type_(const char * input) \
23+ { \
24+ auto lower = ToLower (input); \
25+ if (lower.empty ()) {}
2526
26- // Look for the set of well known objects that should be present after we have spun everything up.
27- // Returns true if all well known objects are found in the expected state.
28- bool SearchForWellKnownObjects ( bool expectExist)
29- {
30- bool result = true ;
27+ # define ITEM_ENUM_PARSE_FUNC ( _type_, _value_ ) \
28+ else if ( ToLower (#_value_) == lower) \
29+ { \
30+ return _type_ ## :: ## _value_; \
31+ }
3132
32- auto coreApplicationProperties = winrt::Windows::ApplicationModel::Core::CoreApplication::Properties ();
33+ #define END_ENUM_PARSE_FUNC \
34+ winrt::throw_hresult (E_INVALIDARG); \
35+ }
3336
34- // COM statics
35- for (std::wstring_view item : {
36- L" WindowsPackageManager.CachedInstalledIndex" sv,
37- L" WindowsPackageManager.TerminationSignalHandler" sv,
38- })
37+ #define BEGIN_ENUM_NAME_FUNC (_type_ ) \
38+ std::string_view ToString (_type_); \
39+ std::ostream& operator <<(std::ostream& o, _type_ input) { return (o << ToString (input)); } \
40+ std::string_view ToString (_type_ input) \
41+ { \
42+ switch (input) {
43+
44+ #define ITEM_ENUM_NAME_FUNC (_type_, _value_ ) \
45+ case _type_ ## :: ## _value_: return #_value_;
46+
47+ #define END_ENUM_NAME_FUNC \
48+ } \
49+ return " Unknown" ; \
50+ }
51+
52+ BEGIN_ENUM_PARSE_FUNC (ComInitializationType)
53+ ITEM_ENUM_PARSE_FUNC (ComInitializationType, STA)
54+ ITEM_ENUM_PARSE_FUNC (ComInitializationType, MTA)
55+ END_ENUM_PARSE_FUNC
56+
57+ BEGIN_ENUM_NAME_FUNC (ComInitializationType)
58+ ITEM_ENUM_NAME_FUNC (ComInitializationType, STA)
59+ ITEM_ENUM_NAME_FUNC (ComInitializationType, MTA)
60+ END_ENUM_NAME_FUNC
61+
62+ BEGIN_ENUM_PARSE_FUNC (UnloadBehavior)
63+ ITEM_ENUM_PARSE_FUNC (UnloadBehavior, Allow)
64+ ITEM_ENUM_PARSE_FUNC (UnloadBehavior, AtExit)
65+ ITEM_ENUM_PARSE_FUNC (UnloadBehavior, Never)
66+ END_ENUM_PARSE_FUNC
67+
68+ BEGIN_ENUM_NAME_FUNC (UnloadBehavior)
69+ ITEM_ENUM_NAME_FUNC (UnloadBehavior, Allow)
70+ ITEM_ENUM_NAME_FUNC (UnloadBehavior, AtExit)
71+ ITEM_ENUM_NAME_FUNC (UnloadBehavior, Never)
72+ END_ENUM_NAME_FUNC
73+
74+ BEGIN_ENUM_PARSE_FUNC (ActivationType)
75+ ITEM_ENUM_PARSE_FUNC (ActivationType, ClassName)
76+ ITEM_ENUM_PARSE_FUNC (ActivationType, CLSID_WinRT)
77+ ITEM_ENUM_PARSE_FUNC (ActivationType, CLSID_CoCreateInstance)
78+ END_ENUM_PARSE_FUNC
79+
80+ BEGIN_ENUM_NAME_FUNC (ActivationType)
81+ ITEM_ENUM_NAME_FUNC (ActivationType, ClassName)
82+ ITEM_ENUM_NAME_FUNC (ActivationType, CLSID_WinRT)
83+ ITEM_ENUM_NAME_FUNC (ActivationType, CLSID_CoCreateInstance)
84+ END_ENUM_NAME_FUNC
85+
86+ BOOL CALLBACK CheckForWinGetWindow (HWND hwnd, LPARAM param)
3987 {
40- bool present = coreApplicationProperties.HasKey (item);
88+ bool * result = reinterpret_cast <bool *>(param);
89+
90+ int textLength = GetWindowTextLengthW (hwnd) + 1 ;
91+ std::wstring windowText (textLength, ' \0 ' );
92+ textLength = GetWindowTextW (hwnd, &windowText[0 ], textLength);
93+ windowText.resize (textLength);
94+
95+ if (L" WingetMessageOnlyWindow" sv == windowText)
96+ {
97+ *result = true ;
98+ return FALSE ;
99+ }
100+
101+ return TRUE ;
102+ }
103+
104+ // Look for the set of well known objects that should be present after we have spun everything up.
105+ // Returns true if all well known objects are found in the expected state.
106+ bool SearchForWellKnownObjects (bool expectExist)
107+ {
108+ bool result = true ;
109+
110+ auto coreApplicationProperties = winrt::Windows::ApplicationModel::Core::CoreApplication::Properties ();
111+
112+ // COM statics
113+ for (std::wstring_view item : {
114+ L" WindowsPackageManager.CachedInstalledIndex" sv,
115+ L" WindowsPackageManager.TerminationSignalHandler" sv,
116+ })
117+ {
118+ bool present = coreApplicationProperties.HasKey (item);
41119
42- if (present != expectExist)
120+ if (present != expectExist)
121+ {
122+ std::cout << " CoreApplication property `" << winrt::to_string (item) << " ` was not in expected state [" << (expectExist ? " should exist" : " should not exist" ) << " ]\n " ;
123+ result = false ;
124+ }
125+ }
126+
127+ // Shutdown monitoring window
128+ bool foundWindow = false ;
129+ EnumWindows (CheckForWinGetWindow, reinterpret_cast <LPARAM>(&foundWindow));
130+
131+ if (foundWindow != expectExist)
43132 {
44- std::cout << " CoreApplication property ` " << winrt::to_string (item) << " ` was not in expected state [" << (expectExist ? " should exist" : " should not exist" ) << " ]\n " ;
133+ std::cout << " WinGet Window `WingetMessageOnlyWindow ` was not in expected state [" << (expectExist ? " should exist" : " should not exist" ) << " ]\n " ;
45134 result = false ;
46135 }
136+
137+ return result;
47138 }
139+ }
48140
49- // Shutdown monitoring window
50- bool foundWindow = false ;
51- EnumWindows (CheckForWinGetWindow, reinterpret_cast <LPARAM>(&foundWindow));
141+ TestParameters::TestParameters (int argc, const char ** argv)
142+ {
143+ for (int i = 0 ; i < argc; ++i)
144+ {
145+ if (" -test" sv == argv[i])
146+ {
147+ ADVANCE_ARG_PARAMETER
148+ TestToRun = ToLower (argv[i]);
149+ }
150+ else if (" -com" sv == argv[i])
151+ {
152+ ADVANCE_ARG_PARAMETER
153+ ComInit = ParseComInitializationType (argv[i]);
154+ }
155+ else if (" -leak-com" sv == argv[i])
156+ {
157+ LeakCOM = true ;
158+ }
159+ else if (" -itr" sv == argv[i])
160+ {
161+ ADVANCE_ARG_PARAMETER
162+ Iterations = atoi (argv[i]);
163+ }
164+ else if (" -pkg" sv == argv[i])
165+ {
166+ ADVANCE_ARG_PARAMETER
167+ PackageName = argv[i];
168+ }
169+ else if (" -unload" sv == argv[i])
170+ {
171+ ADVANCE_ARG_PARAMETER
172+ UnloadBehavior = ParseUnloadBehavior (argv[i]);
173+ }
174+ else if (" -activation" sv == argv[i])
175+ {
176+ ADVANCE_ARG_PARAMETER
177+ ActivationType = ParseActivationType (argv[i]);
178+ }
179+ else if (" -clear-factories" sv == argv[i])
180+ {
181+ ClearFactories = true ;
182+ }
183+ }
184+ }
185+
186+ void TestParameters::OutputDetails () const
187+ {
188+ std::cout << " Running inproc testbed with:\n "
189+ " COM Init : " << ComInit << " \n "
190+ " Activate : " << ActivationType << " \n "
191+ " Clear : " << std::boolalpha << ClearFactories << " \n "
192+ " Leak COM : " << std::boolalpha << LeakCOM << " \n "
193+ " Unload : " << UnloadBehavior << " \n "
194+ " Test : " << TestToRun << " \n "
195+ " Package : " << PackageName << " \n "
196+ " Passes : " << Iterations << std::endl;
197+ }
198+
199+ bool TestParameters::InitializeTestState () const
200+ {
201+ HRESULT hr = S_OK;
52202
53- if (foundWindow != expectExist )
203+ if (ComInitializationType::STA == ComInit )
54204 {
55- std::cout << " WinGet Window `WingetMessageOnlyWindow` was not in expected state [" << (expectExist ? " should exist" : " should not exist" ) << " ]\n " ;
56- result = false ;
205+ hr = RoInitialize (RO_INIT_SINGLETHREADED);
206+ }
207+ else if (ComInitializationType::MTA == ComInit)
208+ {
209+ hr = RoInitialize (RO_INIT_MULTITHREADED);
57210 }
58211
59- return result;
212+ if (FAILED (hr))
213+ {
214+ std::cout << " RoInitialize returned " << hr << std::endl;
215+ return false ;
216+ }
217+
218+ if (UnloadBehavior::Never == UnloadBehavior || UnloadBehavior::AtExit == UnloadBehavior)
219+ {
220+ SetUnloadPreference (false );
221+ }
222+
223+ return true ;
224+ }
225+
226+ std::unique_ptr<ITest> TestParameters::CreateTest () const
227+ {
228+ if (" unload_check" sv == TestToRun)
229+ {
230+ return std::make_unique<UnloadAndCheckForLeaks>(*this );
231+ }
232+
233+ return {};
234+ }
235+
236+ void TestParameters::UninitializeTestState () const
237+ {
238+ if (!LeakCOM)
239+ {
240+ RoUninitialize ();
241+ }
242+
243+ if (UnloadBehavior::AtExit == UnloadBehavior)
244+ {
245+ SetUnloadPreference (true );
246+ }
247+ }
248+
249+ bool TestParameters::UnloadExpected () const
250+ {
251+ bool shouldUnload = true ;
252+ if (UnloadBehavior::Never == UnloadBehavior || UnloadBehavior::AtExit == UnloadBehavior)
253+ {
254+ shouldUnload = false ;
255+ }
256+ return shouldUnload;
60257}
61258
62259Snapshot::Snapshot ()
@@ -97,7 +294,7 @@ Snapshot::Snapshot()
97294 CloseHandle (snapshot);
98295}
99296
100- UnloadAndCheckForLeaks::UnloadAndCheckForLeaks (bool shouldUnload ) : m_shouldUnload(shouldUnload )
297+ UnloadAndCheckForLeaks::UnloadAndCheckForLeaks (const TestParameters& parameters ) : m_parameters(parameters )
101298{
102299}
103300
@@ -114,7 +311,7 @@ bool UnloadAndCheckForLeaks::RunIteration()
114311
115312 m_iterationSnapshots.emplace_back (beforeUnload, Snapshot{});
116313
117- if (!SearchForWellKnownObjects (!m_shouldUnload ))
314+ if (!SearchForWellKnownObjects (!m_parameters. UnloadExpected () ))
118315 {
119316 return false ;
120317 }
0 commit comments