mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
894 lines
37 KiB
C++
894 lines
37 KiB
C++
|
|
||
|
#include <time.h> // TODO: https://github.com/microsoft/wil/issues/44
|
||
|
#include <wil/winrt.h>
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
#include <map>
|
||
|
#include <string>
|
||
|
#endif
|
||
|
|
||
|
// Required for pinterface template specializations that we depend on in this test
|
||
|
#include <Windows.ApplicationModel.Chat.h>
|
||
|
#pragma push_macro("GetCurrentTime")
|
||
|
#undef GetCurrentTime
|
||
|
#include <Windows.UI.Xaml.Data.h>
|
||
|
#pragma pop_macro("GetCurrentTime")
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "FakeWinRTTypes.h"
|
||
|
#include "test_objects.h"
|
||
|
|
||
|
using namespace ABI::Windows::Foundation;
|
||
|
using namespace ABI::Windows::Foundation::Collections;
|
||
|
using namespace ABI::Windows::Storage;
|
||
|
using namespace ABI::Windows::System;
|
||
|
using namespace Microsoft::WRL;
|
||
|
using namespace Microsoft::WRL::Wrappers;
|
||
|
|
||
|
TEST_CASE("WinRTTests::VerifyTraitsTypes", "[winrt]")
|
||
|
{
|
||
|
static_assert(wistd::is_same_v<bool, typename wil::details::LastType<int, bool>::type>, "");
|
||
|
static_assert(wistd::is_same_v<int, typename wil::details::LastType<int>::type>, "");
|
||
|
|
||
|
static_assert(wistd::is_same_v<IAsyncAction*, decltype(wil::details::GetReturnParamPointerType(&IFileIOStatics::WriteTextAsync))>, "");
|
||
|
static_assert(wistd::is_same_v<IAsyncOperation<bool>*, decltype(wil::details::GetReturnParamPointerType(&ILauncherStatics::LaunchUriAsync))>, "");
|
||
|
|
||
|
static_assert(wistd::is_same_v<void, decltype(wil::details::GetAsyncResultType(static_cast<IAsyncAction*>(nullptr)))>, "");
|
||
|
static_assert(wistd::is_same_v<boolean, decltype(wil::details::GetAsyncResultType(static_cast<IAsyncOperation<bool>*>(nullptr)))>, "");
|
||
|
static_assert(wistd::is_same_v<IStorageFile*, decltype(wil::details::GetAsyncResultType(static_cast<IAsyncOperation<StorageFile*>*>(nullptr)))>, "");
|
||
|
}
|
||
|
|
||
|
template <bool InhibitArrayReferences, bool IgnoreCase, typename LhsT, typename RhsT>
|
||
|
void DoHStringComparisonTest(LhsT&& lhs, RhsT&& rhs, int relation)
|
||
|
{
|
||
|
using compare = wil::details::hstring_compare<InhibitArrayReferences, IgnoreCase>;
|
||
|
|
||
|
// == and !=
|
||
|
REQUIRE(compare::equals(lhs, rhs) == (relation == 0));
|
||
|
REQUIRE(compare::not_equals(lhs, rhs) == (relation != 0));
|
||
|
|
||
|
REQUIRE(compare::equals(rhs, lhs) == (relation == 0));
|
||
|
REQUIRE(compare::not_equals(rhs, lhs) == (relation != 0));
|
||
|
|
||
|
// < and >=
|
||
|
REQUIRE(compare::less(lhs, rhs) == (relation < 0));
|
||
|
REQUIRE(compare::greater_equals(lhs, rhs) == (relation >= 0));
|
||
|
|
||
|
REQUIRE(compare::less(rhs, lhs) == (relation > 0));
|
||
|
REQUIRE(compare::greater_equals(rhs, lhs) == (relation <= 0));
|
||
|
|
||
|
// > and <=
|
||
|
REQUIRE(compare::greater(lhs, rhs) == (relation > 0));
|
||
|
REQUIRE(compare::less_equals(lhs, rhs) == (relation <= 0));
|
||
|
|
||
|
REQUIRE(compare::greater(rhs, lhs) == (relation < 0));
|
||
|
REQUIRE(compare::less_equals(rhs, lhs) == (relation >= 0));
|
||
|
|
||
|
// We wish to test with both const and non-const values. We can do this for free here so long as the type is
|
||
|
// not an array since changing the const-ness of an array may change the expected results
|
||
|
#pragma warning(suppress: 4127)
|
||
|
if (!wistd::is_array<wistd::remove_reference_t<LhsT>>::value &&
|
||
|
!wistd::is_const<wistd::remove_reference_t<LhsT>>::value)
|
||
|
{
|
||
|
const wistd::remove_reference_t<LhsT>& constLhs = lhs;
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(constLhs, rhs, relation);
|
||
|
}
|
||
|
|
||
|
#pragma warning(suppress: 4127)
|
||
|
if (!wistd::is_array<wistd::remove_reference_t<RhsT>>::value &&
|
||
|
!wistd::is_const<wistd::remove_reference_t<RhsT>>::value)
|
||
|
{
|
||
|
const wistd::remove_reference_t<RhsT>& constRhs = rhs;
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, constRhs, relation);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The two string arguments are expected to compare equal to one another using the specified IgnoreCase argument and
|
||
|
// contain at least one embedded null character
|
||
|
template <bool InhibitArrayReferences, bool IgnoreCase, size_t Size>
|
||
|
void DoHStringSameValueComparisonTest(const wchar_t (&lhs)[Size], const wchar_t (&rhs)[Size])
|
||
|
{
|
||
|
wchar_t lhsNonConstArray[Size + 5];
|
||
|
wchar_t rhsNonConstArray[Size + 5];
|
||
|
wcsncpy_s(lhsNonConstArray, lhs, Size);
|
||
|
wcsncpy_s(rhsNonConstArray, rhs, Size);
|
||
|
|
||
|
// For non-const arrays, we should never deduce length, so even though we append different values to each string, we
|
||
|
// do so after the last null character, so they should never be read
|
||
|
wcsncpy_s(lhsNonConstArray + Size + 1, 4, L"foo", 3);
|
||
|
wcsncpy_s(rhsNonConstArray + Size + 1, 4, L"bar", 3);
|
||
|
|
||
|
const wchar_t* lhsCstr = lhs;
|
||
|
const wchar_t* rhsCstr = rhs;
|
||
|
|
||
|
HStringReference lhsRef(lhs);
|
||
|
HStringReference rhsRef(rhs);
|
||
|
HString lhsStr;
|
||
|
HString rhsStr;
|
||
|
REQUIRE_SUCCEEDED(lhsStr.Set(lhs));
|
||
|
REQUIRE_SUCCEEDED(rhsStr.Set(rhs));
|
||
|
auto lhsHstr = lhsStr.Get();
|
||
|
auto rhsHstr = rhsStr.Get();
|
||
|
|
||
|
wil::unique_hstring lhsUniqueStr;
|
||
|
wil::unique_hstring rhsUniqueStr;
|
||
|
REQUIRE_SUCCEEDED(lhsStr.CopyTo(&lhsUniqueStr));
|
||
|
REQUIRE_SUCCEEDED(rhsStr.CopyTo(&rhsUniqueStr));
|
||
|
|
||
|
// Const array - embedded nulls are included only if InhibitArrayReferences is false
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhs, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsNonConstArray, InhibitArrayReferences ? 0 : 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsCstr, InhibitArrayReferences ? 0 : 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsRef, InhibitArrayReferences ? -1 : 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsStr, InhibitArrayReferences ? -1 : 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsHstr, InhibitArrayReferences ? -1 : 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsUniqueStr, InhibitArrayReferences ? -1 : 0);
|
||
|
|
||
|
// Non-const array - *never* deduce length
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsNonConstArray, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsCstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsRef, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsStr, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsHstr, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsUniqueStr, -1);
|
||
|
|
||
|
// C string - impossible to deduce length
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsCstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsRef, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsStr, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsHstr, -1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsUniqueStr, -1);
|
||
|
|
||
|
// HStringReference
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsRef, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsStr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsHstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsUniqueStr, 0);
|
||
|
|
||
|
// HString
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsStr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsHstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsUniqueStr, 0);
|
||
|
|
||
|
// Raw HSTRING
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsHstr, rhsHstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsHstr, rhsUniqueStr, 0);
|
||
|
|
||
|
// wil::unique_hstring
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsUniqueStr, rhsUniqueStr, 0);
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
std::wstring lhsWstr(lhs, 7);
|
||
|
std::wstring rhsWstr(rhs, 7);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsWstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhs, InhibitArrayReferences ? 1 : 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsNonConstArray, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsCstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsRef, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsStr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsHstr, 0);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsUniqueStr, 0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// It's expected that the first argument (lhs) compares greater than the second argument (rhs)
|
||
|
template <bool InhibitArrayReferences, bool IgnoreCase, size_t LhsSize, size_t RhsSize>
|
||
|
void DoHStringDifferentValueComparisonTest(const wchar_t (&lhs)[LhsSize], const wchar_t (&rhs)[RhsSize])
|
||
|
{
|
||
|
wchar_t lhsNonConstArray[LhsSize];
|
||
|
wchar_t rhsNonConstArray[RhsSize];
|
||
|
wcsncpy_s(lhsNonConstArray, lhs, LhsSize);
|
||
|
wcsncpy_s(rhsNonConstArray, rhs, RhsSize);
|
||
|
|
||
|
const wchar_t* lhsCstr = lhs;
|
||
|
const wchar_t* rhsCstr = rhs;
|
||
|
|
||
|
HStringReference lhsRef(lhs);
|
||
|
HStringReference rhsRef(rhs);
|
||
|
HString lhsStr;
|
||
|
HString rhsStr;
|
||
|
REQUIRE_SUCCEEDED(lhsStr.Set(lhs));
|
||
|
REQUIRE_SUCCEEDED(rhsStr.Set(rhs));
|
||
|
auto lhsHstr = lhsStr.Get();
|
||
|
auto rhsHstr = rhsStr.Get();
|
||
|
|
||
|
wil::unique_hstring lhsUniqueStr;
|
||
|
wil::unique_hstring rhsUniqueStr;
|
||
|
REQUIRE_SUCCEEDED(lhsStr.CopyTo(&lhsUniqueStr));
|
||
|
REQUIRE_SUCCEEDED(rhsStr.CopyTo(&rhsUniqueStr));
|
||
|
|
||
|
// Const array
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhs, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsNonConstArray, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsCstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsRef, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhs, rhsUniqueStr, 1);
|
||
|
|
||
|
// Non-const array
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsNonConstArray, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsCstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsRef, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsNonConstArray, rhsUniqueStr, 1);
|
||
|
|
||
|
// C string
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsCstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsRef, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsCstr, rhsUniqueStr, 1);
|
||
|
|
||
|
// HStringReference
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsRef, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsRef, rhsUniqueStr, 1);
|
||
|
|
||
|
// HString
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsStr, rhsUniqueStr, 1);
|
||
|
|
||
|
// Raw HSTRING
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsHstr, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsHstr, rhsUniqueStr, 1);
|
||
|
|
||
|
// wil::unique_hstring
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsUniqueStr, rhsUniqueStr, 1);
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
std::wstring lhsWstr(lhs, 7);
|
||
|
std::wstring rhsWstr(rhs, 7);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsWstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhs, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsNonConstArray, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsCstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsRef, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsStr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsHstr, 1);
|
||
|
DoHStringComparisonTest<InhibitArrayReferences, IgnoreCase>(lhsWstr, rhsUniqueStr, 1);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TEST_CASE("WinRTTests::HStringComparison", "[winrt][hstring_compare]")
|
||
|
{
|
||
|
SECTION("Don't inhibit arrays")
|
||
|
{
|
||
|
DoHStringSameValueComparisonTest<false, false>(L"foo\0bar", L"foo\0bar");
|
||
|
DoHStringDifferentValueComparisonTest<false, false>(L"foo", L"bar");
|
||
|
}
|
||
|
|
||
|
SECTION("Inhibit arrays")
|
||
|
{
|
||
|
DoHStringSameValueComparisonTest<true, false>(L"foo\0bar", L"foo\0bar");
|
||
|
DoHStringDifferentValueComparisonTest<true, false>(L"foo", L"bar");
|
||
|
}
|
||
|
|
||
|
SECTION("Ignore case")
|
||
|
{
|
||
|
DoHStringSameValueComparisonTest<true, true>(L"foo\0bar", L"FoO\0bAR");
|
||
|
DoHStringDifferentValueComparisonTest<true, true>(L"Foo", L"baR");
|
||
|
}
|
||
|
|
||
|
SECTION("Empty string")
|
||
|
{
|
||
|
const wchar_t constArray[] = L"";
|
||
|
wchar_t nonConstArray[] = L"";
|
||
|
const wchar_t* cstr = constArray;
|
||
|
const wchar_t* nullCstr = nullptr;
|
||
|
|
||
|
// str may end up referencing a null HSTRING. That's fine; we'll just test null HSTRING twice
|
||
|
HString str;
|
||
|
REQUIRE_SUCCEEDED(str.Set(constArray));
|
||
|
HSTRING nullHstr = nullptr;
|
||
|
|
||
|
// Const array - impossible to use null value
|
||
|
DoHStringComparisonTest<false, false>(constArray, constArray, 0);
|
||
|
DoHStringComparisonTest<false, false>(constArray, nonConstArray, 0);
|
||
|
DoHStringComparisonTest<false, false>(constArray, cstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(constArray, nullCstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(constArray, str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(constArray, nullHstr, 0);
|
||
|
|
||
|
// Non-const array - impossible to use null value
|
||
|
DoHStringComparisonTest<false, false>(nonConstArray, nonConstArray, 0);
|
||
|
DoHStringComparisonTest<false, false>(nonConstArray, cstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(nonConstArray, nullCstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(nonConstArray, str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(nonConstArray, nullHstr, 0);
|
||
|
|
||
|
// Non-null c-string
|
||
|
DoHStringComparisonTest<false, false>(cstr, cstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(cstr, nullCstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(cstr, str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(cstr, nullHstr, 0);
|
||
|
|
||
|
// Null c-string
|
||
|
DoHStringComparisonTest<false, false>(nullCstr, nullCstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(nullCstr, str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(nullCstr, nullHstr, 0);
|
||
|
|
||
|
// (Possibly) non-null HSTRING
|
||
|
DoHStringComparisonTest<false, false>(str.Get(), str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(str.Get(), nullHstr, 0);
|
||
|
|
||
|
// Null HSTRING
|
||
|
DoHStringComparisonTest<false, false>(nullHstr, nullHstr, 0);
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
std::wstring wstr;
|
||
|
DoHStringComparisonTest<false, false>(wstr, wstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, constArray, 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, nonConstArray, 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, cstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, nullCstr, 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, str.Get(), 0);
|
||
|
DoHStringComparisonTest<false, false>(wstr, nullHstr, 0);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
TEST_CASE("WinRTTests::HStringMapTest", "[winrt][hstring_compare]")
|
||
|
{
|
||
|
int nextValue = 0;
|
||
|
std::map<std::wstring, int> wstringMap;
|
||
|
wstringMap.emplace(L"foo", nextValue++);
|
||
|
wstringMap.emplace(L"bar", nextValue++);
|
||
|
wstringMap.emplace(std::wstring(L"foo\0bar", 7), nextValue++);
|
||
|
wstringMap.emplace(L"adding", nextValue++);
|
||
|
wstringMap.emplace(L"quite", nextValue++);
|
||
|
wstringMap.emplace(L"a", nextValue++);
|
||
|
wstringMap.emplace(L"few", nextValue++);
|
||
|
wstringMap.emplace(L"more", nextValue++);
|
||
|
wstringMap.emplace(L"values", nextValue++);
|
||
|
wstringMap.emplace(L"for", nextValue++);
|
||
|
wstringMap.emplace(L"testing", nextValue++);
|
||
|
wstringMap.emplace(L"", nextValue++);
|
||
|
|
||
|
std::map<HString, int> hstringMap;
|
||
|
for (auto& pair : wstringMap)
|
||
|
{
|
||
|
HString str;
|
||
|
THROW_IF_FAILED(str.Set(pair.first.c_str(), static_cast<UINT>(pair.first.length())));
|
||
|
hstringMap.emplace(std::move(str), pair.second);
|
||
|
}
|
||
|
|
||
|
// Order should be the same as the map of wstring
|
||
|
auto itr = hstringMap.begin();
|
||
|
for (auto& pair : wstringMap)
|
||
|
{
|
||
|
REQUIRE(itr != hstringMap.end());
|
||
|
REQUIRE(itr->first == HStringReference(pair.first.c_str(), static_cast<UINT>(pair.first.length())));
|
||
|
|
||
|
// Should also be able to find the value
|
||
|
REQUIRE(hstringMap.find(pair.first) != hstringMap.end());
|
||
|
|
||
|
++itr;
|
||
|
}
|
||
|
REQUIRE(itr == hstringMap.end());
|
||
|
|
||
|
const wchar_t constArray[] = L"foo\0bar";
|
||
|
wchar_t nonConstArray[] = L"foo\0bar";
|
||
|
const wchar_t* cstr = constArray;
|
||
|
|
||
|
HString key;
|
||
|
wil::unique_hstring uniqueHstr;
|
||
|
THROW_IF_FAILED(key.Set(constArray));
|
||
|
THROW_IF_FAILED(key.CopyTo(&uniqueHstr));
|
||
|
|
||
|
HStringReference ref(constArray);
|
||
|
std::wstring wstr(constArray, 7);
|
||
|
|
||
|
auto verifyFunc = [&](int expectedValue, auto&& keyValue)
|
||
|
{
|
||
|
auto itr = hstringMap.find(std::forward<decltype(keyValue)>(keyValue));
|
||
|
REQUIRE(itr != hstringMap.end());
|
||
|
REQUIRE(expectedValue == itr->second);
|
||
|
};
|
||
|
|
||
|
// The following should find "foo\0bar"
|
||
|
auto expectedValue = wstringMap[wstr];
|
||
|
verifyFunc(expectedValue, uniqueHstr);
|
||
|
verifyFunc(expectedValue, key);
|
||
|
verifyFunc(expectedValue, key.Get());
|
||
|
verifyFunc(expectedValue, ref);
|
||
|
verifyFunc(expectedValue, wstr);
|
||
|
|
||
|
// Arrays/strings should not deduce length and should therefore find "foo"
|
||
|
expectedValue = wstringMap[L"foo"];
|
||
|
verifyFunc(expectedValue, constArray);
|
||
|
verifyFunc(expectedValue, nonConstArray);
|
||
|
verifyFunc(expectedValue, cstr);
|
||
|
|
||
|
// Should not ignore case
|
||
|
REQUIRE(hstringMap.find(L"FOO") == hstringMap.end());
|
||
|
|
||
|
// Should also be able to find empty values
|
||
|
const wchar_t constEmptyArray[] = L"";
|
||
|
wchar_t nonConstEmptyArray[] = L"";
|
||
|
const wchar_t* emptyCstr = constEmptyArray;
|
||
|
const wchar_t* nullCstr = nullptr;
|
||
|
|
||
|
HString emptyStr;
|
||
|
HSTRING nullHstr = nullptr;
|
||
|
|
||
|
std::wstring emptyWstr;
|
||
|
|
||
|
expectedValue = wstringMap[L""];
|
||
|
verifyFunc(expectedValue, constEmptyArray);
|
||
|
verifyFunc(expectedValue, nonConstEmptyArray);
|
||
|
verifyFunc(expectedValue, emptyCstr);
|
||
|
verifyFunc(expectedValue, nullCstr);
|
||
|
verifyFunc(expectedValue, emptyStr);
|
||
|
verifyFunc(expectedValue, nullHstr);
|
||
|
verifyFunc(expectedValue, emptyWstr);
|
||
|
}
|
||
|
|
||
|
TEST_CASE("WinRTTests::HStringCaseInsensitiveMapTest", "[winrt][hstring_compare]")
|
||
|
{
|
||
|
std::map<HString, int, wil::hstring_insensitive_less> hstringMap;
|
||
|
|
||
|
auto emplaceFunc = [&](auto&& key, int value)
|
||
|
{
|
||
|
HString str;
|
||
|
THROW_IF_FAILED(str.Set(std::forward<decltype(key)>(key)));
|
||
|
hstringMap.emplace(std::move(str), value);
|
||
|
};
|
||
|
|
||
|
int nextValue = 0;
|
||
|
int fooValue = nextValue++;
|
||
|
emplaceFunc(L"foo", fooValue);
|
||
|
emplaceFunc(L"bar", nextValue++);
|
||
|
int foobarValue = nextValue++;
|
||
|
emplaceFunc(L"foo\0bar", foobarValue);
|
||
|
emplaceFunc(L"foobar", nextValue++);
|
||
|
emplaceFunc(L"adding", nextValue++);
|
||
|
emplaceFunc(L"some", nextValue++);
|
||
|
emplaceFunc(L"more", nextValue++);
|
||
|
emplaceFunc(L"values", nextValue++);
|
||
|
emplaceFunc(L"for", nextValue++);
|
||
|
emplaceFunc(L"testing", nextValue++);
|
||
|
WI_ASSERT(static_cast<size_t>(nextValue) == hstringMap.size());
|
||
|
|
||
|
const wchar_t constArray[] = L"FoO\0BAr";
|
||
|
wchar_t nonConstArray[] = L"fOo\0baR";
|
||
|
const wchar_t* cstr = constArray;
|
||
|
|
||
|
HString key;
|
||
|
wil::unique_hstring uniqueHstr;
|
||
|
THROW_IF_FAILED(key.Set(constArray));
|
||
|
THROW_IF_FAILED(key.CopyTo(&uniqueHstr));
|
||
|
|
||
|
HStringReference ref(constArray);
|
||
|
std::wstring wstr(constArray, 7);
|
||
|
|
||
|
auto verifyFunc = [&](int expectedValue, auto&& key)
|
||
|
{
|
||
|
auto itr = hstringMap.find(std::forward<decltype(key)>(key));
|
||
|
REQUIRE(itr != std::end(hstringMap));
|
||
|
REQUIRE(expectedValue == itr->second);
|
||
|
};
|
||
|
|
||
|
// The following should find "foo\0bar"
|
||
|
verifyFunc(foobarValue, uniqueHstr);
|
||
|
verifyFunc(foobarValue, key);
|
||
|
verifyFunc(foobarValue, key.Get());
|
||
|
verifyFunc(foobarValue, ref);
|
||
|
verifyFunc(foobarValue, wstr);
|
||
|
|
||
|
// Arrays/strings should not deduce length and should therefore find "foo"
|
||
|
verifyFunc(fooValue, constArray);
|
||
|
verifyFunc(fooValue, nonConstArray);
|
||
|
verifyFunc(fooValue, cstr);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// This is not a test method, nor should it be called. This is a compilation-only test.
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
void RunWhenCompleteCompilationTest()
|
||
|
{
|
||
|
{
|
||
|
ComPtr<IAsyncOperation<HSTRING>> stringOp;
|
||
|
wil::run_when_complete(stringOp.Get(), [](HRESULT /* result */, HSTRING /* value */) {});
|
||
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||
|
auto result = wil::wait_for_completion(stringOp.Get());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
{
|
||
|
ComPtr<IAsyncOperationWithProgress<HSTRING, UINT64>> stringOpWithProgress;
|
||
|
wil::run_when_complete(stringOpWithProgress.Get(), [](HRESULT /* result */, HSTRING /* value */) {});
|
||
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||
|
auto result = wil::wait_for_completion(stringOpWithProgress.Get());
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
TEST_CASE("WinRTTests::RunWhenCompleteMoveOnlyTest", "[winrt][run_when_complete]")
|
||
|
{
|
||
|
auto op = Make<FakeAsyncOperation<int>>();
|
||
|
REQUIRE(op);
|
||
|
|
||
|
bool gotEvent = false;
|
||
|
auto hr = wil::run_when_complete_nothrow(op.Get(), [&gotEvent, enforce = cannot_copy{}](HRESULT hr, int result)
|
||
|
{
|
||
|
(void)enforce;
|
||
|
REQUIRE_SUCCEEDED(hr);
|
||
|
REQUIRE(result == 42);
|
||
|
gotEvent = true;
|
||
|
return S_OK;
|
||
|
});
|
||
|
REQUIRE_SUCCEEDED(hr);
|
||
|
|
||
|
op->Complete(S_OK, 42);
|
||
|
REQUIRE(gotEvent);
|
||
|
}
|
||
|
|
||
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||
|
TEST_CASE("WinRTTests::WaitForCompletionTimeout", "[winrt][wait_for_completion]")
|
||
|
{
|
||
|
auto op = Make<FakeAsyncOperation<bool, boolean>>();
|
||
|
REQUIRE(op);
|
||
|
|
||
|
// The wait_for_completion* functions don't properly deduce the "decayed" async type, so force it here
|
||
|
auto asyncOp = static_cast<IAsyncOperation<bool>*>(op.Get());
|
||
|
|
||
|
bool timedOut = false;
|
||
|
REQUIRE_SUCCEEDED(wil::wait_for_completion_or_timeout_nothrow(asyncOp, 1, &timedOut));
|
||
|
REQUIRE(timedOut);
|
||
|
}
|
||
|
|
||
|
// This is not a test method, nor should it be called. This is a compilation-only test.
|
||
|
#pragma warning(push)
|
||
|
#pragma warning(disable: 4702) // Unreachable code
|
||
|
void WaitForCompletionCompilationTest()
|
||
|
{
|
||
|
// Ensure the wait_for_completion variants compile
|
||
|
FAIL_FAST_HR_MSG(E_UNEXPECTED, "This is a compilation test, and should not be called");
|
||
|
|
||
|
// template <typename TAsync = ABI::Windows::Foundation::IAsyncAction>
|
||
|
// inline HRESULT wait_for_completion_nothrow(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
IAsyncAction* action = nullptr;
|
||
|
wil::wait_for_completion_nothrow(action);
|
||
|
wil::wait_for_completion_nothrow(action, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult>
|
||
|
// HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation<TResult>* operation,
|
||
|
// _Out_ typename wil::details::MapAsyncOpResultType<TResult>::type* result,
|
||
|
// COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
IAsyncOperation<bool>* operation = nullptr;
|
||
|
wil::wait_for_completion_nothrow(operation);
|
||
|
wil::wait_for_completion_nothrow(operation, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult, typename TProgress>
|
||
|
// HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>* operation,
|
||
|
// _Out_ typename wil::details::MapAsyncOpProgressResultType<TResult, TProgress>::type* result,
|
||
|
// COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
|
||
|
ComPtr<IAsyncOperation<bool>> operationWithResult;
|
||
|
boolean result = false;
|
||
|
wil::wait_for_completion_nothrow(operationWithResult.Get(), &result);
|
||
|
wil::wait_for_completion_nothrow(operationWithResult.Get(), &result, COWAIT_DEFAULT);
|
||
|
|
||
|
DWORD timeoutValue = 1000; // arbitrary
|
||
|
bool timedOut = false;
|
||
|
|
||
|
// template <typename TAsync = ABI::Windows::Foundation::IAsyncAction>
|
||
|
// inline HRESULT wait_for_completion_or_timeout_nothrow(_In_ TAsync* operation,
|
||
|
// DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(action, timeoutValue, &timedOut);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(action, timeoutValue, &timedOut, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult>
|
||
|
// HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation<TResult>* operation,
|
||
|
// _Out_ typename wil::details::MapAsyncOpResultType<TResult>::type* result,
|
||
|
// DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(operation, timeoutValue, &timedOut);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(operation, timeoutValue, &timedOut, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult, typename TProgress>
|
||
|
// HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>* operation,
|
||
|
// _Out_ typename wil::details::MapAsyncOpProgressResultType<TResult, TProgress>::type* result,
|
||
|
// DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(operationWithResult.Get(), &result, timeoutValue, &timedOut);
|
||
|
wil::wait_for_completion_or_timeout_nothrow(operationWithResult.Get(), &result, timeoutValue, &timedOut, COWAIT_DEFAULT);
|
||
|
|
||
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
||
|
// template <typename TAsync = ABI::Windows::Foundation::IAsyncAction>
|
||
|
// inline void wait_for_completion(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
wil::wait_for_completion(action);
|
||
|
wil::wait_for_completion(action, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult, typename TReturn = typename wil::details::MapToSmartType<typename wil::details::MapAsyncOpResultType<TResult>::type>::type>
|
||
|
// TReturn
|
||
|
// wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation<TResult>* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
wil::wait_for_completion(operation);
|
||
|
wil::wait_for_completion(operation, COWAIT_DEFAULT);
|
||
|
|
||
|
// template <typename TResult, typename TProgress, typename TReturn = typename wil::details::MapToSmartType<typename wil::details::MapAsyncOpResultType<TResult>::type>::type>
|
||
|
// TReturn
|
||
|
// wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS, DWORD timeout = INFINITE);
|
||
|
result = wil::wait_for_completion(operationWithResult.Get());
|
||
|
result = wil::wait_for_completion(operationWithResult.Get(), COWAIT_DEFAULT);
|
||
|
#endif
|
||
|
}
|
||
|
#pragma warning(pop)
|
||
|
#endif
|
||
|
|
||
|
TEST_CASE("WinRTTests::TimeTTests", "[winrt][time_t]")
|
||
|
{
|
||
|
// Verifying that converting DateTime variable set as the date that means 0 as time_t works
|
||
|
DateTime time1 = { wil::SecondsToStartOf1970 * wil::HundredNanoSecondsInSecond };
|
||
|
__time64_t time_t1 = wil::DateTime_to_time_t(time1);
|
||
|
REQUIRE(time_t1 == 0);
|
||
|
|
||
|
// Verifying that converting back to DateTime would return the same value
|
||
|
DateTime time2 = wil::time_t_to_DateTime(time_t1);
|
||
|
REQUIRE(time1.UniversalTime == time2.UniversalTime);
|
||
|
|
||
|
// Verifying that converting to time_t for non-zero value also works
|
||
|
time2.UniversalTime += wil::HundredNanoSecondsInSecond * 123;
|
||
|
__time64_t time_t2 = wil::DateTime_to_time_t(time2);
|
||
|
REQUIRE(time_t2 - time_t1 == 123);
|
||
|
|
||
|
// Verifying that converting back to DateTime for non-zero value also works
|
||
|
time1 = wil::time_t_to_DateTime(time_t2);
|
||
|
REQUIRE(time1.UniversalTime == time2.UniversalTime);
|
||
|
}
|
||
|
|
||
|
ComPtr<IVector<IInspectable*>> MakeSampleInspectableVector()
|
||
|
{
|
||
|
auto result = Make<FakeVector<IInspectable*>>();
|
||
|
REQUIRE(result);
|
||
|
|
||
|
ComPtr<IPropertyValueStatics> propStatics;
|
||
|
REQUIRE_SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propStatics));
|
||
|
|
||
|
for (UINT32 i = 0; i < 5; ++i)
|
||
|
{
|
||
|
ComPtr<IInspectable> myProp;
|
||
|
REQUIRE_SUCCEEDED(propStatics->CreateUInt32(i, &myProp));
|
||
|
REQUIRE_SUCCEEDED(result->Append(myProp.Get()));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
ComPtr<IVector<HSTRING>> MakeSampleStringVector()
|
||
|
{
|
||
|
auto result = Make<FakeVector<HSTRING>>();
|
||
|
REQUIRE(result);
|
||
|
|
||
|
const HStringReference items[] = { HStringReference(L"one"), HStringReference(L"two"), HStringReference(L"three") };
|
||
|
for (const auto& i : items)
|
||
|
{
|
||
|
REQUIRE_SUCCEEDED(result->Append(i.Get()));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
ComPtr<IVector<Point>> MakeSamplePointVector()
|
||
|
{
|
||
|
auto result = Make<FakeVector<Point>>();
|
||
|
REQUIRE(result);
|
||
|
|
||
|
for (int i = 0; i < 5; ++i)
|
||
|
{
|
||
|
auto value = static_cast<float>(i);
|
||
|
REQUIRE_SUCCEEDED(result->Append(Point{ value, value }));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
TEST_CASE("WinRTTests::VectorRangeTest", "[winrt][vector_range]")
|
||
|
{
|
||
|
auto uninit = wil::RoInitialize_failfast();
|
||
|
|
||
|
auto inspectables = MakeSampleInspectableVector();
|
||
|
unsigned count = 0;
|
||
|
REQUIRE_SUCCEEDED(inspectables->get_Size(&count));
|
||
|
|
||
|
unsigned idx = 0;
|
||
|
HRESULT success = S_OK;
|
||
|
for (const auto& i : wil::get_range_nothrow(inspectables.Get(), &success))
|
||
|
{
|
||
|
// Duplications are not a typo - they verify the thing is callable twice
|
||
|
|
||
|
UINT32 value;
|
||
|
ComPtr<IReference<UINT32>> intRef;
|
||
|
REQUIRE_SUCCEEDED(i.CopyTo(IID_PPV_ARGS(&intRef)));
|
||
|
REQUIRE_SUCCEEDED(intRef->get_Value(&value));
|
||
|
REQUIRE(idx == value);
|
||
|
REQUIRE_SUCCEEDED(i.CopyTo(IID_PPV_ARGS(&intRef)));
|
||
|
REQUIRE_SUCCEEDED(intRef->get_Value(&value));
|
||
|
REQUIRE(idx == value);
|
||
|
|
||
|
++idx;
|
||
|
|
||
|
HString rtc;
|
||
|
REQUIRE_SUCCEEDED(i->GetRuntimeClassName(rtc.GetAddressOf()));
|
||
|
REQUIRE_SUCCEEDED(i->GetRuntimeClassName(rtc.GetAddressOf()));
|
||
|
}
|
||
|
REQUIRE_SUCCEEDED(success);
|
||
|
REQUIRE(count == idx);
|
||
|
|
||
|
auto strings = MakeSampleStringVector();
|
||
|
for (const auto& i : wil::get_range_nothrow(strings.Get(), &success))
|
||
|
{
|
||
|
REQUIRE(i.Get());
|
||
|
REQUIRE(i.Get());
|
||
|
}
|
||
|
REQUIRE_SUCCEEDED(success);
|
||
|
|
||
|
int index = 0;
|
||
|
auto points = MakeSamplePointVector();
|
||
|
for (auto value : wil::get_range_nothrow(points.Get(), &success))
|
||
|
{
|
||
|
REQUIRE(index++ == value.Get().X);
|
||
|
}
|
||
|
REQUIRE_SUCCEEDED(success);
|
||
|
|
||
|
// operator-> should not clear out the pointer
|
||
|
auto inspRange = wil::get_range_nothrow(inspectables.Get());
|
||
|
for (auto itr = inspRange.begin(); itr != inspRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(itr->Get());
|
||
|
}
|
||
|
|
||
|
auto strRange = wil::get_range_nothrow(strings.Get());
|
||
|
for (auto itr = strRange.begin(); itr != strRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(itr->Get());
|
||
|
}
|
||
|
|
||
|
index = 0;
|
||
|
auto pointRange = wil::get_range_nothrow(points.Get());
|
||
|
for (auto itr = pointRange.begin(); itr != pointRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(index++ == itr->Get().X);
|
||
|
}
|
||
|
|
||
|
#if (defined WIL_ENABLE_EXCEPTIONS)
|
||
|
idx = 0;
|
||
|
for (const auto& i : wil::get_range(inspectables.Get()))
|
||
|
{
|
||
|
// Duplications are not a typo - they verify the thing is callable twice
|
||
|
|
||
|
UINT32 value;
|
||
|
ComPtr<IReference<UINT32>> intRef;
|
||
|
REQUIRE_SUCCEEDED(i.CopyTo(IID_PPV_ARGS(&intRef)));
|
||
|
REQUIRE_SUCCEEDED(intRef->get_Value(&value));
|
||
|
REQUIRE(idx == value);
|
||
|
REQUIRE_SUCCEEDED(i.CopyTo(IID_PPV_ARGS(&intRef)));
|
||
|
REQUIRE_SUCCEEDED(intRef->get_Value(&value));
|
||
|
REQUIRE(idx == value);
|
||
|
|
||
|
++idx;
|
||
|
|
||
|
HString rtc;
|
||
|
REQUIRE_SUCCEEDED(i->GetRuntimeClassName(rtc.GetAddressOf()));
|
||
|
REQUIRE_SUCCEEDED(i->GetRuntimeClassName(rtc.GetAddressOf()));
|
||
|
}
|
||
|
REQUIRE(count == idx);
|
||
|
|
||
|
for (const auto& i : wil::get_range(strings.Get()))
|
||
|
{
|
||
|
REQUIRE(i.Get());
|
||
|
REQUIRE(i.Get());
|
||
|
}
|
||
|
|
||
|
index = 0;
|
||
|
for (auto value : wil::get_range(points.Get()))
|
||
|
{
|
||
|
REQUIRE(index++ == value.Get().X);
|
||
|
}
|
||
|
|
||
|
// operator-> should not clear out the pointer
|
||
|
for (auto itr = inspRange.begin(); itr != inspRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(itr->Get());
|
||
|
}
|
||
|
|
||
|
for (auto itr = strRange.begin(); itr != strRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(itr->Get());
|
||
|
}
|
||
|
|
||
|
index = 0;
|
||
|
for (auto itr = pointRange.begin(); itr != pointRange.end(); ++itr)
|
||
|
{
|
||
|
REQUIRE(index++ == itr->Get().X);
|
||
|
}
|
||
|
|
||
|
// Iterator self-assignment is a nop.
|
||
|
{
|
||
|
auto inspRange2 = wil::get_range(inspectables.Get());
|
||
|
auto itr = inspRange2.begin();
|
||
|
REQUIRE(itr != inspRange2.end()); // should have something in it
|
||
|
auto& ref = *itr;
|
||
|
auto val = ref;
|
||
|
itr = itr;
|
||
|
REQUIRE(val == ref);
|
||
|
itr = std::move(itr);
|
||
|
REQUIRE(val == ref);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
auto strRange2 = wil::get_range(strings.Get());
|
||
|
auto itr = strRange2.begin();
|
||
|
REQUIRE(itr != strRange2.end()); // should have something in it
|
||
|
auto& ref = *itr;
|
||
|
auto val = ref.Get();
|
||
|
itr = itr;
|
||
|
REQUIRE(val == ref);
|
||
|
itr = std::move(itr);
|
||
|
REQUIRE(val == ref.Get());
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
unsigned long GetComObjectRefCount(IUnknown* unk) { unk->AddRef(); return unk->Release(); }
|
||
|
|
||
|
TEST_CASE("WinRTTests::VectorRangeLeakTest", "[winrt][vector_range]")
|
||
|
{
|
||
|
auto uninit = wil::RoInitialize_failfast();
|
||
|
|
||
|
auto inspectables = MakeSampleInspectableVector();
|
||
|
ComPtr<IInspectable> verifyNotLeaked;
|
||
|
HRESULT hr = S_OK;
|
||
|
for (const auto& ptr : wil::get_range_nothrow(inspectables.Get(), &hr))
|
||
|
{
|
||
|
if (!verifyNotLeaked)
|
||
|
{
|
||
|
verifyNotLeaked = ptr;
|
||
|
}
|
||
|
}
|
||
|
inspectables = nullptr; // clear all refs to verifyNotLeaked
|
||
|
REQUIRE_SUCCEEDED(hr);
|
||
|
REQUIRE(GetComObjectRefCount(verifyNotLeaked.Get()) == 1);
|
||
|
|
||
|
inspectables = MakeSampleInspectableVector();
|
||
|
for (const auto& ptr : wil::get_range_failfast(inspectables.Get()))
|
||
|
{
|
||
|
if (!verifyNotLeaked)
|
||
|
{
|
||
|
verifyNotLeaked = ptr;
|
||
|
}
|
||
|
}
|
||
|
inspectables = nullptr; // clear all refs to verifyNotLeaked
|
||
|
REQUIRE(GetComObjectRefCount(verifyNotLeaked.Get()) == 1);
|
||
|
|
||
|
#if (defined WIL_ENABLE_EXCEPTIONS)
|
||
|
inspectables = MakeSampleInspectableVector();
|
||
|
for (const auto& ptr : wil::get_range(inspectables.Get()))
|
||
|
{
|
||
|
if (!verifyNotLeaked)
|
||
|
{
|
||
|
verifyNotLeaked = ptr;
|
||
|
}
|
||
|
}
|
||
|
inspectables = nullptr; // clear all refs to verifyNotLeaked
|
||
|
REQUIRE(GetComObjectRefCount(verifyNotLeaked.Get()) == 1);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TEST_CASE("WinRTTests::TwoPhaseConstructor", "[winrt][hstring]")
|
||
|
{
|
||
|
const wchar_t left[] = L"left";
|
||
|
const wchar_t right[] = L"right";
|
||
|
ULONG needed = ARRAYSIZE(left) + ARRAYSIZE(right) - 1;
|
||
|
auto maker = wil::TwoPhaseHStringConstructor::Preallocate(needed);
|
||
|
REQUIRE_SUCCEEDED(StringCbCopyW(maker.Get(), maker.ByteSize(), left));
|
||
|
REQUIRE_SUCCEEDED(StringCbCatW(maker.Get(), maker.ByteSize(), right));
|
||
|
REQUIRE_SUCCEEDED(maker.Validate(needed * sizeof(wchar_t)));
|
||
|
|
||
|
wil::unique_hstring promoted{ maker.Promote() };
|
||
|
REQUIRE(wcscmp(L"leftright", str_raw_ptr(promoted)) == 0);
|
||
|
}
|