@@ -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