Merge remote-tracking branch 'upstream/master' into Fix245

This commit is contained in:
Rudy Huyn 2019-03-18 16:55:59 -07:00
commit 55c860361a
11 changed files with 504 additions and 441 deletions

View file

@ -416,34 +416,36 @@ int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>
// To Update the operands in the Expression according to the current Radix // To Update the operands in the Expression according to the current Radix
void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision) void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision)
{ {
if (m_spTokens != nullptr) if (m_spTokens == nullptr)
{ {
unsigned int size; return;
IFT(m_spTokens->GetSize(&size)); }
for (unsigned int i = 0; i < size; ++i) unsigned int size;
IFT(m_spTokens->GetSize(&size));
for (unsigned int i = 0; i < size; ++i)
{
std::pair<std::wstring, int> token;
IFT(m_spTokens->GetAt(i, &token));
int commandPosition = token.second;
if (commandPosition != -1)
{ {
std::pair<std::wstring, int> token; std::shared_ptr<IExpressionCommand> expCommand;
IFT(m_spTokens->GetAt(i, &token)); IFT(m_spCommands->GetAt(commandPosition, &expCommand));
int commandPosition = token.second; if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
if (commandPosition != -1)
{ {
std::shared_ptr<IExpressionCommand> expCommand; std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand);
IFT(m_spCommands->GetAt(commandPosition, &expCommand)); if (opndCommand != nullptr)
if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
{ {
std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand); token.first = opndCommand->GetString(radix, precision);
if (opndCommand != nullptr) IFT(m_spTokens->SetAt(i, token));
{ opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
token.first = opndCommand->GetString(radix, precision);
IFT(m_spTokens->SetAt(i, token));
opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
}
} }
} }
} }
SetExpressionDisplay();
} }
SetExpressionDisplay();
} }
void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol) void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)

View file

@ -490,22 +490,25 @@ namespace CalculationManager
void CalculatorManager::MemorizeNumber() void CalculatorManager::MemorizeNumber()
{ {
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber)); m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber));
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
m_currentCalculatorEngine->ProcessCommand(IDC_STORE); return;
auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObjectPtr != nullptr)
{
m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr);
}
if (m_memorizedNumbers.size() > m_maximumMemorySize)
{
m_memorizedNumbers.resize(m_maximumMemorySize);
}
this->SetMemorizedNumbersString();
} }
m_currentCalculatorEngine->ProcessCommand(IDC_STORE);
auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObjectPtr != nullptr)
{
m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr);
}
if (m_memorizedNumbers.size() > m_maximumMemorySize)
{
m_memorizedNumbers.resize(m_maximumMemorySize);
}
this->SetMemorizedNumbersString();
} }
/// <summary> /// <summary>
@ -516,11 +519,14 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
this->MemorizedNumberSelect(indexOfMemory); return;
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
} }
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
} }
/// <summary> /// <summary>
@ -532,24 +538,27 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
if (m_memorizedNumbers.empty()) return;
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory)
@ -570,27 +579,30 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
// To add negative of the number on display to the memory -x = x - 2x return;
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
this->MemorizedNumberSubtract(0);
this->MemorizedNumberSubtract(0);
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
// To add negative of the number on display to the memory -x = x - 2x
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
this->MemorizedNumberSubtract(0);
this->MemorizedNumberSubtract(0);
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
/// <summary> /// <summary>
@ -613,11 +625,13 @@ namespace CalculationManager
/// <param name="indexOfMemory">Index of the target memory</param> /// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory)
{ {
if (!(m_currentCalculatorEngine->FInErrorState())) if (m_currentCalculatorEngine->FInErrorState())
{ {
auto memoryObject = m_memorizedNumbers.at(indexOfMemory); return;
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
} }
auto memoryObject = m_memorizedNumbers.at(indexOfMemory);
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
} }
/// <summary> /// <summary>
@ -627,13 +641,15 @@ namespace CalculationManager
/// <param name="indexOfMemory">Index of the target memory</param> /// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory)
{ {
if (!(m_currentCalculatorEngine->FInErrorState())) if (m_currentCalculatorEngine->FInErrorState())
{ {
auto memoryObject = m_currentCalculatorEngine->PersistedMemObject(); return;
if (memoryObject != nullptr) }
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject; auto memoryObject = m_currentCalculatorEngine->PersistedMemObject();
} if (memoryObject != nullptr)
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject;
} }
} }

View file

@ -612,6 +612,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis
break; break;
} }
// Drop through in the 'e'-as-a-digit case // Drop through in the 'e'-as-a-digit case
[[fallthrough]];
default: default:
state = machine[state][NZ]; state = machine[state][NZ];
break; break;
@ -646,7 +647,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis
break; break;
case LD: case LD:
pnumret->exp++; pnumret->exp++;
// Fall through [[fallthrough]];
case DD: case DD:
{ {
curChar = NormalizeCharDigit(curChar, radix); curChar = NormalizeCharDigit(curChar, radix);

View file

@ -109,22 +109,8 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i
vector<Unit>& unitVector = m_categoryToUnits[m_currentCategory]; vector<Unit>& unitVector = m_categoryToUnits[m_currentCategory];
for (unsigned int i = 0; i < unitVector.size(); i++) for (unsigned int i = 0; i < unitVector.size(); i++)
{ {
if (unitVector[i].id == m_fromType.id) unitVector[i].isConversionSource = (unitVector[i].id == m_fromType.id);
{ unitVector[i].isConversionTarget = (unitVector[i].id == m_toType.id);
unitVector[i].isConversionSource = true;
}
else
{
unitVector[i].isConversionSource = false;
}
if (unitVector[i].id == m_toType.id)
{
unitVector[i].isConversionTarget = true;
}
else
{
unitVector[i].isConversionTarget = false;
}
} }
m_currentCategory = input; m_currentCategory = input;
if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-') if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-')
@ -156,15 +142,17 @@ Category UnitConverter::GetCurrentCategory()
/// <param name="toType">Unit struct we are converting to</param> /// <param name="toType">Unit struct we are converting to</param>
void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
m_fromType = fromType; return;
m_toType = toType;
Calculate();
UpdateCurrencySymbols();
UpdateViewModel();
} }
m_fromType = fromType;
m_toType = toType;
Calculate();
UpdateCurrencySymbols();
UpdateViewModel();
} }
/// <summary> /// <summary>
@ -181,22 +169,24 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType
/// </param> /// </param>
void UnitConverter::SwitchActive(const wstring& newValue) void UnitConverter::SwitchActive(const wstring& newValue)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
swap(m_fromType, m_toType); return;
swap(m_currentHasDecimal, m_returnHasDecimal); }
m_returnDisplay = m_currentDisplay;
m_currentDisplay = newValue;
m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos);
m_switchedActive = true;
if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr) swap(m_fromType, m_toType);
{ swap(m_currentHasDecimal, m_returnHasDecimal);
shared_ptr<ICurrencyConverterDataLoader> currencyDataLoader = GetCurrencyConverterDataLoader(); m_returnDisplay = m_currentDisplay;
const pair<wstring, wstring> currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType); m_currentDisplay = newValue;
m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos);
m_switchedActive = true;
m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second); if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr)
} {
shared_ptr<ICurrencyConverterDataLoader> currencyDataLoader = GetCurrencyConverterDataLoader();
const pair<wstring, wstring> currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType);
m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second);
} }
} }
@ -291,55 +281,53 @@ wstring UnitConverter::ConversionDataToString(ConversionData d, const wchar_t *
/// </summary> /// </summary>
wstring UnitConverter::Serialize() wstring UnitConverter::Serialize()
{ {
if (CheckLoad()) if (!CheckLoad())
{
wstringstream out(wstringstream::out);
const wchar_t * delimiter = L";";
out << UnitToString(m_fromType, delimiter) << "|";
out << UnitToString(m_toType, delimiter) << "|";
out << CategoryToString(m_currentCategory, delimiter) << "|";
out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter;
out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|";
wstringstream categoryString(wstringstream::out);
wstringstream categoryToUnitString(wstringstream::out);
wstringstream unitToUnitToDoubleString(wstringstream::out);
for (const Category& c : m_categories)
{
categoryString << CategoryToString(c, delimiter) << ",";
}
for (const auto& cur : m_categoryToUnits)
{
categoryToUnitString << CategoryToString(cur.first, delimiter) << "[";
for (const Unit& u : cur.second)
{
categoryToUnitString << UnitToString(u, delimiter) << ",";
}
categoryToUnitString << "[" << "]";
}
for (const auto& cur : m_ratioMap)
{
unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "[";
for (const auto& curConversion : cur.second)
{
unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":";
unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,";
}
unitToUnitToDoubleString << "[" << "]";
}
out << categoryString.str() << "|";
out << categoryToUnitString.str() << "|";
out << unitToUnitToDoubleString.str() << "|";
wstring test = out.str();
return test;
}
else
{ {
return wstring(); return wstring();
} }
wstringstream out(wstringstream::out);
const wchar_t * delimiter = L";";
out << UnitToString(m_fromType, delimiter) << "|";
out << UnitToString(m_toType, delimiter) << "|";
out << CategoryToString(m_currentCategory, delimiter) << "|";
out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter;
out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|";
wstringstream categoryString(wstringstream::out);
wstringstream categoryToUnitString(wstringstream::out);
wstringstream unitToUnitToDoubleString(wstringstream::out);
for (const Category& c : m_categories)
{
categoryString << CategoryToString(c, delimiter) << ",";
}
for (const auto& cur : m_categoryToUnits)
{
categoryToUnitString << CategoryToString(cur.first, delimiter) << "[";
for (const Unit& u : cur.second)
{
categoryToUnitString << UnitToString(u, delimiter) << ",";
}
categoryToUnitString << "[" << "]";
}
for (const auto& cur : m_ratioMap)
{
unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "[";
for (const auto& curConversion : cur.second)
{
unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":";
unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,";
}
unitToUnitToDoubleString << "[" << "]";
}
out << categoryString.str() << "|";
out << categoryToUnitString.str() << "|";
out << unitToUnitToDoubleString.str() << "|";
wstring test = out.str();
return test;
} }
/// <summary> /// <summary>
@ -349,55 +337,58 @@ wstring UnitConverter::Serialize()
void UnitConverter::DeSerialize(const wstring& serializedData) void UnitConverter::DeSerialize(const wstring& serializedData)
{ {
Reset(); Reset();
if (!serializedData.empty())
if (serializedData.empty())
{ {
vector<wstring> outerTokens = StringToVector(serializedData, L"|"); return;
assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT);
m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
vector<wstring> stateDataTokens = StringToVector(outerTokens[3], L";");
assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT);
m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0);
m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0);
m_switchedActive = (stateDataTokens[2].compare(L"1") == 0);
m_currentDisplay = stateDataTokens[3];
m_returnDisplay = stateDataTokens[4];
vector<wstring> categoryListTokens = StringToVector(outerTokens[4], L",");
for (wstring token : categoryListTokens)
{
m_categories.push_back(StringToCategory(token));
}
vector<wstring> unitVectorTokens = StringToVector(outerTokens[5], L"]");
for (wstring unitVector : unitVectorTokens)
{
vector<wstring> mapcomponents = StringToVector(unitVector, L"[");
assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Category key = StringToCategory(mapcomponents[0]);
vector<wstring> units = StringToVector(mapcomponents[1], L",");
for (wstring unit : units)
{
m_categoryToUnits[key].push_back(StringToUnit(unit));
}
}
vector<wstring> ratioMapTokens = StringToVector(outerTokens[6], L"]");
for (wstring token : ratioMapTokens)
{
vector<wstring> ratioMapComponentTokens = StringToVector(token, L"[");
assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit key = StringToUnit(ratioMapComponentTokens[0]);
vector<wstring> ratioMapList = StringToVector(ratioMapComponentTokens[1], L",");
for (wstring subtoken : ratioMapList)
{
vector<wstring> ratioMapSubComponentTokens = StringToVector(subtoken, L":");
assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]);
ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]);
m_ratioMap[key][subkey] = conversion;
}
}
UpdateViewModel();
} }
vector<wstring> outerTokens = StringToVector(serializedData, L"|");
assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT);
m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
vector<wstring> stateDataTokens = StringToVector(outerTokens[3], L";");
assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT);
m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0);
m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0);
m_switchedActive = (stateDataTokens[2].compare(L"1") == 0);
m_currentDisplay = stateDataTokens[3];
m_returnDisplay = stateDataTokens[4];
vector<wstring> categoryListTokens = StringToVector(outerTokens[4], L",");
for (wstring token : categoryListTokens)
{
m_categories.push_back(StringToCategory(token));
}
vector<wstring> unitVectorTokens = StringToVector(outerTokens[5], L"]");
for (wstring unitVector : unitVectorTokens)
{
vector<wstring> mapcomponents = StringToVector(unitVector, L"[");
assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Category key = StringToCategory(mapcomponents[0]);
vector<wstring> units = StringToVector(mapcomponents[1], L",");
for (wstring unit : units)
{
m_categoryToUnits[key].push_back(StringToUnit(unit));
}
}
vector<wstring> ratioMapTokens = StringToVector(outerTokens[6], L"]");
for (wstring token : ratioMapTokens)
{
vector<wstring> ratioMapComponentTokens = StringToVector(token, L"[");
assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit key = StringToUnit(ratioMapComponentTokens[0]);
vector<wstring> ratioMapList = StringToVector(ratioMapComponentTokens[1], L",");
for (wstring subtoken : ratioMapList)
{
vector<wstring> ratioMapSubComponentTokens = StringToVector(subtoken, L":");
assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]);
ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]);
m_ratioMap[key][subkey] = conversion;
}
}
UpdateViewModel();
} }
/// <summary> /// <summary>
@ -406,15 +397,17 @@ void UnitConverter::DeSerialize(const wstring& serializedData)
/// <param name="userPreferences">wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it</param> /// <param name="userPreferences">wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it</param>
void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) void UnitConverter::RestoreUserPreferences(const wstring& userPreferences)
{ {
if (!userPreferences.empty()) if (userPreferences.empty())
{ {
vector<wstring> outerTokens = StringToVector(userPreferences, L"|"); return;
if (outerTokens.size() == 3) }
{
m_fromType = StringToUnit(outerTokens[0]); vector<wstring> outerTokens = StringToVector(userPreferences, L"|");
m_toType = StringToUnit(outerTokens[1]); if (outerTokens.size() == 3)
m_currentCategory = StringToCategory(outerTokens[2]); {
} m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
} }
} }
@ -503,144 +496,146 @@ wstring UnitConverter::Unquote(const wstring& s)
/// <param name="command">Command enum representing the command that was entered</param> /// <param name="command">Command enum representing the command that was entered</param>
void UnitConverter::SendCommand(Command command) void UnitConverter::SendCommand(Command command)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
// TODO: Localization of characters return;
bool clearFront = false; }
if (m_currentDisplay == L"0")
// TODO: Localization of characters
bool clearFront = false;
if (m_currentDisplay == L"0")
{
clearFront = true;
}
bool clearBack = false;
if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED))
{
clearBack = true;
}
if (command != Command::Negate && m_switchedActive)
{
ClearValues();
m_switchedActive = false;
clearFront = true;
clearBack = false;
}
switch (command)
{
case Command::Zero:
m_currentDisplay += L"0";
break;
case Command::One:
m_currentDisplay += L"1";
break;
case Command::Two:
m_currentDisplay += L"2";
break;
case Command::Three:
m_currentDisplay += L"3";
break;
case Command::Four:
m_currentDisplay += L"4";
break;
case Command::Five:
m_currentDisplay += L"5";
break;
case Command::Six:
m_currentDisplay += L"6";
break;
case Command::Seven:
m_currentDisplay += L"7";
break;
case Command::Eight:
m_currentDisplay += L"8";
break;
case Command::Nine:
m_currentDisplay += L"9";
break;
case Command::Decimal:
clearFront = false;
clearBack = false;
if (!m_currentHasDecimal)
{ {
clearFront = true; m_currentDisplay += L".";
m_currentHasDecimal = true;
} }
bool clearBack = false; break;
if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED))
case Command::Backspace:
clearFront = false;
clearBack = false;
if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2)
{ {
clearBack = true; if (m_currentDisplay.back() == '.')
}
if (command != Command::Negate && m_switchedActive)
{
ClearValues();
m_switchedActive = false;
clearFront = true;
clearBack = false;
}
switch (command)
{
case Command::Zero:
m_currentDisplay += L"0";
break;
case Command::One:
m_currentDisplay += L"1";
break;
case Command::Two:
m_currentDisplay += L"2";
break;
case Command::Three:
m_currentDisplay += L"3";
break;
case Command::Four:
m_currentDisplay += L"4";
break;
case Command::Five:
m_currentDisplay += L"5";
break;
case Command::Six:
m_currentDisplay += L"6";
break;
case Command::Seven:
m_currentDisplay += L"7";
break;
case Command::Eight:
m_currentDisplay += L"8";
break;
case Command::Nine:
m_currentDisplay += L"9";
break;
case Command::Decimal:
clearFront = false;
clearBack = false;
if (!m_currentHasDecimal)
{ {
m_currentDisplay += L"."; m_currentHasDecimal = false;
m_currentHasDecimal = true;
} }
break; m_currentDisplay.pop_back();
}
else
{
m_currentDisplay = L"0";
m_currentHasDecimal = false;
}
break;
case Command::Backspace: case Command::Negate:
clearFront = false; clearFront = false;
clearBack = false; clearBack = false;
if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) if (m_currentCategory.supportsNegative)
{
if (m_currentDisplay.front() == '-')
{ {
if (m_currentDisplay.back() == '.') m_currentDisplay.erase(0, 1);
{
m_currentHasDecimal = false;
}
m_currentDisplay.pop_back();
} }
else else
{ {
m_currentDisplay = L"0"; m_currentDisplay.insert(0, 1, '-');
m_currentHasDecimal = false;
} }
break;
case Command::Negate:
clearFront = false;
clearBack = false;
if (m_currentCategory.supportsNegative)
{
if (m_currentDisplay.front() == '-')
{
m_currentDisplay.erase(0, 1);
}
else
{
m_currentDisplay.insert(0, 1, '-');
}
}
break;
case Command::Clear:
clearFront = false;
clearBack = false;
ClearValues();
break;
case Command::Reset:
clearFront = false;
clearBack = false;
ClearValues();
Reset();
break;
default:
break;
} }
break;
case Command::Clear:
clearFront = false;
clearBack = false;
ClearValues();
break;
if (clearFront) case Command::Reset:
{ clearFront = false;
m_currentDisplay.erase(0, 1); clearBack = false;
} ClearValues();
if (clearBack) Reset();
{ break;
m_currentDisplay.erase(m_currentDisplay.size() - 1, 1);
m_vmCallback->MaxDigitsReached();
}
Calculate(); default:
break;
UpdateViewModel();
} }
if (clearFront)
{
m_currentDisplay.erase(0, 1);
}
if (clearBack)
{
m_currentDisplay.erase(m_currentDisplay.size() - 1, 1);
m_vmCallback->MaxDigitsReached();
}
Calculate();
UpdateViewModel();
} }
/// <summary> /// <summary>
@ -844,47 +839,49 @@ void UnitConverter::Reset()
ClearValues(); ClearValues();
m_switchedActive = false; m_switchedActive = false;
if (!m_categories.empty()) if (m_categories.empty())
{ {
m_currentCategory = m_categories[0]; return;
}
m_categoryToUnits.clear(); m_currentCategory = m_categories[0];
m_ratioMap.clear();
bool readyCategoryFound = false; m_categoryToUnits.clear();
for (const Category& category : m_categories) m_ratioMap.clear();
bool readyCategoryFound = false;
for (const Category& category : m_categories)
{
shared_ptr<IConverterDataLoader> activeDataLoader = GetDataLoaderForCategory(category);
if (activeDataLoader == nullptr)
{ {
shared_ptr<IConverterDataLoader> activeDataLoader = GetDataLoaderForCategory(category); // The data loader is different depending on the category, e.g. currency data loader
if (activeDataLoader == nullptr) // is different from the static data loader.
{ // If there is no data loader for this category, continue.
// The data loader is different depending on the category, e.g. currency data loader continue;
// is different from the static data loader.
// If there is no data loader for this category, continue.
continue;
}
vector<Unit> units = activeDataLoader->LoadOrderedUnits(category);
m_categoryToUnits[category] = units;
// Just because the units are empty, doesn't mean the user can't select this category,
// we just want to make sure we don't let an unready category be the default.
if (!units.empty())
{
for (Unit u : units)
{
m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u);
}
if (!readyCategoryFound)
{
m_currentCategory = category;
readyCategoryFound = true;
}
}
} }
InitializeSelectedUnits(); vector<Unit> units = activeDataLoader->LoadOrderedUnits(category);
Calculate(); m_categoryToUnits[category] = units;
// Just because the units are empty, doesn't mean the user can't select this category,
// we just want to make sure we don't let an unready category be the default.
if (!units.empty())
{
for (Unit u : units)
{
m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u);
}
if (!readyCategoryFound)
{
m_currentCategory = category;
readyCategoryFound = true;
}
}
} }
InitializeSelectedUnits();
Calculate();
} }
/// <summary> /// <summary>
@ -1029,22 +1026,24 @@ void UnitConverter::Calculate()
/// <param name="input">wstring to trim</param> /// <param name="input">wstring to trim</param>
void UnitConverter::TrimString(wstring& returnString) void UnitConverter::TrimString(wstring& returnString)
{ {
if (returnString.find(L'.') != m_returnDisplay.npos) if (returnString.find(L'.') == m_returnDisplay.npos)
{ {
wstring::iterator iter; return;
for (iter = returnString.end() - 1; ;iter--) }
wstring::iterator iter;
for (iter = returnString.end() - 1; ;iter--)
{
if (*iter != L'0')
{ {
if (*iter != L'0') returnString.erase(iter + 1, returnString.end());
{ break;
returnString.erase(iter + 1, returnString.end());
break;
}
}
if (*(returnString.end()-1) == L'.')
{
returnString.erase(returnString.end()-1, returnString.end());
} }
} }
if (*(returnString.end()-1) == L'.')
{
returnString.erase(returnString.end()-1, returnString.end());
}
} }
/// <summary> /// <summary>

