@@ -217,6 +217,10 @@ TEST_CASE("single_threaded_observable_vector")
217217 REQUIRE ((vector_i.IndexOf (2 , index) && index == 1 ));
218218 index = 0 ;
219219 REQUIRE ((vector_o.IndexOf (box_value (2 ), index) && index == 1 ));
220+
221+ // A vector of integers never contains non-integers.
222+ REQUIRE (!vector_o.IndexOf (nullptr , index));
223+ REQUIRE (!vector_o.IndexOf (box_value (L" Not-an-integer" ), index));
220224 }
221225 {
222226 // GetView forwarding.
@@ -241,6 +245,10 @@ TEST_CASE("single_threaded_observable_vector")
241245
242246 REQUIRE (vector_i.GetAt (0 ) == 10 );
243247 REQUIRE (vector_i.GetAt (1 ) == 20 );
248+
249+ // Can't put non-integers in a vector of integers.
250+ REQUIRE_THROWS_AS (vector_o.SetAt (0 , nullptr ), hresult_no_interface);
251+ REQUIRE_THROWS_AS (vector_o.SetAt (0 , box_value (L" Not-an-integer" )), hresult_no_interface);
244252 }
245253 {
246254 // InsertAt forwarding.
@@ -258,6 +266,10 @@ TEST_CASE("single_threaded_observable_vector")
258266 REQUIRE (vector_i.GetAt (1 ) == 2 );
259267 REQUIRE (vector_i.GetAt (2 ) == 3 );
260268 REQUIRE (vector_i.GetAt (3 ) == 4 );
269+
270+ // Can't put non-integers in a vector of integers.
271+ REQUIRE_THROWS_AS (vector_o.InsertAt (0 , nullptr ), hresult_no_interface);
272+ REQUIRE_THROWS_AS (vector_o.InsertAt (0 , box_value (L" Not-an-integer" )), hresult_no_interface);
261273 }
262274 {
263275 // Append forwarding.
@@ -273,6 +285,10 @@ TEST_CASE("single_threaded_observable_vector")
273285 REQUIRE (vector_i.Size () == 2 );
274286 REQUIRE (vector_i.GetAt (0 ) == 1 );
275287 REQUIRE (vector_i.GetAt (1 ) == 2 );
288+
289+ // Can't put non-integers in a vector of integers.
290+ REQUIRE_THROWS_AS (vector_o.Append (nullptr ), hresult_no_interface);
291+ REQUIRE_THROWS_AS (vector_o.Append (box_value (L" Not-an-integer" )), hresult_no_interface);
276292 }
277293 {
278294 // GetMany boxing.
@@ -334,13 +350,13 @@ TEST_CASE("single_threaded_observable_vector")
334350 bool changed_i{};
335351 bool changed_o{};
336352
337- vector_i.VectorChanged ([&](IObservableVector<int > const & sender, IVectorChangedEventArgs const &)
353+ auto token_i = vector_i.VectorChanged (auto_revoke, [&](IObservableVector<int > const & sender, IVectorChangedEventArgs const &)
338354 {
339355 changed_i = sender.GetAt (0 ) == 123 ;
340356 REQUIRE (sender == vector_i);
341357 });
342358
343- vector_o.VectorChanged ([&](IObservableVector<IInspectable> const & sender, IVectorChangedEventArgs const &)
359+ auto token_o = vector_o.VectorChanged (auto_revoke, [&](IObservableVector<IInspectable> const & sender, IVectorChangedEventArgs const &)
344360 {
345361 changed_o = unbox_value<int >(sender.GetAt (0 )) == 123 ;
346362 REQUIRE (sender == vector_o);
@@ -357,6 +373,35 @@ TEST_CASE("single_threaded_observable_vector")
357373 REQUIRE (vector_i.Size () == 1 );
358374 REQUIRE (vector_i.GetAt (0 ) == 123 );
359375 }
376+ {
377+ bool changed_i{};
378+ bool changed_o{};
379+
380+ auto token_i = vector_i.VectorChanged (auto_revoke, [&](IObservableVector<int > const & sender, IVectorChangedEventArgs const &)
381+ {
382+ changed_i = true ;
383+ REQUIRE (sender == vector_i);
384+ });
385+
386+ auto token_o = vector_o.VectorChanged (auto_revoke, [&](IObservableVector<IInspectable> const & sender, IVectorChangedEventArgs const &)
387+ {
388+ changed_i = true ;
389+ REQUIRE (sender == vector_o);
390+ });
391+
392+ // Verify strong exception guarantee when replacing with non-integers.
393+ REQUIRE_THROWS_AS (vector_o.ReplaceAll ({ box_value (42 ), nullptr }), hresult_no_interface);
394+ REQUIRE (!changed_i); // unchanged on failure
395+ REQUIRE (!changed_o);
396+ REQUIRE (vector_i.Size () == 1 );
397+ REQUIRE (vector_i.GetAt (0 ) == 123 );
398+
399+ REQUIRE_THROWS_AS (vector_o.ReplaceAll ({ box_value (L" Not-an-integer" ) }), hresult_no_interface);
400+ REQUIRE (!changed_i); // unchanged on failure
401+ REQUIRE (!changed_o);
402+ REQUIRE (vector_i.Size () == 1 );
403+ REQUIRE (vector_i.GetAt (0 ) == 123 );
404+ }
360405
361406 {
362407 IIterator<int > iterator_i = vector_i.First ();
@@ -368,13 +413,13 @@ TEST_CASE("single_threaded_observable_vector")
368413 bool changed_i{};
369414 bool changed_o{};
370415
371- vector_i.VectorChanged ([&](IObservableVector<int > const & sender, IVectorChangedEventArgs const &)
416+ auto token_i = vector_i.VectorChanged (auto_revoke, [&](IObservableVector<int > const & sender, IVectorChangedEventArgs const &)
372417 {
373418 changed_i = sender.GetAt (0 ) == 123 ;
374419 REQUIRE (sender == vector_i);
375420 });
376421
377- vector_o.VectorChanged ([&](IObservableVector<IInspectable> const & sender, IVectorChangedEventArgs const &)
422+ auto token_o = vector_o.VectorChanged (auto_revoke, [&](IObservableVector<IInspectable> const & sender, IVectorChangedEventArgs const &)
378423 {
379424 changed_o = unbox_value<int >(sender.GetAt (0 )) == 123 ;
380425 REQUIRE (sender == vector_o);
@@ -392,4 +437,19 @@ TEST_CASE("single_threaded_observable_vector")
392437 REQUIRE (vector_i.GetAt (0 ) == 123 );
393438 }
394439 }
440+
441+ {
442+ IObservableVector<IVector<int >> vector_i = single_threaded_observable_vector<IVector<int >>({ });
443+ IObservableVector<IInspectable> vector_o = vector_i.as <IObservableVector<IInspectable>>();
444+
445+ // Verify that nulls are legal if the underlying type derives from IInspectable.
446+ REQUIRE_NOTHROW (vector_o.Append (nullptr ));
447+ uint32_t index = 99 ;
448+ REQUIRE (vector_o.IndexOf (nullptr , index));
449+ REQUIRE (index == 0 );
450+
451+ // Verify that type mismatch should report "not found" rather than
452+ // finding the null entry.
453+ REQUIRE (!vector_o.IndexOf (box_value (L" not-a-vector" ), index));
454+ }
395455}
0 commit comments