@@ -188,3 +188,58 @@ TEST_CASE("trylookup_from_abi specialization")
188188 // regular lookup should throw the same error
189189 REQUIRE_THROWS_AS (map.Lookup (123 ), hresult_wrong_thread);
190190}
191+
192+ TEST_CASE (" trylookup_from_abi specialization with IInspectable" )
193+ {
194+ // A map that throws a specific error, used to verify various edge cases.
195+ // and implements tryLookup, to take advantage of an optimization to avoid a throw.
196+ struct map_with_try_lookup : implements<map_with_try_lookup, IMapView<int , IInspectable>>
197+ {
198+ hresult codeToThrow{ S_OK };
199+ bool shouldThrowOnTryLookup{ false };
200+ bool returnNullptr{ false };
201+ std::optional<IInspectable> TryLookup (int , trylookup_from_abi_t )
202+ {
203+ if (returnNullptr)
204+ {
205+ return { nullptr };
206+ }
207+ else if (shouldThrowOnTryLookup)
208+ {
209+ throw_hresult (codeToThrow);
210+ }
211+ else
212+ {
213+ return { std::nullopt };
214+ }
215+ }
216+ IInspectable Lookup (int ) { throw_hresult (E_UNEXPECTED); } // shouldn't be called by the test
217+ int32_t Size () { throw_hresult (E_UNEXPECTED); } // shouldn't be called by the test
218+ bool HasKey (int ) { throw_hresult (E_UNEXPECTED); } // shouldn't be called by the test
219+ void Split (IMapView<int , IInspectable>&, IMapView<int , IInspectable>&) { throw_hresult (E_UNEXPECTED); } // shouldn't be called by the test
220+ };
221+
222+ auto self = make_self<map_with_try_lookup>();
223+ IMapView<int , IInspectable> map = *self;
224+
225+ // Ensure that we return a value on nullptr, a nullptr is a valid IInspectable in the Map
226+ self->returnNullptr = true ;
227+ REQUIRE (map.TryLookup (123 ) == IInspectable{nullptr });
228+ REQUIRE (map.Lookup (123 ) == IInspectable{nullptr });
229+
230+ // Make sure that we use the TryLookup specialization, and don't throw an unexpected exception.
231+ self->shouldThrowOnTryLookup = false ;
232+ self->returnNullptr = false ;
233+ REQUIRE (map.TryLookup (123 ) == IInspectable{nullptr });
234+ // make sure regular lookup stll throws bounds
235+ REQUIRE_THROWS_AS (map.Lookup (123 ), hresult_out_of_bounds);
236+
237+ // Simulate a non-agile map that is being accessed from the wrong thread.
238+ // "Try" operations should throw rather than erroneously report "not found".
239+ // Because they didn't even try. The operation never got off the ground.
240+ self->shouldThrowOnTryLookup = true ;
241+ self->codeToThrow = RPC_E_WRONG_THREAD;
242+ REQUIRE_THROWS_AS (map.TryLookup (123 ), hresult_wrong_thread);
243+ // regular lookup should throw the same error
244+ REQUIRE_THROWS_AS (map.Lookup (123 ), hresult_wrong_thread);
245+ }
0 commit comments