View file

@ -12,6 +12,7 @@ using namespace CalculatorApp::Common::DateCalculation;
DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier) DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier)
{ {
m_calendar = ref new Calendar(); m_calendar = ref new Calendar();
m_calendar->ChangeTimeZone("UTC");
m_calendar->ChangeCalendarSystem(calendarIdentifier); m_calendar->ChangeCalendarSystem(calendarIdentifier);
} }

View file

@ -43,11 +43,7 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
m_StrDateDiffResultAutomationName(L""), m_StrDateDiffResultAutomationName(L""),
m_StrDateDiffResultInDays(L""), m_StrDateDiffResultInDays(L""),
m_StrDateResult(L""), m_StrDateResult(L""),
m_StrDateResultAutomationName(L""), m_StrDateResultAutomationName(L"")
m_fromDate({ 0 }),
m_toDate({ 0 }),
m_startDate({ 0 }),
m_dateResult({ 0 })
{ {
const auto& localizationSettings = LocalizationSettings::GetInstance(); const auto& localizationSettings = LocalizationSettings::GetInstance();
@ -56,19 +52,19 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
// Initialize Date Calc engine // Initialize Date Calc engine
m_dateCalcEngine = make_shared<DateCalculationEngine>(localizationSettings.GetCalendarIdentifier()); m_dateCalcEngine = make_shared<DateCalculationEngine>(localizationSettings.GetCalendarIdentifier());
// Initialize dates of DatePicker controls to today's date // Initialize dates of DatePicker controls to today's date
auto calendar = ref new Calendar(); auto calendar = ref new Calendar();
// We force the timezone to UTC, in order to avoid being affected by Daylight Saving Time
// when we calculate the difference between 2 dates.
calendar->ChangeTimeZone("UTC");
auto today = calendar->GetDateTime(); auto today = calendar->GetDateTime();
// FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC) // FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC)
m_fromDate = today; m_fromDate = ClipTime(today);
m_toDate = today; m_toDate = ClipTime(today);
FromDate = ClipTime(today);
ToDate = ClipTime(today);
// StartDate should not be clipped // StartDate should not be clipped
StartDate = today; m_startDate = today;
m_dateResult = today; m_dateResult = today;
// Initialize the list separator delimiter appended with a space at the end, e.g. ", " // Initialize the list separator delimiter appended with a space at the end, e.g. ", "
@ -86,15 +82,6 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
m_offsetValues->Append(ref new String(numberStr.c_str())); m_offsetValues->Append(ref new String(numberStr.c_str()));
} }
/* In the ClipTime function, we used to change timezone to UTC before clipping the time.
The comment from the previous developers said this was done to eliminate the effects of
Daylight Savings Time. We can't think of a good reason why this change in timezone is
necessary and did find bugs related to the change, therefore, we have removed the
change. Just in case, we will see if the clipped time is ever a different day from the
original day, which would hopefully indicate the change in timezone was actually
necessary. We will collect telemetry if we find this case. If we don't see any
telemetry events after the application has been used for some time, we will feel safe
and can remove this function. */
DayOfWeek trueDayOfWeek = calendar->DayOfWeek; DayOfWeek trueDayOfWeek = calendar->DayOfWeek;
DateTime clippedTime = ClipTime(today); DateTime clippedTime = ClipTime(today);
@ -383,13 +370,14 @@ String^ DateCalculatorViewModel::GetLocalizedNumberString(int value) const
return ref new String(numberStr.c_str()); return ref new String(numberStr.c_str());
} }
// Adjusts the given DateTime to 12AM of the same day // Adjusts the given DateTime to 12AM (UTC) of the same day
DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime) DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime)
{ {
auto calendar = ref new Calendar(); auto calendar = ref new Calendar();
calendar->ChangeTimeZone("UTC");
calendar->SetDateTime(dateTime); calendar->SetDateTime(dateTime);
calendar->Period = 1; calendar->Period = calendar->FirstPeriodInThisDay;
calendar->Hour = 12; calendar->Hour = calendar->FirstHourInThisPeriod;
calendar->Minute = 0; calendar->Minute = 0;
calendar->Second = 0; calendar->Second = 0;
calendar->Nanosecond = 0; calendar->Nanosecond = 0;

View file

@ -23,8 +23,8 @@ namespace CalculatorApp
// Input Properties // Input Properties
OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode); OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode);
OBSERVABLE_PROPERTY_RW(bool, IsAddMode); OBSERVABLE_PROPERTY_RW(bool, IsAddMode);
OBSERVABLE_PROPERTY_RW(bool, IsDiffInDays); // If diff is only in days or the dates are the same, OBSERVABLE_PROPERTY_R(bool, IsDiffInDays); // If diff is only in days or the dates are the same,
// then show only one result and avoid redundancy // then show only one result and avoid redundancy
OBSERVABLE_PROPERTY_RW(int, DaysOffset); OBSERVABLE_PROPERTY_RW(int, DaysOffset);
OBSERVABLE_PROPERTY_RW(int, MonthsOffset); OBSERVABLE_PROPERTY_RW(int, MonthsOffset);
@ -82,11 +82,11 @@ namespace CalculatorApp
} }
// Output Properties // Output Properties
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResult); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResult);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultAutomationName); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultAutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultInDays); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultInDays);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResult); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResult);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResultAutomationName); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResultAutomationName);
COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand); COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand);
@ -104,8 +104,6 @@ namespace CalculatorApp
Platform::String^ GetLocalizedNumberString(int value) const; Platform::String^ GetLocalizedNumberString(int value) const;
static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime); static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime);
static void CheckClipTimeSameDay(Windows::Globalization::Calendar^ reference);
property bool IsOutOfBound property bool IsOutOfBound
{ {
bool get() { return m_isOutOfBound; } bool get() { return m_isOutOfBound; }

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "pch.h" #include "pch.h"
@ -53,6 +53,8 @@ constexpr size_t SELECTED_TARGET_UNIT = 2;
// x millisecond delay before we consider conversion to be final // x millisecond delay before we consider conversion to be final
constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000; constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000;
const wregex regexTrimSpacesStart = wregex(L"^\\s+");
const wregex regexTrimSpacesEnd = wregex(L"\\s+$");
namespace CalculatorApp::ViewModel namespace CalculatorApp::ViewModel
{ {
@ -202,12 +204,10 @@ void UnitConverterViewModel::BuildUnitList(const vector<UCM::Unit>& modelUnitLis
m_Units->Clear(); m_Units->Clear();
for (const UCM::Unit& modelUnit : modelUnitList) for (const UCM::Unit& modelUnit : modelUnitList)
{ {
if (modelUnit.isWhimsical) if (!modelUnit.isWhimsical)
{ {
continue; m_Units->Append(ref new Unit(modelUnit));
} }
m_Units->Append(ref new Unit(modelUnit));
} }
if (m_Units->Size == 0) if (m_Units->Size == 0)
@ -348,10 +348,15 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str
if (pos != wstring::npos) if (pos != wstring::npos)
{ {
currencyResult.erase(pos, currencyCode.length()); currencyResult.erase(pos, currencyCode.length());
pos = currencyResult.find(L'\u00a0'); // non-breaking space std::wsmatch sm;
if (pos != wstring::npos) if (regex_search(currencyResult, sm, regexTrimSpacesStart))
{ {
currencyResult.erase(pos, 1); currencyResult.erase(sm.prefix().length(), sm.length());
}
if (regex_search(currencyResult, sm, regexTrimSpacesEnd))
{
currencyResult.erase(sm.prefix().length(), sm.length());
} }
} }
@ -643,10 +648,8 @@ String^ UnitConverterViewModel::Serialize()
String^ serializedData = ref new String(wstring(out.str()).c_str()); String^ serializedData = ref new String(wstring(out.str()).c_str());
return serializedData; return serializedData;
} }
else
{ return nullptr;
return nullptr;
}
} }
void UnitConverterViewModel::Deserialize(Platform::String^ state) void UnitConverterViewModel::Deserialize(Platform::String^ state)
@ -879,14 +882,11 @@ void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInpu
{ {
// currencyInput is in en-US and has the default decimal separator, so this is safe to do. // currencyInput is in en-US and has the default decimal separator, so this is safe to do.
auto posOfDecimal = currencyInput.find(L'.'); auto posOfDecimal = currencyInput.find(L'.');
m_isInputBlocked = false;
if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory) if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory)
{ {
m_isInputBlocked = (posOfDecimal + static_cast<size_t>(m_currencyMaxFractionDigits) + 1 == currencyInput.length()); m_isInputBlocked = (posOfDecimal + static_cast<size_t>(m_currencyMaxFractionDigits) + 1 == currencyInput.length());
} }
else
{
m_isInputBlocked = false;
}
} }
NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId( NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(
@ -988,7 +988,7 @@ void UnitConverterViewModel::OnPaste(String^ stringToPaste, ViewMode mode)
} }
// Negate is only allowed if it's the first legal character, which is handled above. // Negate is only allowed if it's the first legal character, which is handled above.
if (NumbersAndOperatorsEnum::None != op && NumbersAndOperatorsEnum::Negate != op) if (NumbersAndOperatorsEnum::Negate != op)
{ {
UCM::Command cmd = CommandFromButtonId(op); UCM::Command cmd = CommandFromButtonId(op);
m_model->SendCommand(cmd); m_model->SendCommand(cmd);

View file

@ -515,6 +515,7 @@
<Setter Target="M5.MaxWidth" Value="80"/> <Setter Target="M5.MaxWidth" Value="80"/>
<Setter Target="memButton.(Grid.Column)" Value="5"/> <Setter Target="memButton.(Grid.Column)" Value="5"/>
<Setter Target="MemoryButton.(Grid.Column)" Value="6"/> <Setter Target="MemoryButton.(Grid.Column)" Value="6"/>
<Setter Target="HistoryButton.Visibility" Value="Collapsed"/>
</VisualState.Setters> </VisualState.Setters>
<Storyboard Completed="OnStoryboardCompleted"/> <Storyboard Completed="OnStoryboardCompleted"/>
</VisualState> </VisualState>

View file

@ -415,7 +415,7 @@ void Calculator::UpdateHistoryState()
SetChildAsHistory(); SetChildAsHistory();
HistoryButton->Visibility = ::Visibility::Collapsed; HistoryButton->Visibility = ::Visibility::Collapsed;
if (m_IsLastFlyoutHistory) if (!IsProgrammer && m_IsLastFlyoutHistory)
{ {
DockPivot->SelectedIndex = 0; DockPivot->SelectedIndex = 0;
} }
@ -522,7 +522,7 @@ void Calculator::HistoryFlyout_Closed(_In_ Object ^sender, _In_ Object ^args)
AutomationProperties::SetName(HistoryButton, m_openHistoryFlyoutAutomationName); AutomationProperties::SetName(HistoryButton, m_openHistoryFlyoutAutomationName);
m_fIsHistoryFlyoutOpen = false; m_fIsHistoryFlyoutOpen = false;
EnableControls(true); EnableControls(true);
if (HistoryButton->IsEnabled) if (HistoryButton->IsEnabled && HistoryButton->Visibility == ::Visibility::Visible)
{ {
HistoryButton->Focus(::FocusState::Programmatic); HistoryButton->Focus(::FocusState::Programmatic);
} }

View file

@ -387,6 +387,63 @@ namespace DateCalculationUnitTests
VERIFY_IS_TRUE(StringReference(L"") != viewModel->StrDateResult); VERIFY_IS_TRUE(StringReference(L"") != viewModel->StrDateResult);
} }
TEST_METHOD(DateCalcViewModelDateDiffDaylightSavingTimeTest)
{
auto viewModel = ref new DateCalculatorViewModel();
viewModel->IsDateDiffMode = true;
VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
// 29.02.2008
viewModel->FromDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[5].startDate);
// 31.03.2008
viewModel->ToDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[5].endDate);
//// Assert for the result
VERIFY_IS_FALSE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"31 days"), viewModel->StrDateDiffResultInDays);
VERIFY_ARE_EQUAL(StringReference(L"1 month, 2 days"), viewModel->StrDateDiffResult);
// Daylight Saving Time - Clock Forward
// 10.03.2019
SYSTEMTIME startDate;
startDate.wYear = 2019;
startDate.wMonth = 03;
startDate.wDay = 10;
startDate.wDayOfWeek = 0;
startDate.wHour = startDate.wMinute = 0;
startDate.wSecond = startDate.wMilliseconds = 0;
viewModel->FromDate = DateUtils::SystemTimeToDateTime(startDate);
// 11.03.2019
SYSTEMTIME endDate;
endDate.wYear = 2019;
endDate.wMonth = 03;
endDate.wDay = 11;
endDate.wDayOfWeek = 0;
endDate.wHour = endDate.wMinute = 0;
endDate.wSecond = endDate.wMilliseconds = 0;
viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate);
VERIFY_IS_TRUE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
endDate.wDay += 6;
viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate);
VERIFY_IS_FALSE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"1 week"), viewModel->StrDateDiffResult);
// Daylight Saving Time - Clock Backward
// 03.11.2019
startDate.wMonth = 11;
startDate.wDay = 03;
viewModel->FromDate = DateUtils::SystemTimeToDateTime(startDate);
// 04.11.2019
endDate.wMonth = 11;
endDate.wDay = 04;
viewModel->ToDate = DateUtils::SystemTimeToDateTime(endDate);
VERIFY_IS_TRUE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
}
TEST_METHOD(DateCalcViewModelAddTest) TEST_METHOD(DateCalcViewModelAddTest)
{ {
// TODO - MSFT 10331900, fix this test // TODO - MSFT 10331900, fix this test