mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-14 02:26:50 -07:00
Decouple with a mocked service (#2256)
* refactor * build succeed * mock web failures * mock awaitable * resolve comment * improve scope guard * resolve a comment
This commit is contained in:
parent
c94a88ebad
commit
bb540e6d80
18 changed files with 345 additions and 500 deletions
|
@ -171,8 +171,8 @@ void ApplicationViewModel::OnModeChanged()
|
||||||
if (!m_ConverterViewModel)
|
if (!m_ConverterViewModel)
|
||||||
{
|
{
|
||||||
auto dataLoader = std::make_shared<UnitConverterDataLoader>(ref new GeographicRegion());
|
auto dataLoader = std::make_shared<UnitConverterDataLoader>(ref new GeographicRegion());
|
||||||
auto currencyDataLoader = std::make_shared<CurrencyDataLoader>(std::make_unique<CurrencyHttpClient>());
|
m_ConverterViewModel =
|
||||||
m_ConverterViewModel = ref new UnitConverterViewModel(std::make_shared<UnitConversionManager::UnitConverter>(dataLoader, currencyDataLoader));
|
ref new UnitConverterViewModel(std::make_shared<UnitConversionManager::UnitConverter>(dataLoader, std::make_shared<CurrencyDataLoader>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ConverterViewModel->Mode = m_mode;
|
m_ConverterViewModel->Mode = m_mode;
|
||||||
|
|
|
@ -325,7 +325,6 @@
|
||||||
<ClInclude Include="Common\Utils.h" />
|
<ClInclude Include="Common\Utils.h" />
|
||||||
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
|
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
|
||||||
<ClInclude Include="DataLoaders\CurrencyHttpClient.h" />
|
<ClInclude Include="DataLoaders\CurrencyHttpClient.h" />
|
||||||
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h" />
|
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h" />
|
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h" />
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h" />
|
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h" />
|
||||||
<ClInclude Include="DateCalculatorViewModel.h" />
|
<ClInclude Include="DateCalculatorViewModel.h" />
|
||||||
|
@ -396,23 +395,6 @@
|
||||||
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
|
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemDefinitionGroup Condition="!Exists('DataLoaders\DataLoaderConstants.h')">
|
|
||||||
<ClCompile>
|
|
||||||
<AdditionalOptions>/DUSE_MOCK_DATA %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<Choose>
|
|
||||||
<When Condition="Exists('DataLoaders\DataLoaderConstants.h')">
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="DataLoaders\DataLoaderConstants.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
</When>
|
|
||||||
<Otherwise>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Otherwise>
|
|
||||||
</Choose>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DataLoaders\DefaultFromToCurrency.json" />
|
<None Include="DataLoaders\DefaultFromToCurrency.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -171,12 +171,6 @@
|
||||||
<ClInclude Include="DataLoaders\CurrencyHttpClient.h">
|
<ClInclude Include="DataLoaders\CurrencyHttpClient.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h">
|
|
||||||
<Filter>DataLoaders</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h">
|
|
||||||
<Filter>DataLoaders</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h">
|
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -89,9 +89,8 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr<ICurrencyHttpClient> client, const wchar_t* forcedResponseLanguage)
|
CurrencyDataLoader::CurrencyDataLoader(const wchar_t* forcedResponseLanguage)
|
||||||
: m_client(move(client))
|
: m_loadStatus(CurrencyLoadStatus::NotLoaded)
|
||||||
, m_loadStatus(CurrencyLoadStatus::NotLoaded)
|
|
||||||
, m_responseLanguage(L"en-US")
|
, m_responseLanguage(L"en-US")
|
||||||
, m_ratioFormat(L"")
|
, m_ratioFormat(L"")
|
||||||
, m_timestampFormat(L"")
|
, m_timestampFormat(L"")
|
||||||
|
@ -122,12 +121,7 @@ CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr<ICurrencyHttpClient> clie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_client != nullptr)
|
m_client.Initialize(StringReference{ DefaultCurrencyCode.data() }, m_responseLanguage);
|
||||||
{
|
|
||||||
m_client->SetSourceCurrencyCode(StringReference(DefaultCurrencyCode.data()));
|
|
||||||
m_client->SetResponseLanguage(m_responseLanguage);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto localizationService = LocalizationService::GetInstance();
|
auto localizationService = LocalizationService::GetInstance();
|
||||||
if (CoreWindow::GetForCurrentThread() != nullptr)
|
if (CoreWindow::GetForCurrentThread() != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -199,26 +193,29 @@ void CurrencyDataLoader::LoadData()
|
||||||
if (!LoadFinished())
|
if (!LoadFinished())
|
||||||
{
|
{
|
||||||
RegisterForNetworkBehaviorChanges();
|
RegisterForNetworkBehaviorChanges();
|
||||||
create_task([this]() -> task<bool> {
|
create_task(
|
||||||
vector<function<future<bool>()>> loadFunctions = {
|
[this]() -> task<bool>
|
||||||
[this]() { return TryLoadDataFromCacheAsync(); },
|
|
||||||
[this]() { return TryLoadDataFromWebAsync(); },
|
|
||||||
};
|
|
||||||
|
|
||||||
bool didLoad = false;
|
|
||||||
for (auto& f : loadFunctions)
|
|
||||||
{
|
{
|
||||||
didLoad = co_await f();
|
vector<function<future<bool>()>> loadFunctions = {
|
||||||
if (didLoad)
|
[this]() { return TryLoadDataFromCacheAsync(); },
|
||||||
{
|
[this]() { return TryLoadDataFromWebAsync(); },
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
co_return didLoad;
|
bool didLoad = false;
|
||||||
})
|
for (auto& f : loadFunctions)
|
||||||
|
{
|
||||||
|
didLoad = co_await f();
|
||||||
|
if (didLoad)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
co_return didLoad;
|
||||||
|
})
|
||||||
.then(
|
.then(
|
||||||
[this](bool didLoad) {
|
[this](bool didLoad)
|
||||||
|
{
|
||||||
UpdateDisplayedTimestamp();
|
UpdateDisplayedTimestamp();
|
||||||
NotifyDataLoadFinished(didLoad);
|
NotifyDataLoadFinished(didLoad);
|
||||||
},
|
},
|
||||||
|
@ -283,9 +280,7 @@ double CurrencyDataLoader::RoundCurrencyRatio(double ratio)
|
||||||
int numberDecimals = FORMATTER_RATE_MIN_DECIMALS;
|
int numberDecimals = FORMATTER_RATE_MIN_DECIMALS;
|
||||||
if (ratio < 1)
|
if (ratio < 1)
|
||||||
{
|
{
|
||||||
numberDecimals = max(
|
numberDecimals = max(FORMATTER_RATE_MIN_DECIMALS, (int)(-log10(ratio)) + FORMATTER_RATE_MIN_SIGNIFICANT_DECIMALS);
|
||||||
FORMATTER_RATE_MIN_DECIMALS,
|
|
||||||
(int)(-log10(ratio)) + FORMATTER_RATE_MIN_SIGNIFICANT_DECIMALS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long scale = (unsigned long long)powl(10l, numberDecimals);
|
unsigned long long scale = (unsigned long long)powl(10l, numberDecimals);
|
||||||
|
@ -314,8 +309,7 @@ pair<wstring, wstring> CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U
|
||||||
auto ratioString = LocalizationStringUtil::GetLocalizedString(
|
auto ratioString = LocalizationStringUtil::GetLocalizedString(
|
||||||
m_ratioFormat, digitSymbol, StringReference(unit1.abbreviation.c_str()), roundedFormat, StringReference(unit2.abbreviation.c_str()));
|
m_ratioFormat, digitSymbol, StringReference(unit1.abbreviation.c_str()), roundedFormat, StringReference(unit2.abbreviation.c_str()));
|
||||||
|
|
||||||
auto accessibleRatioString =
|
auto accessibleRatioString = LocalizationStringUtil::GetLocalizedString(
|
||||||
LocalizationStringUtil::GetLocalizedString(
|
|
||||||
m_ratioFormat, digitSymbol, StringReference(unit1.accessibleName.c_str()), roundedFormat, StringReference(unit2.accessibleName.c_str()));
|
m_ratioFormat, digitSymbol, StringReference(unit1.accessibleName.c_str()), roundedFormat, StringReference(unit2.accessibleName.c_str()));
|
||||||
|
|
||||||
return make_pair(ratioString->Data(), accessibleRatioString->Data());
|
return make_pair(ratioString->Data(), accessibleRatioString->Data());
|
||||||
|
@ -415,18 +409,13 @@ future<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
|
||||||
{
|
{
|
||||||
ResetLoadStatus();
|
ResetLoadStatus();
|
||||||
|
|
||||||
if (m_client == nullptr)
|
|
||||||
{
|
|
||||||
co_return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_networkAccessBehavior == NetworkAccessBehavior::Offline || (m_networkAccessBehavior == NetworkAccessBehavior::OptIn && !m_meteredOverrideSet))
|
if (m_networkAccessBehavior == NetworkAccessBehavior::Offline || (m_networkAccessBehavior == NetworkAccessBehavior::OptIn && !m_meteredOverrideSet))
|
||||||
{
|
{
|
||||||
co_return false;
|
co_return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ^ staticDataResponse = co_await m_client->GetCurrencyMetadata();
|
String ^ staticDataResponse = co_await m_client.GetCurrencyMetadataAsync();
|
||||||
String ^ allRatiosResponse = co_await m_client->GetCurrencyRatios();
|
String ^ allRatiosResponse = co_await m_client.GetCurrencyRatiosAsync();
|
||||||
if (staticDataResponse == nullptr || allRatiosResponse == nullptr)
|
if (staticDataResponse == nullptr || allRatiosResponse == nullptr)
|
||||||
{
|
{
|
||||||
co_return false;
|
co_return false;
|
||||||
|
@ -550,9 +539,7 @@ bool CurrencyDataLoader::TryParseStaticData(_In_ String ^ rawJson, _Inout_ vecto
|
||||||
staticData[i] = CurrencyStaticData{ countryCode, countryName, currencyCode, currencyName, currencySymbol };
|
staticData[i] = CurrencyStaticData{ countryCode, countryName, currencyCode, currencyName, currencySymbol };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sortCountryNames = [](const UCM::CurrencyStaticData & s) {
|
auto sortCountryNames = [](const UCM::CurrencyStaticData& s) { return ref new String(s.countryName.c_str()); };
|
||||||
return ref new String(s.countryName.c_str());
|
|
||||||
};
|
|
||||||
|
|
||||||
LocalizationService::GetInstance()->Sort<UCM::CurrencyStaticData>(staticData, sortCountryNames);
|
LocalizationService::GetInstance()->Sort<UCM::CurrencyStaticData>(staticData, sortCountryNames);
|
||||||
|
|
||||||
|
@ -577,7 +564,7 @@ bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String ^ rawJson, _Inout_ Cu
|
||||||
{
|
{
|
||||||
obj = data->GetAt(i)->GetObject();
|
obj = data->GetAt(i)->GetObject();
|
||||||
}
|
}
|
||||||
catch (COMException^ e)
|
catch (COMException ^ e)
|
||||||
{
|
{
|
||||||
if (e->HResult == E_ILLEGAL_METHOD_CALL)
|
if (e->HResult == E_ILLEGAL_METHOD_CALL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "CalcManager/UnitConverter.h"
|
#include "CalcManager/UnitConverter.h"
|
||||||
#include "Common/NetworkManager.h"
|
#include "Common/NetworkManager.h"
|
||||||
#include "ICurrencyHttpClient.h"
|
#include "CurrencyHttpClient.h"
|
||||||
|
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
{
|
{
|
||||||
|
@ -54,9 +54,7 @@ namespace CalculatorApp
|
||||||
class CurrencyDataLoader : public UCM::IConverterDataLoader, public UCM::ICurrencyConverterDataLoader
|
class CurrencyDataLoader : public UCM::IConverterDataLoader, public UCM::ICurrencyConverterDataLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CurrencyDataLoader(
|
CurrencyDataLoader(const wchar_t* overrideLanguage = nullptr);
|
||||||
_In_ std::unique_ptr<CalculatorApp::ViewModel::DataLoaders::ICurrencyHttpClient> client,
|
|
||||||
const wchar_t* overrideLanguage = nullptr);
|
|
||||||
~CurrencyDataLoader();
|
~CurrencyDataLoader();
|
||||||
|
|
||||||
bool LoadFinished();
|
bool LoadFinished();
|
||||||
|
@ -114,7 +112,7 @@ namespace CalculatorApp
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Platform::String ^ m_responseLanguage;
|
Platform::String ^ m_responseLanguage;
|
||||||
std::unique_ptr<CalculatorApp::ViewModel::DataLoaders::ICurrencyHttpClient> m_client;
|
CurrencyHttpClient m_client;
|
||||||
|
|
||||||
bool m_isRtlLanguage;
|
bool m_isRtlLanguage;
|
||||||
|
|
||||||
|
|
|
@ -4,47 +4,145 @@
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "CurrencyHttpClient.h"
|
#include "CurrencyHttpClient.h"
|
||||||
|
|
||||||
#ifdef USE_MOCK_DATA
|
namespace
|
||||||
#include "DataLoaderMockConstants.h"
|
|
||||||
#else
|
|
||||||
#include "DataLoaderConstants.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace CalculatorApp::DataLoaders;
|
|
||||||
using namespace CalculatorApp::ViewModel::DataLoaders;
|
|
||||||
using namespace Platform;
|
|
||||||
using namespace std;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
using namespace Windows::Web::Http;
|
|
||||||
|
|
||||||
CurrencyHttpClient::CurrencyHttpClient()
|
|
||||||
: m_client(ref new HttpClient())
|
|
||||||
, m_responseLanguage(L"en-US")
|
|
||||||
{
|
{
|
||||||
}
|
constexpr auto MockCurrencyConverterData = LR"(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"An": "MAR",
|
||||||
|
"Rt": 1.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "MON",
|
||||||
|
"Rt": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "NEP",
|
||||||
|
"Rt": 0.00125
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "SAT",
|
||||||
|
"Rt": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "URA",
|
||||||
|
"Rt": 2.75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "VEN",
|
||||||
|
"Rt": 900.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "JUP",
|
||||||
|
"Rt": 1.23456789123456789
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "MER",
|
||||||
|
"Rt": 2.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "JPY",
|
||||||
|
"Rt": 0.00125
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"An": "JOD",
|
||||||
|
"Rt": 0.25
|
||||||
|
}
|
||||||
|
])";
|
||||||
|
|
||||||
void CurrencyHttpClient::SetSourceCurrencyCode(String ^ sourceCurrencyCode)
|
constexpr auto MockCurrencyStaticData = LR"(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"CountryCode": "MAR",
|
||||||
|
"CountryName": "Mars",
|
||||||
|
"CurrencyCode": "MAR",
|
||||||
|
"CurrencyName": "The Martian Dollar",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "MON",
|
||||||
|
"CountryName": "Moon",
|
||||||
|
"CurrencyCode": "MON",
|
||||||
|
"CurrencyName": "Moon Bucks",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "NEP",
|
||||||
|
"CountryName": "Neptune",
|
||||||
|
"CurrencyCode": "NEP",
|
||||||
|
"CurrencyName": "Space Coins",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "SAT",
|
||||||
|
"CountryName": "Saturn",
|
||||||
|
"CurrencyCode": "SAT",
|
||||||
|
"CurrencyName": "Rings",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "URA",
|
||||||
|
"CountryName": "Uranus",
|
||||||
|
"CurrencyCode": "URA",
|
||||||
|
"CurrencyName": "Galaxy Credits",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "VEN",
|
||||||
|
"CountryName": "Venus",
|
||||||
|
"CurrencyCode": "VEN",
|
||||||
|
"CurrencyName": "Venusian Seashells",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "JUP",
|
||||||
|
"CountryName": "Jupiter",
|
||||||
|
"CurrencyCode": "JUP",
|
||||||
|
"CurrencyName": "Gas Money",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "MER",
|
||||||
|
"CountryName": "Mercury",
|
||||||
|
"CurrencyCode": "MER",
|
||||||
|
"CurrencyName": "Sun Notes",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "TEST1",
|
||||||
|
"CountryName": "Test No Fractional Digits",
|
||||||
|
"CurrencyCode": "JPY",
|
||||||
|
"CurrencyName": "Test No Fractional Digits",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CountryCode": "TEST2",
|
||||||
|
"CountryName": "Test Fractional Digits",
|
||||||
|
"CurrencyCode": "JOD",
|
||||||
|
"CurrencyName": "Test Fractional Digits",
|
||||||
|
"CurrencySymbol": "¤"
|
||||||
|
}
|
||||||
|
])";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace CalculatorApp::ViewModel::DataLoaders
|
||||||
{
|
{
|
||||||
m_sourceCurrencyCode = sourceCurrencyCode;
|
bool CurrencyHttpClient::ForceWebFailure = false;
|
||||||
}
|
void CurrencyHttpClient::Initialize(Platform::String ^ sourceCurrencyCode, Platform::String ^ responseLanguage)
|
||||||
|
{
|
||||||
|
m_sourceCurrencyCode = sourceCurrencyCode;
|
||||||
|
m_responseLanguage = responseLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
void CurrencyHttpClient::SetResponseLanguage(String ^ responseLanguage)
|
MockAwaitable<Platform::String ^> CurrencyHttpClient::GetCurrencyMetadataAsync() const
|
||||||
{
|
{
|
||||||
m_responseLanguage = responseLanguage;
|
(void)m_responseLanguage; // to be used in production.
|
||||||
}
|
return MockAwaitable<Platform::String ^>{ ref new Platform::String(MockCurrencyStaticData) };
|
||||||
|
}
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyMetadata()
|
MockAwaitable<Platform::String ^> CurrencyHttpClient::GetCurrencyRatiosAsync() const
|
||||||
{
|
{
|
||||||
wstring uri = wstring{ sc_MetadataUriLocalizeFor } + m_responseLanguage->Data();
|
(void)m_sourceCurrencyCode; // to be used in production.
|
||||||
auto metadataUri = ref new Uri(StringReference(uri.c_str()));
|
return MockAwaitable<Platform::String ^>{ ref new Platform::String(MockCurrencyConverterData) };
|
||||||
|
}
|
||||||
return m_client->GetStringAsync(metadataUri);
|
} // namespace CalculatorApp::ViewModel::DataLoaders
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyRatios()
|
|
||||||
{
|
|
||||||
wstring uri = wstring{ sc_RatiosUriRelativeTo } + m_sourceCurrencyCode->Data();
|
|
||||||
auto ratiosUri = ref new Uri(StringReference(uri.c_str()));
|
|
||||||
|
|
||||||
return m_client->GetStringAsync(ratiosUri);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,29 +1,43 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "ICurrencyHttpClient.h"
|
namespace CalculatorApp::ViewModel::DataLoaders
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
{
|
||||||
namespace ViewModel::DataLoaders
|
template <class T>
|
||||||
|
struct MockAwaitable
|
||||||
{
|
{
|
||||||
class CurrencyHttpClient : public ICurrencyHttpClient
|
T Value;
|
||||||
|
|
||||||
|
bool await_ready() const noexcept
|
||||||
{
|
{
|
||||||
public:
|
return true;
|
||||||
CurrencyHttpClient();
|
}
|
||||||
|
|
||||||
void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) override;
|
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||||
void SetResponseLanguage(Platform::String ^ responseLanguage) override;
|
{
|
||||||
|
assert(false && "not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() override;
|
T await_resume() noexcept
|
||||||
Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() override;
|
{
|
||||||
|
return std::move(Value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
class CurrencyHttpClient
|
||||||
Windows::Web::Http::HttpClient ^ m_client;
|
{
|
||||||
Platform::String ^ m_responseLanguage;
|
public:
|
||||||
Platform::String ^ m_sourceCurrencyCode;
|
static bool ForceWebFailure;
|
||||||
};
|
void Initialize(Platform::String ^ sourceCurrencyCode, Platform::String ^ responseLanguage);
|
||||||
}
|
|
||||||
|
MockAwaitable<Platform::String ^> GetCurrencyMetadataAsync() const;
|
||||||
|
MockAwaitable<Platform::String ^> GetCurrencyRatiosAsync() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Platform::String ^ m_sourceCurrencyCode;
|
||||||
|
Platform::String ^ m_responseLanguage;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
namespace DataLoaders
|
|
||||||
{
|
|
||||||
static constexpr auto sc_MetadataUriLocalizeFor = L"https://go.microsoft.com/fwlink/?linkid=2091028&localizeFor=";
|
|
||||||
static constexpr auto sc_RatiosUriRelativeTo = L"https://go.microsoft.com/fwlink/?linkid=2091307&localCurrency=";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
namespace ViewModel::DataLoaders
|
|
||||||
{
|
|
||||||
class ICurrencyHttpClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ICurrencyHttpClient()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) = 0;
|
|
||||||
virtual void SetResponseLanguage(Platform::String ^ responseLanguage) = 0;
|
|
||||||
|
|
||||||
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() = 0;
|
|
||||||
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -319,8 +319,6 @@
|
||||||
<ClInclude Include="..\CalcViewModel\Common\TraceLogger.h" />
|
<ClInclude Include="..\CalcViewModel\Common\TraceLogger.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\Common\Utils.h" />
|
<ClInclude Include="..\CalcViewModel\Common\Utils.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\CurrencyDataLoader.h" />
|
<ClInclude Include="..\CalcViewModel\DataLoaders\CurrencyDataLoader.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\CurrencyHttpClient.h" />
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\ICurrencyHttpClient.h" />
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataConstants.h" />
|
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataConstants.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataLoader.h" />
|
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataLoader.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\DateCalculatorViewModel.h" />
|
<ClInclude Include="..\CalcViewModel\DateCalculatorViewModel.h" />
|
||||||
|
@ -357,7 +355,6 @@
|
||||||
<ClCompile Include="..\CalcViewModel\Common\TraceLogger.cpp" />
|
<ClCompile Include="..\CalcViewModel\Common\TraceLogger.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\Common\Utils.cpp" />
|
<ClCompile Include="..\CalcViewModel\Common\Utils.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\DataLoaders\CurrencyDataLoader.cpp" />
|
<ClCompile Include="..\CalcViewModel\DataLoaders\CurrencyDataLoader.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\DataLoaders\CurrencyHttpClient.cpp" />
|
|
||||||
<ClCompile Include="..\CalcViewModel\DataLoaders\UnitConverterDataLoader.cpp" />
|
<ClCompile Include="..\CalcViewModel\DataLoaders\UnitConverterDataLoader.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\DateCalculatorViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\DateCalculatorViewModel.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\GraphingCalculator\EquationViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\GraphingCalculator\EquationViewModel.cpp" />
|
||||||
|
@ -379,6 +376,7 @@
|
||||||
<ClCompile Include="..\CalcViewModel\Snapshots.cpp" />
|
<ClCompile Include="..\CalcViewModel\Snapshots.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\StandardCalculatorViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\StandardCalculatorViewModel.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\UnitConverterViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\UnitConverterViewModel.cpp" />
|
||||||
|
<ClCompile Include="DataLoaders\CurrencyHttpClient.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
|
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
|
||||||
|
@ -391,31 +389,6 @@
|
||||||
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
|
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemDefinitionGroup Condition="!Exists('..\CalcViewModel\DataLoaders\DataLoaderConstants.h')">
|
|
||||||
<ClCompile>
|
|
||||||
<AdditionalOptions>/DUSE_MOCK_DATA %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
|
|
||||||
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpp17</LanguageStandard>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<Choose>
|
|
||||||
<When Condition="Exists('..\CalcViewModel\DataLoaders\DataLoaderConstants.h')">
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\DataLoaderConstants.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
</When>
|
|
||||||
<Otherwise>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\DataLoaderMockConstants.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Otherwise>
|
|
||||||
</Choose>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\CalcViewModel\DataLoaders\DefaultFromToCurrency.json" />
|
<None Include="..\CalcViewModel\DataLoaders\DefaultFromToCurrency.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -177,12 +177,6 @@
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\CurrencyHttpClient.h">
|
<ClInclude Include="..\CalcViewModel\DataLoaders\CurrencyHttpClient.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\DataLoaderMockConstants.h">
|
|
||||||
<Filter>DataLoaders</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\ICurrencyHttpClient.h">
|
|
||||||
<Filter>DataLoaders</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataConstants.h">
|
<ClInclude Include="..\CalcViewModel\DataLoaders\UnitConverterDataConstants.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "DataLoaders/CurrencyHttpClient.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr auto MockCurrencyConverterData =
|
||||||
|
LR"([{"An":"USD","Ch":0,"Pc":0,"Rt":1},{"An":"EUR","Ch":0.003803,"Pc":0.4149,"Rt":0.920503,"Yh":0.9667,"Yl":0.86701}])";
|
||||||
|
constexpr auto MockCurrencyStaticData =
|
||||||
|
LR"([{"CountryCode":"USA","CountryName":"United States","CurrencyCode":"USD","CurrencyName":"Dollar","CurrencySymbol":"$"},{"CountryCode":"EUR","CountryName":"Europe","CurrencyCode":"EUR","CurrencyName":"Euro","CurrencySymbol":"€"}])";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CalculatorApp::ViewModel::DataLoaders
|
||||||
|
{
|
||||||
|
bool CurrencyHttpClient::ForceWebFailure = false;
|
||||||
|
void CurrencyHttpClient::Initialize(Platform::String ^ sourceCurrencyCode, Platform::String ^ responseLanguage)
|
||||||
|
{
|
||||||
|
m_sourceCurrencyCode = sourceCurrencyCode;
|
||||||
|
m_responseLanguage = responseLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
MockAwaitable<Platform::String ^> CurrencyHttpClient::GetCurrencyMetadataAsync() const
|
||||||
|
{
|
||||||
|
if (ForceWebFailure)
|
||||||
|
{
|
||||||
|
throw ref new Platform::Exception(E_FAIL, L"Mocked Network Failure: failed to load currency metadata");
|
||||||
|
}
|
||||||
|
(void)m_responseLanguage; // to be used in production.
|
||||||
|
return MockAwaitable<Platform::String ^>{ ref new Platform::String(MockCurrencyStaticData) };
|
||||||
|
}
|
||||||
|
|
||||||
|
MockAwaitable<Platform::String ^> CurrencyHttpClient::GetCurrencyRatiosAsync() const
|
||||||
|
{
|
||||||
|
if (ForceWebFailure)
|
||||||
|
{
|
||||||
|
throw ref new Platform::Exception(E_FAIL, L"Mocked Network Failure: failed to load currency metadata");
|
||||||
|
}
|
||||||
|
(void)m_sourceCurrencyCode; // to be used in production.
|
||||||
|
return MockAwaitable<Platform::String ^>{ ref new Platform::String(MockCurrencyConverterData) };
|
||||||
|
}
|
||||||
|
} // namespace CalculatorApp::ViewModel::DataLoaders
|
|
@ -207,7 +207,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="DateUtils.h" />
|
<ClInclude Include="DateUtils.h" />
|
||||||
<ClInclude Include="Helpers.h" />
|
<ClInclude Include="Helpers.h" />
|
||||||
<ClInclude Include="Mocks\CurrencyHttpClient.h" />
|
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
|
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
|
||||||
<ClInclude Include="UnitTestApp.xaml.h">
|
<ClInclude Include="UnitTestApp.xaml.h">
|
||||||
|
@ -243,7 +242,6 @@
|
||||||
<ClCompile Include="HistoryTests.cpp" />
|
<ClCompile Include="HistoryTests.cpp" />
|
||||||
<ClCompile Include="LocalizationServiceUnitTests.cpp" />
|
<ClCompile Include="LocalizationServiceUnitTests.cpp" />
|
||||||
<ClCompile Include="LocalizationSettingsUnitTests.cpp" />
|
<ClCompile Include="LocalizationSettingsUnitTests.cpp" />
|
||||||
<ClCompile Include="Mocks\CurrencyHttpClient.cpp" />
|
|
||||||
<ClCompile Include="MultiWindowUnitTests.cpp" />
|
<ClCompile Include="MultiWindowUnitTests.cpp" />
|
||||||
<ClCompile Include="NarratorAnnouncementUnitTests.cpp" />
|
<ClCompile Include="NarratorAnnouncementUnitTests.cpp" />
|
||||||
<ClCompile Include="NavCategoryUnitTests.cpp" />
|
<ClCompile Include="NavCategoryUnitTests.cpp" />
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
<ClCompile Include="UnitTestApp.xaml.cpp" />
|
<ClCompile Include="UnitTestApp.xaml.cpp" />
|
||||||
<ClCompile Include="pch.cpp" />
|
<ClCompile Include="pch.cpp" />
|
||||||
<ClCompile Include="UtilsTests.cpp" />
|
<ClCompile Include="UtilsTests.cpp" />
|
||||||
<ClCompile Include="Mocks\CurrencyHttpClient.cpp">
|
|
||||||
<Filter>Mocks</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="LocalizationServiceUnitTests.cpp" />
|
<ClCompile Include="LocalizationServiceUnitTests.cpp" />
|
||||||
<ClCompile Include="RationalTest.cpp" />
|
<ClCompile Include="RationalTest.cpp" />
|
||||||
<ClCompile Include="LocalizationSettingsUnitTests.cpp" />
|
<ClCompile Include="LocalizationSettingsUnitTests.cpp" />
|
||||||
|
@ -38,9 +35,6 @@
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
|
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
|
||||||
<ClInclude Include="UnitTestApp.xaml.h" />
|
<ClInclude Include="UnitTestApp.xaml.h" />
|
||||||
<ClInclude Include="Mocks\CurrencyHttpClient.h">
|
|
||||||
<Filter>Mocks</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Xml Include="UnitTestApp.rd.xml" />
|
<Xml Include="UnitTestApp.rd.xml" />
|
||||||
|
@ -75,8 +69,5 @@
|
||||||
<Filter Include="Assets">
|
<Filter Include="Assets">
|
||||||
<UniqueIdentifier>{f2987b0a-9832-46fc-b818-d5347362b3d8}</UniqueIdentifier>
|
<UniqueIdentifier>{f2987b0a-9832-46fc-b818-d5347362b3d8}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="Mocks">
|
|
||||||
<UniqueIdentifier>{d3ec8922-022d-4531-8744-f65a872f3841}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -14,61 +14,12 @@ using namespace CalculatorApp::ViewModel;
|
||||||
using namespace CalculatorUnitTests;
|
using namespace CalculatorUnitTests;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace std;
|
|
||||||
using namespace UnitConversionManager;
|
using namespace UnitConversionManager;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Storage;
|
using namespace Windows::Storage;
|
||||||
using namespace Windows::Web::Http;
|
using namespace Windows::Web::Http;
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
|
|
||||||
namespace CalculatorApp::ViewModel
|
|
||||||
{
|
|
||||||
namespace DataLoaders
|
|
||||||
{
|
|
||||||
class MockCurrencyHttpClientWithResult : public CurrencyHttpClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MockCurrencyHttpClientWithResult(String ^ staticResponse, String ^ allRatiosResponse)
|
|
||||||
: m_staticResponse(staticResponse)
|
|
||||||
, m_allRatiosResponse(allRatiosResponse)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ GetCurrencyMetadata() override
|
|
||||||
{
|
|
||||||
return ref new MockAsyncOperationWithProgress(m_staticResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ GetCurrencyRatios() override
|
|
||||||
{
|
|
||||||
return ref new MockAsyncOperationWithProgress(m_allRatiosResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
String ^ m_staticResponse;
|
|
||||||
String ^ m_allRatiosResponse;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockCurrencyHttpClientThrowsException : public CurrencyHttpClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MockCurrencyHttpClientThrowsException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ GetCurrencyMetadata() override
|
|
||||||
{
|
|
||||||
throw ref new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ GetCurrencyRatios() override
|
|
||||||
{
|
|
||||||
throw ref new NotImplementedException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataLoadedCallback : public UnitConversionManager::IViewModelCurrencyCallback
|
class DataLoadedCallback : public UnitConversionManager::IViewModelCurrencyCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -82,10 +33,10 @@ public:
|
||||||
m_task_completion_event.set();
|
m_task_completion_event.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CurrencySymbolsCallback(_In_ const wstring& /*fromSymbol*/, _In_ const wstring& /*toSymbol*/) override
|
void CurrencySymbolsCallback(_In_ const std::wstring& /*fromSymbol*/, _In_ const std::wstring& /*toSymbol*/) override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void CurrencyRatiosCallback(_In_ const wstring& /*ratioEquality*/, _In_ const wstring& /*accRatioEquality*/) override
|
void CurrencyRatiosCallback(_In_ const std::wstring& /*ratioEquality*/, _In_ const std::wstring& /*accRatioEquality*/) override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void CurrencyTimestampCallback(_In_ const std::wstring& /*timestamp*/, bool /*isWeekOldData*/) override
|
void CurrencyTimestampCallback(_In_ const std::wstring& /*timestamp*/, bool /*isWeekOldData*/) override
|
||||||
|
@ -101,16 +52,32 @@ private:
|
||||||
|
|
||||||
namespace CalculatorUnitTests
|
namespace CalculatorUnitTests
|
||||||
{
|
{
|
||||||
constexpr auto sc_Language_EN = L"en-US";
|
namespace
|
||||||
|
|
||||||
unique_ptr<CurrencyDataLoader> MakeLoaderWithResults(String ^ staticResponse, String ^ allRatiosResponse)
|
|
||||||
{
|
{
|
||||||
auto client = make_unique<MockCurrencyHttpClientWithResult>(staticResponse, allRatiosResponse);
|
template <class F>
|
||||||
client->SetSourceCurrencyCode(StringReference(DefaultCurrencyCode.data()));
|
auto ScopeGuard(F&& f)
|
||||||
return make_unique<CurrencyDataLoader>(move(client));
|
{
|
||||||
|
struct ScopeExit
|
||||||
|
{
|
||||||
|
explicit ScopeExit(F&& ef)
|
||||||
|
: ExitFunctor(std::forward<F>(ef))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ScopeExit(const ScopeExit&) = delete;
|
||||||
|
ScopeExit(ScopeExit&&) = delete;
|
||||||
|
~ScopeExit()
|
||||||
|
{
|
||||||
|
ExitFunctor();
|
||||||
|
}
|
||||||
|
F ExitFunctor;
|
||||||
|
};
|
||||||
|
return ScopeExit{ std::forward<F>(f) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String^ SerializeContent(const vector<String^>& data)
|
constexpr auto sc_Language_EN = L"en-US";
|
||||||
|
|
||||||
|
String^ SerializeContent(const std::vector<String^>& data)
|
||||||
{
|
{
|
||||||
String^ result = L"";
|
String^ result = L"";
|
||||||
String^ delimiter = CurrencyDataLoaderConstants::CacheDelimiter;
|
String^ delimiter = CurrencyDataLoaderConstants::CacheDelimiter;
|
||||||
|
@ -193,8 +160,8 @@ namespace CalculatorUnitTests
|
||||||
|
|
||||||
VERIFY_IS_TRUE(DeleteCurrencyCacheFiles());
|
VERIFY_IS_TRUE(DeleteCurrencyCacheFiles());
|
||||||
|
|
||||||
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
|
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient{}.GetCurrencyMetadataAsync().Value));
|
||||||
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
|
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient{}.GetCurrencyRatiosAsync().Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CLASS(CurrencyConverterLoadTests){ public: TEST_METHOD_INITIALIZE(DeleteCacheFiles){ DeleteCurrencyCacheFiles();
|
TEST_CLASS(CurrencyConverterLoadTests){ public: TEST_METHOD_INITIALIZE(DeleteCacheFiles){ DeleteCurrencyCacheFiles();
|
||||||
|
@ -203,7 +170,7 @@ namespace CalculatorUnitTests
|
||||||
TEST_METHOD(LoadFromCache_Fail_NoCacheKey)
|
TEST_METHOD(LoadFromCache_Fail_NoCacheKey)
|
||||||
{
|
{
|
||||||
RemoveFromLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey);
|
RemoveFromLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey);
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -221,7 +188,9 @@ TEST_METHOD(LoadFromCache_Fail_OlderThanADay)
|
||||||
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
|
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
|
||||||
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
|
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
auto guard = ScopeGuard([] { CurrencyHttpClient::ForceWebFailure = false; });
|
||||||
|
CurrencyHttpClient::ForceWebFailure = true;
|
||||||
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -238,9 +207,9 @@ TEST_METHOD(LoadFromCache_Fail_StaticDataFileDoesNotExist)
|
||||||
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
|
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
|
||||||
|
|
||||||
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename));
|
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename));
|
||||||
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
|
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient{}.GetCurrencyRatiosAsync().Value));
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -256,10 +225,10 @@ TEST_METHOD(LoadFromCache_Fail_AllRatiosDataFileDoesNotExist)
|
||||||
DateTime now = Utils::GetUniversalSystemTime();
|
DateTime now = Utils::GetUniversalSystemTime();
|
||||||
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
|
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
|
||||||
|
|
||||||
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
|
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient{}.GetCurrencyMetadataAsync().Value));
|
||||||
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
|
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -276,10 +245,10 @@ TEST_METHOD(LoadFromCache_Fail_ResponseLanguageChanged)
|
||||||
// Tests always use en-US as response language. Insert a different lang-code to fail the test.
|
// Tests always use en-US as response language. Insert a different lang-code to fail the test.
|
||||||
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, L"ar-SA");
|
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, L"ar-SA");
|
||||||
|
|
||||||
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
|
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient{}.GetCurrencyMetadataAsync().Value));
|
||||||
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
|
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -292,7 +261,7 @@ TEST_METHOD(LoadFromCache_Success)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
|
||||||
|
|
||||||
|
@ -301,20 +270,11 @@ TEST_METHOD(LoadFromCache_Success)
|
||||||
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(LoadFromWeb_Fail_ClientIsNullptr)
|
|
||||||
{
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromWebAsync().get();
|
|
||||||
|
|
||||||
VERIFY_IS_FALSE(didLoad);
|
|
||||||
VERIFY_IS_FALSE(loader.LoadFinished());
|
|
||||||
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD(LoadFromWeb_Fail_WebException)
|
TEST_METHOD(LoadFromWeb_Fail_WebException)
|
||||||
{
|
{
|
||||||
CurrencyDataLoader loader(make_unique<MockCurrencyHttpClientThrowsException>(), L"en-US");
|
auto guard = ScopeGuard([] { CurrencyHttpClient::ForceWebFailure = false; });
|
||||||
|
CurrencyHttpClient::ForceWebFailure = true;
|
||||||
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
bool didLoad = loader.TryLoadDataFromWebAsync().get();
|
bool didLoad = loader.TryLoadDataFromWebAsync().get();
|
||||||
|
|
||||||
|
@ -325,24 +285,22 @@ TEST_METHOD(LoadFromWeb_Fail_WebException)
|
||||||
|
|
||||||
TEST_METHOD(LoadFromWeb_Success)
|
TEST_METHOD(LoadFromWeb_Success)
|
||||||
{
|
{
|
||||||
String ^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
String ^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
|
|
||||||
unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
|
|
||||||
|
|
||||||
bool didLoad = loader->TryLoadDataFromWebAsync().get();
|
bool didLoad = loader.TryLoadDataFromWebAsync().get();
|
||||||
|
|
||||||
VERIFY_IS_TRUE(didLoad);
|
VERIFY_IS_TRUE(didLoad);
|
||||||
VERIFY_IS_TRUE(loader->LoadFinished());
|
VERIFY_IS_TRUE(loader.LoadFinished());
|
||||||
VERIFY_IS_TRUE(loader->LoadedFromWeb());
|
VERIFY_IS_TRUE(loader.LoadedFromWeb());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Load_Success_LoadedFromCache)
|
TEST_METHOD(Load_Success_LoadedFromCache)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -362,20 +320,18 @@ TEST_METHOD(Load_Success_LoadedFromWeb)
|
||||||
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
|
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
|
||||||
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
|
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
|
||||||
|
|
||||||
String ^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
String ^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
|
|
||||||
unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
|
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader->SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader->LoadData();
|
loader.LoadData();
|
||||||
data_loaded_task.wait();
|
data_loaded_task.wait();
|
||||||
|
|
||||||
VERIFY_IS_TRUE(loader->LoadFinished());
|
VERIFY_IS_TRUE(loader.LoadFinished());
|
||||||
VERIFY_IS_FALSE(loader->LoadedFromCache());
|
VERIFY_IS_FALSE(loader.LoadedFromCache());
|
||||||
VERIFY_IS_TRUE(loader->LoadedFromWeb());
|
VERIFY_IS_TRUE(loader.LoadedFromWeb());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -384,18 +340,18 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
{
|
{
|
||||||
const UCM::Category CURRENCY_CATEGORY = { NavCategoryStates::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
|
const UCM::Category CURRENCY_CATEGORY = { NavCategoryStates::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
|
||||||
|
|
||||||
const UCM::Unit GetUnit(const vector<UCM::Unit>& unitList, const wstring& target)
|
const UCM::Unit GetUnit(const std::vector<UCM::Unit>& unitList, const std::wstring& target)
|
||||||
{
|
{
|
||||||
return *find_if(begin(unitList), end(unitList), [&target](const UCM::Unit& u) { return u.abbreviation == target; });
|
return *std::find_if(std::begin(unitList), std::end(unitList), [&target](const UCM::Unit& u) { return u.abbreviation == target; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Loaded_LoadOrderedUnits)
|
TEST_METHOD(Loaded_LoadOrderedUnits)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -405,27 +361,27 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
||||||
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
||||||
|
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L"United States - Dollar"), usdUnit.name);
|
VERIFY_ARE_EQUAL(std::wstring(L"United States - Dollar"), usdUnit.name);
|
||||||
VERIFY_ARE_EQUAL(wstring(L"USD"), usdUnit.abbreviation);
|
VERIFY_ARE_EQUAL(std::wstring(L"USD"), usdUnit.abbreviation);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L"Europe - Euro"), eurUnit.name);
|
VERIFY_ARE_EQUAL(std::wstring(L"Europe - Euro"), eurUnit.name);
|
||||||
VERIFY_ARE_EQUAL(wstring(L"EUR"), eurUnit.abbreviation);
|
VERIFY_ARE_EQUAL(std::wstring(L"EUR"), eurUnit.abbreviation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Loaded_LoadOrderedRatios)
|
TEST_METHOD(Loaded_LoadOrderedRatios)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -435,13 +391,13 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
||||||
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
||||||
|
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
||||||
|
|
||||||
unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> ratios = loader.LoadOrderedRatios(usdUnit);
|
std::unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> ratios = loader.LoadOrderedRatios(usdUnit);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, ratios.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, ratios.size());
|
||||||
|
|
||||||
UCM::ConversionData usdRatioData = ratios[usdUnit];
|
UCM::ConversionData usdRatioData = ratios[usdUnit];
|
||||||
|
@ -455,10 +411,10 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -468,26 +424,26 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
||||||
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
||||||
|
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
||||||
|
|
||||||
const pair<wstring, wstring> symbols = loader.GetCurrencySymbols(usdUnit, eurUnit);
|
const auto symbols = loader.GetCurrencySymbols(usdUnit, eurUnit);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L"$"), symbols.first);
|
VERIFY_ARE_EQUAL(std::wstring(L"$"), symbols.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L"\x20ac"), symbols.second); // €
|
VERIFY_ARE_EQUAL(std::wstring(L"\x20ac"), symbols.second); // €
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Loaded_GetCurrencySymbols_Invalid)
|
TEST_METHOD(Loaded_GetCurrencySymbols_Invalid)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -501,36 +457,36 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
|
|
||||||
const UCM::Unit fakeUnit2 = { 2, L"fakeUnit2", L"FUD2", false, false, false };
|
const UCM::Unit fakeUnit2 = { 2, L"fakeUnit2", L"FUD2", false, false, false };
|
||||||
|
|
||||||
pair<wstring, wstring> symbols = loader.GetCurrencySymbols(fakeUnit1, fakeUnit2);
|
auto symbols = loader.GetCurrencySymbols(fakeUnit1, fakeUnit2);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), wstring(symbols.first.c_str()));
|
VERIFY_ARE_EQUAL(std::wstring(L""), std::wstring(symbols.first.c_str()));
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), wstring(symbols.second.c_str()));
|
VERIFY_ARE_EQUAL(std::wstring(L""), std::wstring(symbols.second.c_str()));
|
||||||
|
|
||||||
// Verify that when only one unit is valid, both symbols return as empty string.
|
// Verify that when only one unit is valid, both symbols return as empty string.
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
|
|
||||||
symbols = loader.GetCurrencySymbols(fakeUnit1, usdUnit);
|
symbols = loader.GetCurrencySymbols(fakeUnit1, usdUnit);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), symbols.first);
|
VERIFY_ARE_EQUAL(std::wstring(L""), symbols.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), symbols.second);
|
VERIFY_ARE_EQUAL(std::wstring(L""), symbols.second);
|
||||||
|
|
||||||
symbols = loader.GetCurrencySymbols(usdUnit, fakeUnit1);
|
symbols = loader.GetCurrencySymbols(usdUnit, fakeUnit1);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), symbols.first);
|
VERIFY_ARE_EQUAL(std::wstring(L""), symbols.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), symbols.second);
|
VERIFY_ARE_EQUAL(std::wstring(L""), symbols.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Valid)
|
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Valid)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -540,26 +496,26 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
VERIFY_IS_TRUE(loader.LoadedFromCache());
|
||||||
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
VERIFY_IS_FALSE(loader.LoadedFromWeb());
|
||||||
|
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
|
||||||
|
|
||||||
const pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(usdUnit, eurUnit);
|
const auto ratio = loader.GetCurrencyRatioEquality(usdUnit, eurUnit);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L"1 USD = 0.9205 EUR"), ratio.first);
|
VERIFY_ARE_EQUAL(std::wstring(L"1 USD = 0.9205 EUR"), ratio.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L"1 United States Dollar = 0.9205 Europe Euro"), ratio.second);
|
VERIFY_ARE_EQUAL(std::wstring(L"1 United States Dollar = 0.9205 Europe Euro"), ratio.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Invalid)
|
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Invalid)
|
||||||
{
|
{
|
||||||
StandardCacheSetup();
|
StandardCacheSetup();
|
||||||
|
|
||||||
CurrencyDataLoader loader(nullptr, L"en-US");
|
CurrencyDataLoader loader{ L"en-US" };
|
||||||
|
|
||||||
auto data_loaded_event = task_completion_event<void>();
|
auto data_loaded_event = task_completion_event<void>();
|
||||||
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
|
loader.SetViewModelCallback(std::make_shared<DataLoadedCallback>(data_loaded_event));
|
||||||
|
|
||||||
auto data_loaded_task = create_task(data_loaded_event);
|
auto data_loaded_task = create_task(data_loaded_event);
|
||||||
loader.LoadData();
|
loader.LoadData();
|
||||||
|
@ -572,26 +528,26 @@ TEST_CLASS(CurrencyConverterUnitTests)
|
||||||
const UCM::Unit fakeUnit1 = { 1, L"fakeUnit1", L"fakeCountry1", L"FUD1", false, false, false };
|
const UCM::Unit fakeUnit1 = { 1, L"fakeUnit1", L"fakeCountry1", L"FUD1", false, false, false };
|
||||||
const UCM::Unit fakeUnit2 = { 2, L"fakeUnit2", L"fakeCountry2", L"FUD2", false, false, false };
|
const UCM::Unit fakeUnit2 = { 2, L"fakeUnit2", L"fakeCountry2", L"FUD2", false, false, false };
|
||||||
|
|
||||||
pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(fakeUnit1, fakeUnit2);
|
auto ratio = loader.GetCurrencyRatioEquality(fakeUnit1, fakeUnit2);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.second);
|
||||||
|
|
||||||
// Verify that when only one unit is valid, both symbols return as empty string.
|
// Verify that when only one unit is valid, both symbols return as empty string.
|
||||||
vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
std::vector<UCM::Unit> unitList = loader.GetOrderedUnits(CURRENCY_CATEGORY);
|
||||||
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
|
||||||
|
|
||||||
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
|
||||||
|
|
||||||
ratio = loader.GetCurrencyRatioEquality(fakeUnit1, usdUnit);
|
ratio = loader.GetCurrencyRatioEquality(fakeUnit1, usdUnit);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.second);
|
||||||
|
|
||||||
ratio = loader.GetCurrencyRatioEquality(usdUnit, fakeUnit1);
|
ratio = loader.GetCurrencyRatioEquality(usdUnit, fakeUnit1);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.first);
|
||||||
VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
|
VERIFY_ARE_EQUAL(std::wstring(L""), ratio.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD(Test_RoundCurrencyRatio)
|
TEST_METHOD(Test_RoundCurrencyRatio)
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#include "pch.h"
|
|
||||||
#include "CurrencyHttpClient.h"
|
|
||||||
|
|
||||||
#include "CalcViewModel/Common/NetworkManager.h"
|
|
||||||
|
|
||||||
using namespace CalculatorApp::ViewModel::DataLoaders;
|
|
||||||
using namespace Platform;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
using namespace Windows::System::UserProfile;
|
|
||||||
using namespace Windows::Web::Http;
|
|
||||||
|
|
||||||
// Generic responses so unit tests will pass.
|
|
||||||
static constexpr auto STATIC_DATA_RESPONSE =
|
|
||||||
LR"([{"CountryCode":"USA","CountryName":"United States","CurrencyCode":"USD","CurrencyName":"Dollar","CurrencySymbol":"$"},{"CountryCode":"EUR","CountryName":"Europe","CurrencyCode":"EUR","CurrencyName":"Euro","CurrencySymbol":"€"}])";
|
|
||||||
static constexpr auto ALL_RATIOS_RESPONSE =
|
|
||||||
LR"([{"An":"USD","Ch":0,"Pc":0,"Rt":1},{"An":"EUR","Ch":0.003803,"Pc":0.4149,"Rt":0.920503,"Yh":0.9667,"Yl":0.86701}])";
|
|
||||||
|
|
||||||
CurrencyHttpClient::CurrencyHttpClient()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
String ^ CurrencyHttpClient::GetRawStaticDataResponse()
|
|
||||||
{
|
|
||||||
return StringReference(STATIC_DATA_RESPONSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
String ^ CurrencyHttpClient::GetRawAllRatiosDataResponse()
|
|
||||||
{
|
|
||||||
return StringReference(ALL_RATIOS_RESPONSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyMetadata()
|
|
||||||
{
|
|
||||||
return ref new MockAsyncOperationWithProgress(StringReference(STATIC_DATA_RESPONSE));
|
|
||||||
}
|
|
||||||
|
|
||||||
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyRatios()
|
|
||||||
{
|
|
||||||
return ref new MockAsyncOperationWithProgress(StringReference(ALL_RATIOS_RESPONSE));
|
|
||||||
}
|
|
||||||
|
|
||||||
MockAsyncOperationWithProgress::MockAsyncOperationWithProgress(String ^ result)
|
|
||||||
: m_result(result)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HResult MockAsyncOperationWithProgress::ErrorCode::get()
|
|
||||||
{
|
|
||||||
HResult okayResult;
|
|
||||||
okayResult.Value = S_OK;
|
|
||||||
return okayResult;
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CalcViewModel/DataLoaders/ICurrencyHttpClient.h"
|
|
||||||
|
|
||||||
namespace CalculatorApp::ViewModel
|
|
||||||
{
|
|
||||||
namespace DataLoaders
|
|
||||||
{
|
|
||||||
class CurrencyHttpClient : public ICurrencyHttpClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CurrencyHttpClient();
|
|
||||||
|
|
||||||
static Platform::String ^ GetRawStaticDataResponse();
|
|
||||||
static Platform::String ^ GetRawAllRatiosDataResponse();
|
|
||||||
|
|
||||||
// ICurrencyHttpClient
|
|
||||||
void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void SetResponseLanguage(Platform::String ^ responseLanguage) override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() override;
|
|
||||||
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() override;
|
|
||||||
// ICurrencyHttpClient
|
|
||||||
};
|
|
||||||
|
|
||||||
public
|
|
||||||
ref class MockAsyncOperationWithProgress sealed
|
|
||||||
: public Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MockAsyncOperationWithProgress(Platform::String ^ result);
|
|
||||||
|
|
||||||
// IAsyncInfo
|
|
||||||
virtual property Windows::Foundation::HResult ErrorCode
|
|
||||||
{
|
|
||||||
Windows::Foundation::HResult get();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual property unsigned int Id
|
|
||||||
{
|
|
||||||
unsigned int get()
|
|
||||||
{
|
|
||||||
return 128u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual property Windows::Foundation::AsyncStatus Status
|
|
||||||
{
|
|
||||||
Windows::Foundation::AsyncStatus get()
|
|
||||||
{
|
|
||||||
return Windows::Foundation::AsyncStatus::Completed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Cancel()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
// IAsyncInfo
|
|
||||||
|
|
||||||
// IAsyncOperationWithProgress
|
|
||||||
virtual property Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ Progress
|
|
||||||
{
|
|
||||||
Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ get() { return nullptr; }
|
|
||||||
void set(Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ handler) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual property Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ Completed
|
|
||||||
{
|
|
||||||
Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ get() { return nullptr; }
|
|
||||||
void set(Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ handler) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Platform::String^ GetResults() { return m_result; }
|
|
||||||
// IAsyncOperationWithProgress
|
|
||||||
|
|
||||||
private:
|
|
||||||
Platform::String^ m_result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -62,7 +62,6 @@
|
||||||
#include "CalcViewModel/Common/CalculatorButtonUser.h"
|
#include "CalcViewModel/Common/CalculatorButtonUser.h"
|
||||||
#include "CalcViewModel/Common/NetworkManager.h"
|
#include "CalcViewModel/Common/NetworkManager.h"
|
||||||
|
|
||||||
#include "Mocks/CurrencyHttpClient.h"
|
|
||||||
#include "Helpers.h"
|
#include "Helpers.h"
|
||||||
|
|
||||||
#include "UnitTestApp.xaml.h"
|
#include "UnitTestApp.xaml.h"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue