diff --git a/.gitattributes b/.gitattributes
index 51617f5f..e0d31f91 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -12,29 +12,6 @@
###############################################################################
*.cs diff=csharp
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-*.sln merge=binary
-*.csproj merge=binary
-*.vbproj merge=binary
-*.vcxproj merge=binary
-*.vcproj merge=binary
-*.dbproj merge=binary
-*.fsproj merge=binary
-*.lsproj merge=binary
-*.wixproj merge=binary
-*.modelproj merge=binary
-*.sqlproj merge=binary
-*.wwaproj merge=binary
-
###############################################################################
# behavior for image files
#
diff --git a/.gitignore b/.gitignore
index 2100dfc1..1088272d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -289,6 +289,7 @@ __pycache__/
# Calculator specific
Generated Files/
+src/GraphControl/GraphingImplOverrides.props
!/build/config/TRexDefs/**
!src/Calculator/TemporaryKey.pfx
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx
\ No newline at end of file
diff --git a/README.md b/README.md
index d967b175..00243142 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,9 @@ Calculator ships regularly with new features and bug fixes. You can get the late
- Calculation history and memory capabilities.
- Conversion between many units of measurement.
- Currency conversion based on data retrieved from [Bing](https://www.bing.com).
+- [Infinite precision](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) for basic
+ arithmetic operations (addition, subtraction, multiplication, division) so that calculations
+ never lose precision.
## Getting started
Prerequisites:
diff --git a/build/config/SignConfig.xml b/build/config/SignConfig.xml
index 7209725e..eb298e87 100644
--- a/build/config/SignConfig.xml
+++ b/build/config/SignConfig.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/build/pipelines/azure-pipelines.ci.yaml b/build/pipelines/azure-pipelines.ci.yaml
index 31ce98fb..23eb46ca 100644
--- a/build/pipelines/azure-pipelines.ci.yaml
+++ b/build/pipelines/azure-pipelines.ci.yaml
@@ -33,6 +33,10 @@ jobs:
platform: ARM64
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
+- template: ./templates/run-ui-tests.yaml
+ parameters:
+ platform: x64
+
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x64
diff --git a/build/pipelines/templates/build-single-architecture.yaml b/build/pipelines/templates/build-single-architecture.yaml
index 92e06f7b..50859db3 100644
--- a/build/pipelines/templates/build-single-architecture.yaml
+++ b/build/pipelines/templates/build-single-architecture.yaml
@@ -30,7 +30,7 @@ steps:
inputs:
solution: src/Calculator.sln
vsVersion: 15.0
- msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) ${{ parameters.extraMsBuildArgs }}
+ msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: true
diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml
index a6a4973b..178fd268 100644
--- a/build/pipelines/templates/prepare-release-internalonly.yaml
+++ b/build/pipelines/templates/prepare-release-internalonly.yaml
@@ -1,5 +1,5 @@
# This template contains a job which builds artifacts needed to release the app to the store and to
-# Windows using Microsoft-internal systems. It relies Microsoft-internal resources and will not
+# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
# work outside of Microsoft.
# Specifically, this job:
# - Signs the bundle using a secure system. If you want to build your own, use SignTool following
diff --git a/build/pipelines/templates/run-ui-tests.yaml b/build/pipelines/templates/run-ui-tests.yaml
new file mode 100644
index 00000000..41d441ad
--- /dev/null
+++ b/build/pipelines/templates/run-ui-tests.yaml
@@ -0,0 +1,52 @@
+# This template contains jobs to run UI tests using WinAppDriver.
+
+parameters:
+ platform: ''
+
+jobs:
+- job: UITests${{ parameters.platform }}
+ displayName: UITests ${{ parameters.platform }}
+ dependsOn: Build${{ parameters.platform }}
+ condition: succeeded()
+ pool:
+ vmImage: windows-2019
+ variables:
+ skipComponentGovernanceDetection: true
+ steps:
+ - checkout: none
+
+ - powershell: Set-DisplayResolution -Width 1920 -Height 1080 -Force
+ displayName: Set resolution to 1920x1080
+ continueOnError: true
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download AppxBundle and CalculatorUITests
+ inputs:
+ artifactName: drop
+ itemPattern: |
+ drop/Release/${{ parameters.platform }}/Calculator/AppPackages/**
+ drop/Release/${{ parameters.platform }}/publish/**
+
+ - task: PowerShell@2
+ displayName: Install certificate
+ inputs:
+ filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
+ arguments: -CertificatePath $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Calculator_$(Build.BuildNumber)_${{ parameters.platform }}.cer -Force
+
+ - task: PowerShell@2
+ displayName: Install app
+ inputs:
+ filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
+ arguments: -Force
+
+ - powershell: Start-Process -FilePath "C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe" -Verb RunAs
+ displayName: Start WinAppDriver
+
+ - task: VSTest@2
+ displayName: Run CalculatorUITests
+ inputs:
+ testAssemblyVer2: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.dll
+ vsTestVersion: 16.0
+ runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.runsettings
+ platform: ${{ parameters.platform }}
+ configuration: Release
\ No newline at end of file
diff --git a/docs/ApplicationArchitecture.md b/docs/ApplicationArchitecture.md
index 0d7c2ff3..dff02965 100644
--- a/docs/ApplicationArchitecture.md
+++ b/docs/ApplicationArchitecture.md
@@ -153,7 +153,9 @@ The CalcEngine contains the logic for interpreting and performing operations acc
### RatPack
-The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for performing its mathematical operations. The interface to this layer is defined in [ratpak.h][ratpak.h].
+The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for
+performing its mathematical operations (using [infinite precision][Infinite Precision] arithmetic
+instead of regular floating point arithmetic). The interface to this layer is defined in [ratpak.h][ratpak.h].
[References]:####################################################################################################
diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp
index c8adad34..6d6807ba 100644
--- a/src/CalcViewModel/Common/CopyPasteManager.cpp
+++ b/src/CalcViewModel/Common/CopyPasteManager.cpp
@@ -15,11 +15,15 @@ using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::ApplicationModel::DataTransfer;
-unsigned long long maxOperandNumber;
+String^ CopyPasteManager::supportedFormats[] =
+{
+ StandardDataFormats::Text
+};
-String ^ CopyPasteManager::supportedFormats[] = { StandardDataFormats::Text };
+static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" };
-constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" };
+// The below values can not be "constexpr"-ed,
+// as both wstring_view and wchar[] can not be concatenated
// [\s\x85] means white-space characters
static const wstring c_wspc = L"[\\s\\x85]*";
static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc;
@@ -36,26 +40,43 @@ static const wstring c_binProgrammerChars = L"[0-1]+((_|'|`)[0-1]+)*";
static const wstring c_uIntSuffixes = L"[uU]?[lL]{0,2}";
// RegEx Patterns used by various modes
-static const array standardModePatterns = { wregex(c_wspc + c_signedDecFloat + c_wspc) };
-static const array scientificModePatterns = { wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens),
- wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat
- + L"[e]([+]|[-])+\\d+" + c_wspcRParens) };
-static const array, 4> programmerModePatterns = {
- { // Hex numbers like 5F, 4A0C, 0xa9, 0xFFull, 47CDh
- { wregex(c_wspcLParens + L"(0[xX])?" + c_hexProgrammerChars + c_uIntSuffixes + c_wspcRParens),
- wregex(c_wspcLParens + c_hexProgrammerChars + L"[hH]?" + c_wspcRParens) },
- // Decimal numbers like -145, 145, 0n145, 123ull etc
- { wregex(c_wspcLParens + L"[-+]?" + c_decProgrammerChars + L"[lL]{0,2}" + c_wspcRParens),
- wregex(c_wspcLParens + L"(0[nN])?" + c_decProgrammerChars + c_uIntSuffixes + c_wspcRParens) },
- // Octal numbers like 06, 010, 0t77, 0o77, 077ull etc
- { wregex(c_wspcLParens + L"(0[otOT])?" + c_octProgrammerChars + c_uIntSuffixes + c_wspcRParens) },
- // Binary numbers like 011010110, 0010110, 10101001, 1001b, 0b1001, 0y1001, 0b1001ull
- { wregex(c_wspcLParens + L"(0[byBY])?" + c_binProgrammerChars + c_uIntSuffixes + c_wspcRParens),
- wregex(c_wspcLParens + c_binProgrammerChars + L"[bB]?" + c_wspcRParens) } }
+static const array standardModePatterns =
+{
+ wregex(c_wspc + c_signedDecFloat + c_wspc)
+};
+static const array scientificModePatterns =
+{
+ wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens),
+ wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + L"[e]([+]|[-])+\\d+" + c_wspcRParens)
+};
+static const array, 4> programmerModePatterns =
+{ {
+ // Hex numbers like 5F, 4A0C, 0xa9, 0xFFull, 47CDh
+ {
+ wregex(c_wspcLParens + L"(0[xX])?" + c_hexProgrammerChars + c_uIntSuffixes + c_wspcRParens),
+ wregex(c_wspcLParens + c_hexProgrammerChars + L"[hH]?" + c_wspcRParens)
+ },
+ // Decimal numbers like -145, 145, 0n145, 123ull etc
+ {
+ wregex(c_wspcLParens + L"[-+]?" + c_decProgrammerChars + L"[lL]{0,2}" +c_wspcRParens),
+ wregex(c_wspcLParens + L"(0[nN])?" + c_decProgrammerChars + c_uIntSuffixes + c_wspcRParens)
+ },
+ // Octal numbers like 06, 010, 0t77, 0o77, 077ull etc
+ {
+ wregex(c_wspcLParens + L"(0[otOT])?" + c_octProgrammerChars + c_uIntSuffixes + c_wspcRParens)
+ },
+ // Binary numbers like 011010110, 0010110, 10101001, 1001b, 0b1001, 0y1001, 0b1001ull
+ {
+ wregex(c_wspcLParens + L"(0[byBY])?" + c_binProgrammerChars + c_uIntSuffixes + c_wspcRParens),
+ wregex(c_wspcLParens + c_binProgrammerChars + L"[bB]?" + c_wspcRParens)
+ }
+ } };
+static const array unitConverterPatterns =
+{
+ wregex(c_wspc + L"[-+]?\\d*[.]?\\d*" + c_wspc)
};
-static const array unitConverterPatterns = { wregex(c_wspc + L"[-+]?\\d*[.]?\\d*" + c_wspc) };
-void CopyPasteManager::CopyToClipboard(String ^ stringToCopy)
+void CopyPasteManager::CopyToClipboard(String^ stringToCopy)
{
// Copy the string to the clipboard
auto dataPackage = ref new DataPackage();
@@ -63,7 +84,7 @@ void CopyPasteManager::CopyToClipboard(String ^ stringToCopy)
Clipboard::SetContent(dataPackage);
}
-task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
+task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
{
// Retrieve the text in the clipboard
auto dataPackageView = Clipboard::GetContent();
@@ -74,36 +95,35 @@ task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupTy
//-- add support to allow pasting for expressions like 1.3e12(as of now we allow 1.3e+12)
return create_task((dataPackageView->GetTextAsync(::StandardDataFormats::Text)))
- .then([mode, modeType, programmerNumberBase,
- bitLengthType](String ^ pastedText) { return ValidatePasteExpression(pastedText, mode, modeType, programmerNumberBase, bitLengthType); },
- task_continuation_context::use_arbitrary());
+ .then([mode, modeType, programmerNumberBase, bitLengthType](String^ pastedText)
+ {
+ return ValidatePasteExpression(pastedText, mode, modeType, programmerNumberBase, bitLengthType);
+ }
+ , task_continuation_context::use_arbitrary());
}
int CopyPasteManager::ClipboardTextFormat()
{
- int result = -1;
-
- auto dataPackageView = Clipboard::GetContent();
+ const auto dataPackageView = Clipboard::GetContent();
for (int i = 0; i < RTL_NUMBER_OF(supportedFormats); i++)
{
if (dataPackageView->Contains(supportedFormats[i]))
{
- result = i;
- break;
+ return i;
}
}
- return result;
+ return -1;
}
-String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType)
+String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType)
{
return CopyPasteManager::ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType);
}
// return "NoOp" if pastedText is invalid else return pastedText
-String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
+String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
{
if (pastedText->Length() > MaxPasteableLength)
{
@@ -115,7 +135,7 @@ String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode
wstring pasteExpression = pastedText->Data();
// Get english translated expression
- String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression);
+ String^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression);
// Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333
pasteExpression = RemoveUnwantedCharsFromWstring(englishString->Data());
@@ -203,8 +223,7 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression
if ((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-'))
{
// don't break the expression into operands if the encountered character corresponds to sign command(+-)
- if (isPreviousOpenParen || startOfExpression || isPreviousOperator
- || ((mode != ViewMode::Programmer) && !((i != 0) && (pasteExpression.at(i - 1) != L'e'))))
+ if (isPreviousOpenParen || startOfExpression || isPreviousOperator || ((mode != ViewMode::Programmer) && !((i != 0) && (pasteExpression.at(i - 1) != L'e'))))
{
isPreviousOperator = false;
continue;
@@ -247,13 +266,8 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
return false;
}
- bool expMatched = true;
vector patterns{};
-
- pair operandLimits = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType);
- size_t maxOperandLength = operandLimits.first;
- uint64_t maxOperandValue = operandLimits.second;
-
+
if (mode == ViewMode::Standard)
{
patterns.assign(standardModePatterns.begin(), standardModePatterns.end());
@@ -271,11 +285,14 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
patterns.assign(unitConverterPatterns.begin(), unitConverterPatterns.end());
}
- for (const wstring& operand : operands)
+ const auto [maxOperandLength, maxOperandValue] = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType);
+ bool expMatched = true;
+
+ for (const auto& operand : operands)
{
// Each operand only needs to match one of the available patterns.
bool operandMatched = false;
- for (const wregex& pattern : patterns)
+ for (const auto& pattern : patterns)
{
operandMatched = operandMatched || regex_match(operand, pattern);
}
@@ -284,7 +301,7 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
{
// Remove characters that are valid in the expression but we do not want to include in length calculations
// or which will break conversion from string-to-ULL.
- wstring operandValue = SanitizeOperand(operand);
+ const wstring operandValue = SanitizeOperand(operand);
// If an operand exceeds the maximum length allowed, break and return.
if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLength)
@@ -320,16 +337,16 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
{
- size_t maxLength = 0;
- uint64_t maxValue = 0;
-
+ constexpr size_t defaultMaxOperandLength = 0;
+ constexpr uint64_t defaultMaxValue = 0;
+
if (mode == ViewMode::Standard)
{
- maxLength = MaxStandardOperandLength;
+ return make_pair(MaxStandardOperandLength, defaultMaxValue);
}
else if (mode == ViewMode::Scientific)
{
- maxLength = MaxScientificOperandLength;
+ return make_pair(MaxScientificOperandLength, defaultMaxValue);
}
else if (mode == ViewMode::Programmer)
{
@@ -369,15 +386,17 @@ pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mo
unsigned int signBit = (programmerNumberBase == DecBase) ? 1 : 0;
- maxLength = (size_t)ceil((bitLength - signBit) / bitsPerDigit);
- maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit));
+ const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit));
+ const uint64_t maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit));
+
+ return make_pair(maxLength, maxValue);
}
else if (modeType == CategoryGroupType::Converter)
{
- maxLength = MaxConverterInputLength;
+ return make_pair(MaxConverterInputLength, defaultMaxValue);
}
- return make_pair(maxLength, maxValue);
+ return make_pair(defaultMaxOperandLength, defaultMaxValue);
}
wstring CopyPasteManager::SanitizeOperand(const wstring& operand)
@@ -396,8 +415,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
return false;
}
- // Default to base10
- int intBase = 10;
+ int intBase;
switch (numberBase)
{
case HexBase:
@@ -409,6 +427,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
case BinBase:
intBase = 2;
break;
+ default:
case DecBase:
intBase = 10;
break;
@@ -420,11 +439,11 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
result = stoull(operand, &size, intBase);
return true;
}
- catch (invalid_argument)
+ catch (const invalid_argument&)
{
// Do nothing
}
- catch (out_of_range)
+ catch (const out_of_range&)
{
// Do nothing
}
@@ -432,35 +451,28 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
return false;
}
-size_t CopyPasteManager::OperandLength(wstring operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase)
-{
- size_t len = 0;
- if (mode == ViewMode::Standard || mode == ViewMode::Scientific)
- {
- len = StandardScientificOperandLength(operand);
- }
- else if (mode == ViewMode::Programmer)
- {
- len = ProgrammerOperandLength(operand, programmerNumberBase);
- }
- else if (modeType == CategoryGroupType::Converter)
- {
- len = operand.length();
+size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase)
+{
+ if (modeType == CategoryGroupType::Converter) {
+ return operand.length();
}
- return len;
+ switch(mode) {
+ case ViewMode::Standard:
+ case ViewMode::Scientific:
+ return StandardScientificOperandLength(operand);
+
+ case ViewMode::Programmer:
+ return ProgrammerOperandLength(operand, programmerNumberBase);
+
+ default:
+ return 0;
+ }
}
-size_t CopyPasteManager::StandardScientificOperandLength(wstring operand)
-{
- bool hasDecimal = false;
- for (size_t i = 0; i < operand.length(); i++)
- {
- if (operand[i] == L'.')
- {
- hasDecimal = true;
- }
- }
+size_t CopyPasteManager::StandardScientificOperandLength(const wstring& operand)
+{
+ const bool hasDecimal = operand.find('.') != wstring::npos;
if (hasDecimal)
{
@@ -482,8 +494,7 @@ size_t CopyPasteManager::StandardScientificOperandLength(wstring operand)
size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int numberBase)
{
- size_t len = operand.length();
-
+
vector prefixes{};
vector suffixes{};
switch (numberBase)
@@ -504,7 +515,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
break;
default:
// No defined prefixes/suffixes
- break;
+ return 0;
}
// UInt suffixes are common across all modes
@@ -514,9 +525,11 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
wstring operandUpper = operand;
transform(operandUpper.begin(), operandUpper.end(), operandUpper.begin(), towupper);
+ size_t len = operand.length();
+
// Detect if there is a suffix and subtract its length
// Check suffixes first to allow e.g. "0b" to result in length 1 (value 0), rather than length 0 (no value).
- for (const wstring& suffix : suffixes)
+ for (const auto& suffix : suffixes)
{
if (len < suffix.length())
{
@@ -531,7 +544,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
}
// Detect if there is a prefix and subtract its length
- for (const wstring& prefix : prefixes)
+ for (const auto& prefix : prefixes)
{
if (len < prefix.length())
{
diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h
index 1d23414b..9d6fd669 100644
--- a/src/CalcViewModel/Common/CopyPasteManager.h
+++ b/src/CalcViewModel/Common/CopyPasteManager.h
@@ -13,21 +13,20 @@ namespace CalculatorUnitTests
namespace CalculatorApp
{
-#define QwordType 1
-#define DwordType 2
-#define WordType 3
-#define ByteType 4
-#define HexBase 5
-#define DecBase 6
-#define OctBase 7
-#define BinBase 8
+ inline constexpr auto QwordType = 1;
+ inline constexpr auto DwordType = 2;
+ inline constexpr auto WordType = 3;
+ inline constexpr auto ByteType = 4;
+ inline constexpr auto HexBase = 5;
+ inline constexpr auto DecBase = 6;
+ inline constexpr auto OctBase = 7;
+ inline constexpr auto BinBase = 8;
class CopyPasteManager
{
public:
- static void CopyToClipboard(Platform::String ^ stringToCopy);
- static concurrency::task GetStringToPaste(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType,
- int programmerNumberBase = -1, int bitLengthType = -1);
+ static void CopyToClipboard(Platform::String^ stringToCopy);
+ static concurrency::task GetStringToPaste(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1);
static bool HasStringToPaste()
{
return ClipboardTextFormat() >= 0;
@@ -37,24 +36,26 @@ namespace CalculatorApp
private:
static int ClipboardTextFormat();
- static Platform::String
- ^ ValidatePasteExpression(Platform::String ^ pastedText, CalculatorApp::Common::ViewMode mode, int programmerNumberBase, int bitLengthType);
- static Platform::String
- ^ ValidatePasteExpression(Platform::String ^ pastedText, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType,
- int programmerNumberBase, int bitLengthType);
+ static Platform::String^ ValidatePasteExpression(
+ Platform::String^ pastedText,
+ CalculatorApp::Common::ViewMode mode,
+ int programmerNumberBase,
+ int bitLengthType);
+ static Platform::String^ ValidatePasteExpression(
+ Platform::String^ pastedText,
+ CalculatorApp::Common::ViewMode mode,
+ CalculatorApp::Common::CategoryGroupType modeType,
+ int programmerNumberBase,
+ int bitLengthType);
- static std::vector ExtractOperands(const std::wstring& pasteExpression, CalculatorApp::Common::ViewMode mode,
- int programmerNumberBase = -1, int bitLengthType = -1);
- static bool ExpressionRegExMatch(std::vector operands, CalculatorApp::Common::ViewMode mode,
- CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1);
+ static std::vector ExtractOperands(const std::wstring& pasteExpression, CalculatorApp::Common::ViewMode mode, int programmerNumberBase = -1, int bitLengthType = -1);
+ static bool ExpressionRegExMatch(std::vector operands, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1);
- static std::pair GetMaxOperandLengthAndValue(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType,
- int programmerNumberBase = -1, int bitLengthType = -1);
+ static std::pair GetMaxOperandLengthAndValue(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1);
static std::wstring SanitizeOperand(const std::wstring& operand);
static bool TryOperandToULL(const std::wstring& operand, int numberBase, unsigned long long int& result);
- static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType,
- int programmerNumberBase = -1);
- static size_t StandardScientificOperandLength(std::wstring operand);
+ static size_t OperandLength(const std::wstring& operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1);
+ static size_t StandardScientificOperandLength(const std::wstring& operand);
static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase);
static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input);
@@ -66,7 +67,7 @@ namespace CalculatorApp
static constexpr size_t MaxExponentLength = 4;
static constexpr size_t MaxProgrammerBitLength = 64;
- static Platform::String ^ supportedFormats[];
+ static Platform::String^ supportedFormats[];
friend class CalculatorUnitTests::CopyPasteManagerTest;
};
diff --git a/src/CalcViewModel/Common/DateCalculator.cpp b/src/CalcViewModel/Common/DateCalculator.cpp
index b6b1388c..de42fbe9 100644
--- a/src/CalcViewModel/Common/DateCalculator.cpp
+++ b/src/CalcViewModel/Common/DateCalculator.cpp
@@ -20,13 +20,27 @@ DateCalculationEngine::DateCalculationEngine(_In_ String ^ calendarIdentifier)
// Returns: True if function succeeds to calculate the date else returns False
bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate)
{
+ auto currentCalendarSystem = m_calendar->GetCalendarSystem();
+
try
{
m_calendar->SetDateTime(startDate);
if (duration.year != 0)
{
+ // The Japanese Era system can have multiple year partitions within the same year.
+ // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
+ // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in a date in Heisei 31.
+ // To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math, and then convert back to the Japanese era system.
+ // This works because the Japanese era system maintains the same year/month boundaries and durations as the Gregorian system and is only different in display value.
+ if (currentCalendarSystem == CalendarIdentifiers::Japanese)
+ {
+ m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian);
+ }
+
m_calendar->AddYears(duration.year);
+
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
}
if (duration.month != 0)
{
@@ -41,6 +55,9 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date
}
catch (Platform::InvalidArgumentException ^ ex)
{
+ // ensure that we revert to the correct calendar system
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
+
// Do nothing
return false;
}
@@ -52,6 +69,8 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date
// Returns: True if function succeeds to calculate the date else returns False
bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate)
{
+ auto currentCalendarSystem = m_calendar->GetCalendarSystem();
+
// For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first
// and then the larger units.
try
@@ -68,13 +87,28 @@ bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const
}
if (duration.year != 0)
{
+ // The Japanese Era system can have multiple year partitions within the same year.
+ // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
+ // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in a date in Heisei 31.
+ // To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math, and then convert back to the Japanese era system.
+ // This works because the Japanese era system maintains the same year/month boundaries and durations as the Gregorian system and is only different in display value.
+ if (currentCalendarSystem == CalendarIdentifiers::Japanese)
+ {
+ m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian);
+ }
+
m_calendar->AddYears(-duration.year);
+
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
}
*endDate = m_calendar->GetDateTime();
}
catch (Platform::InvalidArgumentException ^ ex)
{
+ // ensure that we revert to the correct calendar system
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
+
// Do nothing
return false;
}
diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp
index 8d9de3be..be656b2e 100644
--- a/src/CalcViewModel/StandardCalculatorViewModel.cpp
+++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp
@@ -782,6 +782,12 @@ void StandardCalculatorViewModel::OnPaste(String ^ pastedString, ViewMode mode)
NumbersAndOperatorsEnum mappedNumOp = MapCharacterToButtonId(*it, canSendNegate);
+ if (mappedNumOp == NumbersAndOperatorsEnum::None)
+ {
+ ++it;
+ continue;
+ }
+
if (isFirstLegalChar || isPreviousOperator)
{
isFirstLegalChar = false;
@@ -803,74 +809,71 @@ void StandardCalculatorViewModel::OnPaste(String ^ pastedString, ViewMode mode)
}
}
- if (mappedNumOp != NumbersAndOperatorsEnum::None)
+ switch (mappedNumOp)
{
- switch (mappedNumOp)
+ // Opening parenthesis starts a new expression and pushes negation state onto the stack
+ case NumbersAndOperatorsEnum::OpenParenthesis:
+ negateStack.push_back(sendNegate);
+ sendNegate = false;
+ break;
+
+ // Closing parenthesis pops the negation state off the stack and sends it down to the calc engine
+ case NumbersAndOperatorsEnum::CloseParenthesis:
+ if (!negateStack.empty())
{
- // Opening parenthesis starts a new expression and pushes negation state onto the stack
- case NumbersAndOperatorsEnum::OpenParenthesis:
- negateStack.push_back(sendNegate);
- sendNegate = false;
- break;
-
- // Closing parenthesis pops the negation state off the stack and sends it down to the calc engine
- case NumbersAndOperatorsEnum::CloseParenthesis:
- if (!negateStack.empty())
- {
- sendNegate = negateStack.back();
- negateStack.pop_back();
- canSendNegate = true;
- }
- else
- {
- // Don't send a closing parenthesis if a matching opening parenthesis hasn't been sent already
- sendCommand = false;
- }
- break;
-
- case NumbersAndOperatorsEnum::Zero:
- case NumbersAndOperatorsEnum::One:
- case NumbersAndOperatorsEnum::Two:
- case NumbersAndOperatorsEnum::Three:
- case NumbersAndOperatorsEnum::Four:
- case NumbersAndOperatorsEnum::Five:
- case NumbersAndOperatorsEnum::Six:
- case NumbersAndOperatorsEnum::Seven:
- case NumbersAndOperatorsEnum::Eight:
- case NumbersAndOperatorsEnum::Nine:
- processedDigit = true;
- break;
-
- case NumbersAndOperatorsEnum::Add:
- case NumbersAndOperatorsEnum::Subtract:
- case NumbersAndOperatorsEnum::Multiply:
- case NumbersAndOperatorsEnum::Divide:
- isPreviousOperator = true;
- break;
+ sendNegate = negateStack.back();
+ negateStack.pop_back();
+ canSendNegate = true;
}
-
- if (sendCommand)
+ else
{
- sentEquals = (mappedNumOp == NumbersAndOperatorsEnum::Equals);
- Command cmdenum = ConvertToOperatorsEnum(mappedNumOp);
- m_standardCalculatorManager.SendCommand(cmdenum);
+ // Don't send a closing parenthesis if a matching opening parenthesis hasn't been sent already
+ sendCommand = false;
+ }
+ break;
- // The CalcEngine state machine won't allow the negate command to be sent before any
- // other digits, so instead a flag is set and the command is sent after the first appropriate
- // command.
- if (sendNegate)
+ case NumbersAndOperatorsEnum::Zero:
+ case NumbersAndOperatorsEnum::One:
+ case NumbersAndOperatorsEnum::Two:
+ case NumbersAndOperatorsEnum::Three:
+ case NumbersAndOperatorsEnum::Four:
+ case NumbersAndOperatorsEnum::Five:
+ case NumbersAndOperatorsEnum::Six:
+ case NumbersAndOperatorsEnum::Seven:
+ case NumbersAndOperatorsEnum::Eight:
+ case NumbersAndOperatorsEnum::Nine:
+ processedDigit = true;
+ break;
+
+ case NumbersAndOperatorsEnum::Add:
+ case NumbersAndOperatorsEnum::Subtract:
+ case NumbersAndOperatorsEnum::Multiply:
+ case NumbersAndOperatorsEnum::Divide:
+ isPreviousOperator = true;
+ break;
+ }
+
+ if (sendCommand)
+ {
+ sentEquals = (mappedNumOp == NumbersAndOperatorsEnum::Equals);
+ Command cmdenum = ConvertToOperatorsEnum(mappedNumOp);
+ m_standardCalculatorManager.SendCommand(cmdenum);
+
+ // The CalcEngine state machine won't allow the negate command to be sent before any
+ // other digits, so instead a flag is set and the command is sent after the first appropriate
+ // command.
+ if (sendNegate)
+ {
+ if (canSendNegate)
{
- if (canSendNegate)
- {
- Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum::Negate);
- m_standardCalculatorManager.SendCommand(cmdNegate);
- }
+ Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum::Negate);
+ m_standardCalculatorManager.SendCommand(cmdNegate);
+ }
- // Can't send negate on a leading zero, so wait until the appropriate time to send it.
- if (NumbersAndOperatorsEnum::Zero != mappedNumOp && NumbersAndOperatorsEnum::Decimal != mappedNumOp)
- {
- sendNegate = false;
- }
+ // Can't send negate on a leading zero, so wait until the appropriate time to send it.
+ if (NumbersAndOperatorsEnum::Zero != mappedNumOp && NumbersAndOperatorsEnum::Decimal != mappedNumOp)
+ {
+ sendNegate = false;
}
}
}
diff --git a/src/Calculator.sln b/src/Calculator.sln
index 329ff19f..47084340 100644
--- a/src/Calculator.sln
+++ b/src/Calculator.sln
@@ -18,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "CalcViewMo
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{D3BAED2C-4B07-4E1D-8807-9D6499450349}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorUITests", "CalculatorUITests\CalculatorUITests.csproj", "{B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@@ -102,6 +104,22 @@ Global
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.ActiveCfg = Release|Win32
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Build.0 = Release|Win32
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Deploy.0 = Release|Win32
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x64.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x86.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM64.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x64.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x64.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x86.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Calculator/Views/UnitConverter.xaml b/src/Calculator/Views/UnitConverter.xaml
index 1d52c3eb..a1a0a8d0 100644
--- a/src/Calculator/Views/UnitConverter.xaml
+++ b/src/Calculator/Views/UnitConverter.xaml
@@ -615,8 +615,7 @@
x:Uid="RefreshButtonText"
Foreground="{ThemeResource SystemControlHyperlinkBaseHighBrush}"
Click="CurrencyRefreshButton_Click"/>
-
-
+
diff --git a/src/CalculatorUITests/CalculatorSession.cs b/src/CalculatorUITests/CalculatorSession.cs
new file mode 100644
index 00000000..9e4caa9b
--- /dev/null
+++ b/src/CalculatorUITests/CalculatorSession.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using OpenQA.Selenium.Appium;
+using OpenQA.Selenium.Appium.Windows;
+using System;
+
+namespace CalculatorUITests
+{
+ public class CalculatorSession
+ {
+ // Note: append /wd/hub to the URL if you're directing the test at Appium
+ private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
+ private const string CalculatorAppId = "Microsoft.WindowsCalculator.Dev_8wekyb3d8bbwe!App";
+ protected static WindowsDriver session;
+
+ public static void Setup(TestContext context)
+ {
+ // Launch Calculator application if it is not yet launched
+ if (session == null)
+ {
+ // Create a new session to bring up an instance of the Calculator application
+ // Note: Multiple calculator windows (instances) share the same process Id
+ var options = new AppiumOptions();
+ options.AddAdditionalCapability("app", CalculatorAppId);
+ options.AddAdditionalCapability("deviceName", "WindowsPC");
+ session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), options);
+ session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(180);
+ Assert.IsNotNull(session);
+ }
+ }
+
+ public static void TearDown()
+ {
+ // Close the application and delete the session
+ if (session != null)
+ {
+ session.Quit();
+ session = null;
+ }
+ }
+ }
+}
diff --git a/src/CalculatorUITests/CalculatorUITests.csproj b/src/CalculatorUITests/CalculatorUITests.csproj
new file mode 100644
index 00000000..42ed8672
--- /dev/null
+++ b/src/CalculatorUITests/CalculatorUITests.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netcoreapp2.1
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/src/CalculatorUITests/CalculatorUITests.runsettings b/src/CalculatorUITests/CalculatorUITests.runsettings
new file mode 100644
index 00000000..ac9968d5
--- /dev/null
+++ b/src/CalculatorUITests/CalculatorUITests.runsettings
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/CalculatorUITests/ScenarioStandard.cs b/src/CalculatorUITests/ScenarioStandard.cs
new file mode 100644
index 00000000..8bc824a3
--- /dev/null
+++ b/src/CalculatorUITests/ScenarioStandard.cs
@@ -0,0 +1,112 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using OpenQA.Selenium.Appium.Windows;
+using System.Threading;
+using System;
+
+namespace CalculatorUITests
+{
+ [TestClass]
+ public class StandardModeTests : CalculatorSession
+ {
+ private static WindowsElement header;
+ private static WindowsElement calculatorResult;
+
+ [TestMethod]
+ public void Addition()
+ {
+ // Find the buttons by their names and click them in sequence to perform 1 + 7 = 8
+ session.FindElementByName("One").Click();
+ session.FindElementByName("Plus").Click();
+ session.FindElementByName("Seven").Click();
+ session.FindElementByName("Equals").Click();
+ Assert.AreEqual("8", GetCalculatorResultText());
+ }
+
+ [TestMethod]
+ public void Division()
+ {
+ // Find the buttons by their accessibility ids and click them in sequence to perform 88 / 11 = 8
+ session.FindElementByAccessibilityId("num8Button").Click();
+ session.FindElementByAccessibilityId("num8Button").Click();
+ session.FindElementByAccessibilityId("divideButton").Click();
+ session.FindElementByAccessibilityId("num1Button").Click();
+ session.FindElementByAccessibilityId("num1Button").Click();
+ session.FindElementByAccessibilityId("equalButton").Click();
+ Assert.AreEqual("8", GetCalculatorResultText());
+ }
+
+ [TestMethod]
+ public void Multiplication()
+ {
+ session.FindElementByAccessibilityId("num9Button").Click();
+ session.FindElementByAccessibilityId("multiplyButton").Click();
+ session.FindElementByAccessibilityId("num9Button").Click();
+ session.FindElementByAccessibilityId("equalButton").Click();
+ Assert.AreEqual("81", GetCalculatorResultText());
+ }
+
+ [TestMethod]
+ public void Subtraction()
+ {
+ // Find the buttons by their accessibility ids using XPath and click them in sequence to perform 9 - 1 = 8
+ session.FindElementByAccessibilityId("num9Button").Click();
+ session.FindElementByAccessibilityId("minusButton").Click();
+ session.FindElementByAccessibilityId("num1Button").Click();
+ session.FindElementByAccessibilityId("equalButton").Click();
+ Assert.AreEqual("8", GetCalculatorResultText());
+ }
+
+
+ [ClassInitialize]
+ public static void ClassInitialize(TestContext context)
+ {
+ // Create session to launch a Calculator window
+ Setup(context);
+ // Identify calculator mode by locating the header
+ try
+ {
+ header = session.FindElementByAccessibilityId("Header");
+ }
+ catch
+ {
+ header = session.FindElementByAccessibilityId("ContentPresenter");
+ }
+
+ // Ensure that calculator is in standard mode
+ if (!header.Text.Equals("Standard", StringComparison.OrdinalIgnoreCase))
+ {
+ session.FindElementByAccessibilityId("TogglePaneButton").Click();
+ Thread.Sleep(TimeSpan.FromSeconds(1));
+ var splitViewPane = session.FindElementByClassName("SplitViewPane");
+ splitViewPane.FindElementByName("Standard Calculator").Click();
+ Thread.Sleep(TimeSpan.FromSeconds(1));
+ Assert.IsTrue(header.Text.Equals("Standard", StringComparison.OrdinalIgnoreCase));
+ }
+
+ // Locate the calculatorResult element
+ calculatorResult = session.FindElementByAccessibilityId("CalculatorResults");
+ Assert.IsNotNull(calculatorResult);
+ }
+
+ [ClassCleanup]
+ public static void ClassCleanup()
+ {
+ TearDown();
+ }
+
+ [TestInitialize]
+ public void Clear()
+ {
+ session.FindElementByName("Clear").Click();
+ Assert.AreEqual("0", GetCalculatorResultText());
+ }
+
+ private string GetCalculatorResultText()
+ {
+ return calculatorResult.Text.Replace("Display is", string.Empty).Trim();
+ }
+ }
+}
diff --git a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
index 4c02dd05..0318f152 100644
--- a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
+++ b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
@@ -44,914 +44,677 @@ namespace DateCalculationUnitTests
DateTimeTestCase datetimeAddCase[c_addCases];
DateTimeTestCase datetimeSubtractCase[c_subtractCases];
+
// Test Class
- TEST_CLASS(DateCalculatorUnitTests){ public: TEST_CLASS_INITIALIZE(TestClassSetup){ /* Test Case Data */
-
- // Dates - DD.MM.YYYY
- /*31.12.9999*/ date[0].wYear = 9999;
- date[0].wMonth = 12;
- date[0].wDayOfWeek = 5;
- date[0].wDay = 31;
- date[0].wHour = 0;
- date[0].wMinute = 0;
- date[0].wSecond = 0;
- date[0].wMilliseconds = 0;
- /*30.12.9999*/ date[1].wYear = 9999;
- date[1].wMonth = 12;
- date[1].wDayOfWeek = 4;
- date[1].wDay = 30;
- date[1].wHour = 0;
- date[1].wMinute = 0;
- date[1].wSecond = 0;
- date[1].wMilliseconds = 0;
- /*31.12.9998*/ date[2].wYear = 9998;
- date[2].wMonth = 12;
- date[2].wDayOfWeek = 4;
- date[2].wDay = 31;
- date[2].wHour = 0;
- date[2].wMinute = 0;
- date[2].wSecond = 0;
- date[2].wMilliseconds = 0;
- /*01.01.1601*/ date[3].wYear = 1601;
- date[3].wMonth = 1;
- date[3].wDayOfWeek = 1;
- date[3].wDay = 1;
- date[3].wHour = 0;
- date[3].wMinute = 0;
- date[3].wSecond = 0;
- date[3].wMilliseconds = 0;
- /*02.01.1601*/ date[4].wYear = 1601;
- date[4].wMonth = 1;
- date[4].wDayOfWeek = 2;
- date[4].wDay = 2;
- date[4].wHour = 0;
- date[4].wMinute = 0;
- date[4].wSecond = 0;
- date[4].wMilliseconds = 0;
- /*10.05.2008*/ date[5].wYear = 2008;
- date[5].wMonth = 5;
- date[5].wDayOfWeek = 6;
- date[5].wDay = 10;
- date[5].wHour = 0;
- date[5].wMinute = 0;
- date[5].wSecond = 0;
- date[5].wMilliseconds = 0;
- /*10.03.2008*/ date[6].wYear = 2008;
- date[6].wMonth = 3;
- date[6].wDayOfWeek = 1;
- date[6].wDay = 10;
- date[6].wHour = 0;
- date[6].wMinute = 0;
- date[6].wSecond = 0;
- date[6].wMilliseconds = 0;
- /*29.02.2008*/ date[7].wYear = 2008;
- date[7].wMonth = 2;
- date[7].wDayOfWeek = 5;
- date[7].wDay = 29;
- date[7].wHour = 0;
- date[7].wMinute = 0;
- date[7].wSecond = 0;
- date[7].wMilliseconds = 0;
- /*28.02.2007*/ date[8].wYear = 2007;
- date[8].wMonth = 2;
- date[8].wDayOfWeek = 3;
- date[8].wDay = 28;
- date[8].wHour = 0;
- date[8].wMinute = 0;
- date[8].wSecond = 0;
- date[8].wMilliseconds = 0;
- /*10.03.2007*/ date[9].wYear = 2007;
- date[9].wMonth = 3;
- date[9].wDayOfWeek = 6;
- date[9].wDay = 10;
- date[9].wHour = 0;
- date[9].wMinute = 0;
- date[9].wSecond = 0;
- date[9].wMilliseconds = 0;
- /*10.05.2007*/ date[10].wYear = 2007;
- date[10].wMonth = 5;
- date[10].wDayOfWeek = 4;
- date[10].wDay = 10;
- date[10].wHour = 0;
- date[10].wMinute = 0;
- date[10].wSecond = 0;
- date[10].wMilliseconds = 0;
- /*29.01.2008*/ date[11].wYear = 2008;
- date[11].wMonth = 1;
- date[11].wDayOfWeek = 2;
- date[11].wDay = 29;
- date[11].wHour = 0;
- date[11].wMinute = 0;
- date[11].wSecond = 0;
- date[11].wMilliseconds = 0;
- /*28.01.2007*/ date[12].wYear = 2007;
- date[12].wMonth = 1;
- date[12].wDayOfWeek = 0;
- date[12].wDay = 28;
- date[12].wHour = 0;
- date[12].wMinute = 0;
- date[12].wSecond = 0;
- date[12].wMilliseconds = 0;
- /*31.01.2008*/ date[13].wYear = 2008;
- date[13].wMonth = 1;
- date[13].wDayOfWeek = 4;
- date[13].wDay = 31;
- date[13].wHour = 0;
- date[13].wMinute = 0;
- date[13].wSecond = 0;
- date[13].wMilliseconds = 0;
- /*31.03.2008*/ date[14].wYear = 2008;
- date[14].wMonth = 3;
- date[14].wDayOfWeek = 1;
- date[14].wDay = 31;
- date[14].wHour = 0;
- date[14].wMinute = 0;
- date[14].wSecond = 0;
- date[14].wMilliseconds = 0;
-
- // Date Differences
- dateDifference[0].year = 1;
- dateDifference[0].month = 1;
- dateDifference[1].month = 1;
- dateDifference[1].day = 10;
- dateDifference[2].day = 2;
- /*date[2]-[0]*/ dateDifference[3].week = 52;
- dateDifference[3].day = 1;
- /*date[2]-[0]*/ dateDifference[4].year = 1;
- dateDifference[5].day = 365;
- dateDifference[6].month = 1;
- dateDifference[7].month = 1;
- dateDifference[7].day = 2;
- dateDifference[8].day = 31;
- dateDifference[9].month = 11;
- dateDifference[9].day = 1;
- dateDifference[10].year = 8398;
- dateDifference[10].month = 11;
- dateDifference[10].day = 30;
- dateDifference[11].year = 2008;
- dateDifference[12].year = 7991;
- dateDifference[12].month = 11;
- dateDifference[13].week = 416998;
- dateDifference[13].day = 1;
-
- /* Test Cases */
-
- // Date Difference test cases
- datetimeDifftest[0].startDate = date[0];
- datetimeDifftest[0].endDate = date[3];
- datetimeDifftest[0].dateDiff = dateDifference[10];
- datetimeDifftest[1].startDate = date[0];
- datetimeDifftest[1].endDate = date[2];
- datetimeDifftest[1].dateDiff = dateDifference[5];
- datetimeDifftest[2].startDate = date[0];
- datetimeDifftest[2].endDate = date[2];
- datetimeDifftest[2].dateDiff = dateDifference[4];
- datetimeDifftest[3].startDate = date[0];
- datetimeDifftest[3].endDate = date[2];
- datetimeDifftest[3].dateDiff = dateDifference[3];
- datetimeDifftest[4].startDate = date[14];
- datetimeDifftest[4].endDate = date[7];
- datetimeDifftest[4].dateDiff = dateDifference[7];
- datetimeDifftest[5].startDate = date[14];
- datetimeDifftest[5].endDate = date[7];
- datetimeDifftest[5].dateDiff = dateDifference[8];
- datetimeDifftest[6].startDate = date[11];
- datetimeDifftest[6].endDate = date[8];
- datetimeDifftest[6].dateDiff = dateDifference[9];
- datetimeDifftest[7].startDate = date[13];
- datetimeDifftest[7].endDate = date[0];
- datetimeDifftest[7].dateDiff = dateDifference[12];
- datetimeDifftest[8].startDate = date[13];
- datetimeDifftest[8].endDate = date[0];
- datetimeDifftest[8].dateDiff = dateDifference[13];
-
- // Date Add Out of Bound test cases (Negative tests)
- /*OutofBound*/ datetimeBoundAdd[0].startDate = date[1];
- datetimeBoundAdd[0].endDate = date[0];
- datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
- /*OutofBound*/ datetimeBoundAdd[1].startDate = date[2];
- datetimeBoundAdd[1].endDate = date[0];
- datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
-
- // Date Subtract Out of Bound test cases (Negative tests)
- /*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3];
- datetimeBoundSubtract[0].endDate = date[0];
- datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
- /*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14];
- datetimeBoundSubtract[1].endDate = date[0];
- datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
-
- // Date Add test cases (Positive tests)
- datetimeAddCase[0].startDate = date[13];
- datetimeAddCase[0].endDate = date[7];
- datetimeAddCase[0].dateDiff = dateDifference[6]; // add
- datetimeAddCase[1].startDate = date[14];
- datetimeAddCase[1].endDate = date[5];
- datetimeAddCase[1].dateDiff = dateDifference[1]; // add
- datetimeAddCase[2].startDate = date[13];
- datetimeAddCase[2].endDate = date[6];
- datetimeAddCase[2].dateDiff = dateDifference[1]; // add
-
- // Date Subtract test cases (Positive tests)
- datetimeSubtractCase[0].startDate = date[14];
- datetimeSubtractCase[0].endDate = date[7];
- datetimeSubtractCase[0].dateDiff = dateDifference[6]; // subtract
- datetimeSubtractCase[1].startDate = date[6];
- datetimeSubtractCase[1].endDate = date[11];
- datetimeSubtractCase[1].dateDiff = dateDifference[1]; // subtract
- datetimeSubtractCase[2].startDate = date[9];
- datetimeSubtractCase[2].endDate = date[12];
- datetimeSubtractCase[2].dateDiff = dateDifference[1]; // subtract
-}
-
-/* Duration Between Two Date Tests -- Timediff obtained after calculation should be checked to be identical */
-TEST_METHOD(TestDateDiff)
-{
- // TODO - MSFT 10331900, fix this test
-
- // for (int testIndex = 0; testIndex < c_diffTestCase; testIndex++)
- //{
- // DateDifference diff;
- // DateUnit dateOutputFormat;
-
- // switch (testIndex)
- // {
- // case 0:
- // case 2:
- // dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
- // break;
- // case 1:
- // dateOutputFormat = DateUnit::Day;
- // break;
- // case 3:
- // case 8:
- // dateOutputFormat = DateUnit::Week | DateUnit::Day;
- // break;
- // case 7:
- // dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
- // break;
- // case 4:
- // case 6:
- // dateOutputFormat = DateUnit::Month | DateUnit::Day;
- // break;
- // case 5:
- // dateOutputFormat = DateUnit::Day;
- // break;
- // }
-
- // // Calculate the difference
- // m_DateCalcEngine.GetDateDifference(DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].startDate),
- // DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].endDate), dateOutputFormat, &diff);
-
- // // Assert for the result
- // bool areIdentical = true;
- // if (diff.year != datetimeDifftest[testIndex].dateDiff.year ||
- // diff.month != datetimeDifftest[testIndex].dateDiff.month ||
- // diff.week != datetimeDifftest[testIndex].dateDiff.week ||
- // diff.day != datetimeDifftest[testIndex].dateDiff.day)
- // {
- // areIdentical = false;
- // }
-
- // VERIFY_IS_TRUE(areIdentical);
- //}
-}
-
-/*Add Out of bound Tests*/
-TEST_METHOD(TestAddOob)
-{
- // TODO - MSFT 10331900, fix this test
-
- // for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
- //{
- // DateTime endDate;
-
- // // Add Duration
- // bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate),
- // datetimeBoundAdd[testIndex].dateDiff, &endDate);
-
- // // Assert for the result
- // VERIFY_IS_FALSE(isValid);
- //}
-}
-
-/*Subtract Out of bound Tests*/
-TEST_METHOD(TestSubtractOob)
-{
- for (int testIndex = 0; testIndex < c_numSubtractOobDate; testIndex++)
+ TEST_CLASS(DateCalculatorUnitTests)
{
- DateTime endDate;
+ public:
+ TEST_CLASS_INITIALIZE(TestClassSetup)
+ {
+ /* Test Case Data */
- // Subtract Duration
- bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate),
- datetimeBoundSubtract[testIndex].dateDiff, &endDate);
+ // Dates - DD.MM.YYYY
+ /*31.12.9999*/ date[0].wYear = 9999; date[0].wMonth = 12; date[0].wDayOfWeek = 5; date[0].wDay = 31; date[0].wHour = 0; date[0].wMinute = 0; date[0].wSecond = 0; date[0].wMilliseconds = 0;
+ /*30.12.9999*/ date[1].wYear = 9999; date[1].wMonth = 12; date[1].wDayOfWeek = 4; date[1].wDay = 30; date[1].wHour = 0; date[1].wMinute = 0; date[1].wSecond = 0; date[1].wMilliseconds = 0;
+ /*31.12.9998*/ date[2].wYear = 9998; date[2].wMonth = 12; date[2].wDayOfWeek = 4; date[2].wDay = 31; date[2].wHour = 0; date[2].wMinute = 0; date[2].wSecond = 0; date[2].wMilliseconds = 0;
+ /*01.01.1601*/ date[3].wYear = 1601; date[3].wMonth = 1; date[3].wDayOfWeek = 1; date[3].wDay = 1; date[3].wHour = 0; date[3].wMinute = 0; date[3].wSecond = 0; date[3].wMilliseconds = 0;
+ /*02.01.1601*/ date[4].wYear = 1601; date[4].wMonth = 1; date[4].wDayOfWeek = 2; date[4].wDay = 2; date[4].wHour = 0; date[4].wMinute = 0; date[4].wSecond = 0; date[4].wMilliseconds = 0;
+ /*10.05.2008*/ date[5].wYear = 2008; date[5].wMonth = 5; date[5].wDayOfWeek = 6; date[5].wDay = 10; date[5].wHour = 0; date[5].wMinute = 0; date[5].wSecond = 0; date[5].wMilliseconds = 0;
+ /*10.03.2008*/ date[6].wYear = 2008; date[6].wMonth = 3; date[6].wDayOfWeek = 1; date[6].wDay = 10; date[6].wHour = 0; date[6].wMinute = 0; date[6].wSecond = 0; date[6].wMilliseconds = 0;
+ /*29.02.2008*/ date[7].wYear = 2008; date[7].wMonth = 2; date[7].wDayOfWeek = 5; date[7].wDay = 29; date[7].wHour = 0; date[7].wMinute = 0; date[7].wSecond = 0; date[7].wMilliseconds = 0;
+ /*28.02.2007*/ date[8].wYear = 2007; date[8].wMonth = 2; date[8].wDayOfWeek = 3; date[8].wDay = 28; date[8].wHour = 0; date[8].wMinute = 0; date[8].wSecond = 0; date[8].wMilliseconds = 0;
+ /*10.03.2007*/ date[9].wYear = 2007; date[9].wMonth = 3; date[9].wDayOfWeek = 6; date[9].wDay = 10; date[9].wHour = 0; date[9].wMinute = 0; date[9].wSecond = 0; date[9].wMilliseconds = 0;
+ /*10.05.2007*/ date[10].wYear = 2007; date[10].wMonth = 5; date[10].wDayOfWeek = 4; date[10].wDay = 10; date[10].wHour = 0; date[10].wMinute = 0; date[10].wSecond = 0; date[10].wMilliseconds = 0;
+ /*29.01.2008*/ date[11].wYear = 2008; date[11].wMonth = 1; date[11].wDayOfWeek = 2; date[11].wDay = 29; date[11].wHour = 0; date[11].wMinute = 0; date[11].wSecond = 0; date[11].wMilliseconds = 0;
+ /*28.01.2007*/ date[12].wYear = 2007; date[12].wMonth = 1; date[12].wDayOfWeek = 0; date[12].wDay = 28; date[12].wHour = 0; date[12].wMinute = 0; date[12].wSecond = 0; date[12].wMilliseconds = 0;
+ /*31.01.2008*/ date[13].wYear = 2008; date[13].wMonth = 1; date[13].wDayOfWeek = 4; date[13].wDay = 31; date[13].wHour = 0; date[13].wMinute = 0; date[13].wSecond = 0; date[13].wMilliseconds = 0;
+ /*31.03.2008*/ date[14].wYear = 2008; date[14].wMonth = 3; date[14].wDayOfWeek = 1; date[14].wDay = 31; date[14].wHour = 0; date[14].wMinute = 0; date[14].wSecond = 0; date[14].wMilliseconds = 0;
- // Assert for the result
- VERIFY_IS_FALSE(isValid);
- }
-}
+ // Date Differences
+ dateDifference[0].year = 1; dateDifference[0].month = 1;
+ dateDifference[1].month = 1; dateDifference[1].day = 10;
+ dateDifference[2].day = 2;
+ /*date[2]-[0]*/ dateDifference[3].week = 52; dateDifference[3].day = 1;
+ /*date[2]-[0]*/ dateDifference[4].year = 1;
+ dateDifference[5].day = 365;
+ dateDifference[6].month = 1;
+ dateDifference[7].month = 1; dateDifference[7].day = 2;
+ dateDifference[8].day = 31;
+ dateDifference[9].month = 11; dateDifference[9].day = 1;
+ dateDifference[10].year = 8398; dateDifference[10].month = 11; dateDifference[10].day = 30;
+ dateDifference[11].year = 2008;
+ dateDifference[12].year = 7991; dateDifference[12].month = 11;
+ dateDifference[13].week = 416998; dateDifference[13].day = 1;
-// Add Tests
-TEST_METHOD(TestAddition)
-{
- // TODO - MSFT 10331900, fix this test
- // for (int testIndex = 0; testIndex < c_addCases; testIndex++)
- //{
- // DateTime endDate;
- // // Add Duration
- // bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeAddCase[testIndex].startDate),
- // datetimeAddCase[testIndex].dateDiff, &endDate);
+ /* Test Cases */
- // // Assert for the result
- // VERIFY_IS_TRUE(isValid);
+ // Date Difference test cases
+ datetimeDifftest[0].startDate = date[0]; datetimeDifftest[0].endDate = date[3]; datetimeDifftest[0].dateDiff = dateDifference[10];
+ datetimeDifftest[1].startDate = date[0]; datetimeDifftest[1].endDate = date[2]; datetimeDifftest[1].dateDiff = dateDifference[5];
+ datetimeDifftest[2].startDate = date[0]; datetimeDifftest[2].endDate = date[2]; datetimeDifftest[2].dateDiff = dateDifference[4];
+ datetimeDifftest[3].startDate = date[0]; datetimeDifftest[3].endDate = date[2]; datetimeDifftest[3].dateDiff = dateDifference[3];
+ datetimeDifftest[4].startDate = date[14]; datetimeDifftest[4].endDate = date[7]; datetimeDifftest[4].dateDiff = dateDifference[7];
+ datetimeDifftest[5].startDate = date[14]; datetimeDifftest[5].endDate = date[7]; datetimeDifftest[5].dateDiff = dateDifference[8];
+ datetimeDifftest[6].startDate = date[11]; datetimeDifftest[6].endDate = date[8]; datetimeDifftest[6].dateDiff = dateDifference[9];
+ datetimeDifftest[7].startDate = date[13]; datetimeDifftest[7].endDate = date[0]; datetimeDifftest[7].dateDiff = dateDifference[12];
+ datetimeDifftest[8].startDate = date[13]; datetimeDifftest[8].endDate = date[0]; datetimeDifftest[8].dateDiff = dateDifference[13];
- // SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
- // if (systemTime.wYear != datetimeAddCase[testIndex].endDate.wYear ||
- // systemTime.wMonth != datetimeAddCase[testIndex].endDate.wMonth ||
- // systemTime.wDay != datetimeAddCase[testIndex].endDate.wDay ||
- // systemTime.wDayOfWeek != datetimeAddCase[testIndex].endDate.wDayOfWeek)
- // {
- // isValid = false;
- // }
+ // Date Add Out of Bound test cases (Negative tests)
+ /*OutofBound*/ datetimeBoundAdd[0].startDate = date[1]; datetimeBoundAdd[0].endDate = date[0]; datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
+ /*OutofBound*/ datetimeBoundAdd[1].startDate = date[2]; datetimeBoundAdd[1].endDate = date[0]; datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
- // VERIFY_IS_TRUE(isValid);
- //}
-}
+ // Date Subtract Out of Bound test cases (Negative tests)
+ /*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3]; datetimeBoundSubtract[0].endDate = date[0]; datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
+ /*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14]; datetimeBoundSubtract[1].endDate = date[0]; datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
-// Subtract Tests
-TEST_METHOD(TestSubtraction)
-{
- // TODO - MSFT 10331900, fix this test
+ // Date Add test cases (Positive tests)
+ datetimeAddCase[0].startDate = date[13]; datetimeAddCase[0].endDate = date[7]; datetimeAddCase[0].dateDiff = dateDifference[6];// add
+ datetimeAddCase[1].startDate = date[14]; datetimeAddCase[1].endDate = date[5]; datetimeAddCase[1].dateDiff = dateDifference[1];// add
+ datetimeAddCase[2].startDate = date[13]; datetimeAddCase[2].endDate = date[6]; datetimeAddCase[2].dateDiff = dateDifference[1];// add
- // for (int testIndex = 0; testIndex < c_subtractCases; testIndex++)
- //{
- // DateTime endDate;
+ // Date Subtract test cases (Positive tests)
+ datetimeSubtractCase[0].startDate = date[14]; datetimeSubtractCase[0].endDate = date[7]; datetimeSubtractCase[0].dateDiff = dateDifference[6];// subtract
+ datetimeSubtractCase[1].startDate = date[6]; datetimeSubtractCase[1].endDate = date[11]; datetimeSubtractCase[1].dateDiff = dateDifference[1];// subtract
+ datetimeSubtractCase[2].startDate = date[9]; datetimeSubtractCase[2].endDate = date[12]; datetimeSubtractCase[2].dateDiff = dateDifference[1];// subtract
+ }
- // // Subtract Duration
- // bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeSubtractCase[testIndex].startDate),
- // datetimeSubtractCase[testIndex].dateDiff, &endDate);
- // // assert for the result
- // VERIFY_IS_TRUE(isValid);
+ /* Duration Between Two Date Tests -- Timediff obtained after calculation should be checked to be identical */
+ TEST_METHOD(TestDateDiff)
+ {
+ // TODO - MSFT 10331900, fix this test
- // SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
- // if (systemTime.wYear != datetimeSubtractCase[testIndex].endDate.wYear ||
- // systemTime.wMonth != datetimeSubtractCase[testIndex].endDate.wMonth ||
- // systemTime.wDay != datetimeSubtractCase[testIndex].endDate.wDay ||
- // systemTime.wDayOfWeek != datetimeSubtractCase[testIndex].endDate.wDayOfWeek)
- // {
- // isValid = false;
- // }
+ //for (int testIndex = 0; testIndex < c_diffTestCase; testIndex++)
+ //{
+ // DateDifference diff;
+ // DateUnit dateOutputFormat;
- // VERIFY_IS_TRUE(isValid);
- //}
-}
+ // switch (testIndex)
+ // {
+ // case 0:
+ // case 2:
+ // dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
+ // break;
+ // case 1:
+ // dateOutputFormat = DateUnit::Day;
+ // break;
+ // case 3:
+ // case 8:
+ // dateOutputFormat = DateUnit::Week | DateUnit::Day;
+ // break;
+ // case 7:
+ // dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
+ // break;
+ // case 4:
+ // case 6:
+ // dateOutputFormat = DateUnit::Month | DateUnit::Day;
+ // break;
+ // case 5:
+ // dateOutputFormat = DateUnit::Day;
+ // break;
+ // }
-private:
-}
-;
+ // // Calculate the difference
+ // m_DateCalcEngine.GetDateDifference(DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].startDate), DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].endDate), dateOutputFormat, &diff);
-TEST_CLASS(DateCalculatorViewModelTests){ public: TEST_CLASS_INITIALIZE(TestClassSetup){ /* Test Case Data */
+ // // Assert for the result
+ // bool areIdentical = true;
+ // if (diff.year != datetimeDifftest[testIndex].dateDiff.year ||
+ // diff.month != datetimeDifftest[testIndex].dateDiff.month ||
+ // diff.week != datetimeDifftest[testIndex].dateDiff.week ||
+ // diff.day != datetimeDifftest[testIndex].dateDiff.day)
+ // {
+ // areIdentical = false;
+ // }
- // Dates - DD.MM.YYYY
- /*31.12.9999*/ date[0].wYear = 9999;
-date[0].wMonth = 12;
-date[0].wDayOfWeek = 5;
-date[0].wDay = 31;
-date[0].wHour = 0;
-date[0].wMinute = 0;
-date[0].wSecond = 0;
-date[0].wMilliseconds = 0;
-/*30.12.9999*/ date[1].wYear = 9999;
-date[1].wMonth = 12;
-date[1].wDayOfWeek = 4;
-date[1].wDay = 30;
-date[1].wHour = 0;
-date[1].wMinute = 0;
-date[1].wSecond = 0;
-date[1].wMilliseconds = 0;
-/*31.12.9998*/ date[2].wYear = 9998;
-date[2].wMonth = 12;
-date[2].wDayOfWeek = 4;
-date[2].wDay = 31;
-date[2].wHour = 0;
-date[2].wMinute = 0;
-date[2].wSecond = 0;
-date[2].wMilliseconds = 0;
-/*01.01.1601*/ date[3].wYear = 1601;
-date[3].wMonth = 1;
-date[3].wDayOfWeek = 1;
-date[3].wDay = 1;
-date[3].wHour = 0;
-date[3].wMinute = 0;
-date[3].wSecond = 0;
-date[3].wMilliseconds = 0;
-/*02.01.1601*/ date[4].wYear = 1601;
-date[4].wMonth = 1;
-date[4].wDayOfWeek = 2;
-date[4].wDay = 2;
-date[4].wHour = 0;
-date[4].wMinute = 0;
-date[4].wSecond = 0;
-date[4].wMilliseconds = 0;
-/*10.05.2008*/ date[5].wYear = 2008;
-date[5].wMonth = 5;
-date[5].wDayOfWeek = 6;
-date[5].wDay = 10;
-date[5].wHour = 0;
-date[5].wMinute = 0;
-date[5].wSecond = 0;
-date[5].wMilliseconds = 0;
-/*10.03.2008*/ date[6].wYear = 2008;
-date[6].wMonth = 3;
-date[6].wDayOfWeek = 1;
-date[6].wDay = 10;
-date[6].wHour = 0;
-date[6].wMinute = 0;
-date[6].wSecond = 0;
-date[6].wMilliseconds = 0;
-/*29.02.2008*/ date[7].wYear = 2008;
-date[7].wMonth = 2;
-date[7].wDayOfWeek = 5;
-date[7].wDay = 29;
-date[7].wHour = 0;
-date[7].wMinute = 0;
-date[7].wSecond = 0;
-date[7].wMilliseconds = 0;
-/*28.02.2007*/ date[8].wYear = 2007;
-date[8].wMonth = 2;
-date[8].wDayOfWeek = 3;
-date[8].wDay = 28;
-date[8].wHour = 0;
-date[8].wMinute = 0;
-date[8].wSecond = 0;
-date[8].wMilliseconds = 0;
-/*10.03.2007*/ date[9].wYear = 2007;
-date[9].wMonth = 3;
-date[9].wDayOfWeek = 6;
-date[9].wDay = 10;
-date[9].wHour = 0;
-date[9].wMinute = 0;
-date[9].wSecond = 0;
-date[9].wMilliseconds = 0;
-/*10.05.2007*/ date[10].wYear = 2007;
-date[10].wMonth = 5;
-date[10].wDayOfWeek = 4;
-date[10].wDay = 10;
-date[10].wHour = 0;
-date[10].wMinute = 0;
-date[10].wSecond = 0;
-date[10].wMilliseconds = 0;
-/*29.01.2008*/ date[11].wYear = 2008;
-date[11].wMonth = 1;
-date[11].wDayOfWeek = 2;
-date[11].wDay = 29;
-date[11].wHour = 0;
-date[11].wMinute = 0;
-date[11].wSecond = 0;
-date[11].wMilliseconds = 0;
-/*28.01.2007*/ date[12].wYear = 2007;
-date[12].wMonth = 1;
-date[12].wDayOfWeek = 0;
-date[12].wDay = 28;
-date[12].wHour = 0;
-date[12].wMinute = 0;
-date[12].wSecond = 0;
-date[12].wMilliseconds = 0;
-/*31.01.2008*/ date[13].wYear = 2008;
-date[13].wMonth = 1;
-date[13].wDayOfWeek = 4;
-date[13].wDay = 31;
-date[13].wHour = 0;
-date[13].wMinute = 0;
-date[13].wSecond = 0;
-date[13].wMilliseconds = 0;
-/*31.03.2008*/ date[14].wYear = 2008;
-date[14].wMonth = 3;
-date[14].wDayOfWeek = 1;
-date[14].wDay = 31;
-date[14].wHour = 0;
-date[14].wMinute = 0;
-date[14].wSecond = 0;
-date[14].wMilliseconds = 0;
+ // VERIFY_IS_TRUE(areIdentical);
+ //}
+ }
-// Date Differences
-dateDifference[0].year = 1;
-dateDifference[0].month = 1;
-dateDifference[1].month = 1;
-dateDifference[1].day = 10;
-dateDifference[2].day = 2;
-/*date[2]-[0]*/ dateDifference[3].week = 52;
-dateDifference[3].day = 1;
-/*date[2]-[0]*/ dateDifference[4].year = 1;
-dateDifference[5].day = 365;
-dateDifference[6].month = 1;
-dateDifference[7].month = 1;
-dateDifference[7].day = 2;
-dateDifference[8].day = 31;
-dateDifference[9].month = 11;
-dateDifference[9].day = 1;
-dateDifference[10].year = 8398;
-dateDifference[10].month = 11;
-dateDifference[10].day = 30;
-dateDifference[11].year = 2008;
-dateDifference[12].year = 7991;
-dateDifference[12].month = 11;
-dateDifference[13].week = 416998;
-dateDifference[13].day = 1;
+ /*Add Out of bound Tests*/
+ TEST_METHOD(TestAddOob)
+ {
+ // TODO - MSFT 10331900, fix this test
-/* Test Cases */
+ //for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
+ //{
+ // DateTime endDate;
-// Date Difference test cases
-datetimeDifftest[0].startDate = date[0];
-datetimeDifftest[0].endDate = date[3];
-datetimeDifftest[0].dateDiff = dateDifference[10];
-datetimeDifftest[1].startDate = date[0];
-datetimeDifftest[1].endDate = date[2];
-datetimeDifftest[1].dateDiff = dateDifference[5];
-datetimeDifftest[2].startDate = date[0];
-datetimeDifftest[2].endDate = date[2];
-datetimeDifftest[2].dateDiff = dateDifference[4];
-datetimeDifftest[3].startDate = date[0];
-datetimeDifftest[3].endDate = date[2];
-datetimeDifftest[3].dateDiff = dateDifference[3];
-datetimeDifftest[4].startDate = date[14];
-datetimeDifftest[4].endDate = date[7];
-datetimeDifftest[4].dateDiff = dateDifference[7];
-datetimeDifftest[5].startDate = date[14];
-datetimeDifftest[5].endDate = date[7];
-datetimeDifftest[5].dateDiff = dateDifference[8];
-datetimeDifftest[6].startDate = date[11];
-datetimeDifftest[6].endDate = date[8];
-datetimeDifftest[6].dateDiff = dateDifference[9];
-datetimeDifftest[7].startDate = date[13];
-datetimeDifftest[7].endDate = date[0];
-datetimeDifftest[7].dateDiff = dateDifference[12];
-datetimeDifftest[8].startDate = date[13];
-datetimeDifftest[8].endDate = date[0];
-datetimeDifftest[8].dateDiff = dateDifference[13];
+ // // Add Duration
+ // bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate), datetimeBoundAdd[testIndex].dateDiff, &endDate);
-// Date Add Out of Bound test cases (Negative tests)
-/*OutofBound*/ datetimeBoundAdd[0].startDate = date[1];
-datetimeBoundAdd[0].endDate = date[0];
-datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
-/*OutofBound*/ datetimeBoundAdd[1].startDate = date[2];
-datetimeBoundAdd[1].endDate = date[0];
-datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
+ // // Assert for the result
+ // VERIFY_IS_FALSE(isValid);
+ //}
+ }
-// Date Subtract Out of Bound test cases (Negative tests)
-/*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3];
-datetimeBoundSubtract[0].endDate = date[0];
-datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
-/*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14];
-datetimeBoundSubtract[1].endDate = date[0];
-datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
+ /*Subtract Out of bound Tests*/
+ TEST_METHOD(TestSubtractOob)
+ {
+ for (int testIndex = 0; testIndex< c_numSubtractOobDate; testIndex++)
+ {
+ DateTime endDate;
-// Date Add test cases (Positive tests)
-datetimeAddCase[0].startDate = date[13];
-datetimeAddCase[0].endDate = date[7];
-datetimeAddCase[0].dateDiff = dateDifference[6]; // add
-datetimeAddCase[1].startDate = date[14];
-datetimeAddCase[1].endDate = date[5];
-datetimeAddCase[1].dateDiff = dateDifference[1]; // add
-datetimeAddCase[2].startDate = date[13];
-datetimeAddCase[2].endDate = date[6];
-datetimeAddCase[2].dateDiff = dateDifference[1]; // add
+ // Subtract Duration
+ bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate), datetimeBoundSubtract[testIndex].dateDiff, &endDate);
-// Date Subtract test cases (Positive tests)
-datetimeSubtractCase[0].startDate = date[14];
-datetimeSubtractCase[0].endDate = date[7];
-datetimeSubtractCase[0].dateDiff = dateDifference[6]; // subtract
-datetimeSubtractCase[1].startDate = date[6];
-datetimeSubtractCase[1].endDate = date[11];
-datetimeSubtractCase[1].dateDiff = dateDifference[1]; // subtract
-datetimeSubtractCase[2].startDate = date[9];
-datetimeSubtractCase[2].endDate = date[12];
-datetimeSubtractCase[2].dateDiff = dateDifference[1]; // subtract
-}
+ // Assert for the result
+ VERIFY_IS_FALSE(isValid);
+ }
+ }
-TEST_METHOD(DateCalcViewModelInitializationTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
+ // Add Tests
+ TEST_METHOD(TestAddition)
+ {
+ // TODO - MSFT 10331900, fix this test
- // Check for the initialized values
- VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
- VERIFY_IS_TRUE(viewModel->IsAddMode);
+ //for (int testIndex = 0; testIndex < c_addCases; testIndex++)
+ //{
+ // DateTime endDate;
- VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
- VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
- VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
+ // // Add Duration
+ // bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeAddCase[testIndex].startDate), datetimeAddCase[testIndex].dateDiff, &endDate);
- VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
- VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
- VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
+ // // Assert for the result
+ // VERIFY_IS_TRUE(isValid);
- VERIFY_IS_TRUE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
- VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+ // SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
+ // if (systemTime.wYear != datetimeAddCase[testIndex].endDate.wYear ||
+ // systemTime.wMonth != datetimeAddCase[testIndex].endDate.wMonth ||
+ // systemTime.wDay != datetimeAddCase[testIndex].endDate.wDay ||
+ // systemTime.wDayOfWeek != datetimeAddCase[testIndex].endDate.wDayOfWeek)
+ // {
+ // isValid = false;
+ // }
- VERIFY_IS_NULL(viewModel->StrDateResult);
-}
+ // VERIFY_IS_TRUE(isValid);
+ //}
+ }
-TEST_METHOD(DateCalcViewModelAddSubtractInitTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
- viewModel->IsDateDiffMode = false;
+ // Subtract Tests
+ TEST_METHOD(TestSubtraction)
+ {
+ // TODO - MSFT 10331900, fix this test
- // Check for the initialized values
- VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
- VERIFY_IS_TRUE(viewModel->IsAddMode);
+ //for (int testIndex = 0; testIndex < c_subtractCases; testIndex++)
+ //{
+ // DateTime endDate;
- VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
- VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
- VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
+ // // Subtract Duration
+ // bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeSubtractCase[testIndex].startDate), datetimeSubtractCase[testIndex].dateDiff, &endDate);
- VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
- VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
- VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
+ // // assert for the result
+ // VERIFY_IS_TRUE(isValid);
- VERIFY_IS_TRUE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
- VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+ // SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
+ // if (systemTime.wYear != datetimeSubtractCase[testIndex].endDate.wYear ||
+ // systemTime.wMonth != datetimeSubtractCase[testIndex].endDate.wMonth ||
+ // systemTime.wDay != datetimeSubtractCase[testIndex].endDate.wDay ||
+ // systemTime.wDayOfWeek != datetimeSubtractCase[testIndex].endDate.wDayOfWeek)
+ // {
+ // isValid = false;
+ // }
- VERIFY_IS_NOT_NULL(viewModel->StrDateResult);
- VERIFY_IS_TRUE(StringReference(L"") != viewModel->StrDateResult);
-}
+ // VERIFY_IS_TRUE(isValid);
+ //}
+ }
-TEST_METHOD(DateCalcViewModelDateDiffDaylightSavingTimeTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
+ private:
- 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)
-{
- // TODO - MSFT 10331900, fix this test
- // A few issues to be investigated..
- // The date returned by DateUtils::GetLongDate can be a different string than expected
- // based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
- // doesn't format according to UTC. If it did, the test would still be incorrect because
- // the ViewModel is not necessarily in UTC.
- //
- // The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
- // the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
- // This means testing a specific date here, is *not* the same as selecting that date in the app.
-
- // auto viewModel = ref new DateCalculatorViewModel();
- // viewModel->Initialize();
-
- // viewModel->IsDateDiffMode = false;
- // viewModel->IsAddMode = true;
- // VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
- // VERIFY_IS_TRUE(viewModel->IsAddMode);
-
- // viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeAddCase[0].startDate);
- // viewModel->DaysOffset = datetimeAddCase[0].dateDiff.day;
- // viewModel->MonthsOffset = datetimeAddCase[0].dateDiff.month;
- // viewModel->YearsOffset = datetimeAddCase[0].dateDiff.year;
-
- //// Assert for the result
- // VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
-}
-
-TEST_METHOD(DateCalcViewModelSubtractTest)
-{
- // TODO - MSFT 10331900, fix this test
- // A few issues to be investigated..
- // The date returned by DateUtils::GetLongDate can be a different string than expected
- // based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
- // doesn't format according to UTC. If it did, the test would still be incorrect because
- // the ViewModel is not necessarily in UTC.
- //
- // The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
- // the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
- // This means testing a specific date here, is *not* the same as selecting that date in the app.
-
- // auto viewModel = ref new DateCalculatorViewModel();
- // viewModel->Initialize();
-
- // viewModel->IsDateDiffMode = false;
- // viewModel->IsAddMode = false;
- // VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
- // VERIFY_IS_FALSE(viewModel->IsAddMode);
-
- // viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeSubtractCase[0].startDate);
- // viewModel->DaysOffset = datetimeSubtractCase[0].dateDiff.day;
- // viewModel->MonthsOffset = datetimeSubtractCase[0].dateDiff.month;
- // viewModel->YearsOffset = datetimeSubtractCase[0].dateDiff.year;
-
- //// Assert for the result
- // VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
-}
-
-TEST_METHOD(DateCalcViewModelAddOobTest)
-{
- // TODO - MSFT 10331900, fix this test
- // Curiously enough, this test fails because it fails to go Oob.
- // Possibly need to update test to use a new max date.
-
- // auto viewModel = ref new DateCalculatorViewModel();
- // viewModel->Initialize();
-
- // viewModel->IsDateDiffMode = false;
- // viewModel->IsAddMode = true;
- // VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
- // VERIFY_IS_TRUE(viewModel->IsAddMode);
-
- // for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
- //{
- // viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate);
- // viewModel->DaysOffset = datetimeBoundAdd[testIndex].dateDiff.day;
- // viewModel->MonthsOffset = datetimeBoundAdd[testIndex].dateDiff.month;
- // viewModel->YearsOffset = datetimeBoundAdd[testIndex].dateDiff.year;
-
- // // Assert for the result
- // VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
- //}
-}
-
-TEST_METHOD(DateCalcViewModelSubtractOobTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
-
- viewModel->IsDateDiffMode = false;
- viewModel->IsAddMode = false;
- VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
- VERIFY_IS_FALSE(viewModel->IsAddMode);
-
- for (int testIndex = 0; testIndex < c_numSubtractOobDate; testIndex++)
+ TEST_CLASS(DateCalculatorViewModelTests)
{
- viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate);
- viewModel->DaysOffset = datetimeBoundSubtract[testIndex].dateDiff.day;
- viewModel->MonthsOffset = datetimeBoundSubtract[testIndex].dateDiff.month;
- viewModel->YearsOffset = datetimeBoundSubtract[testIndex].dateDiff.year;
+ public:
+ TEST_CLASS_INITIALIZE(TestClassSetup)
+ {
+ /* Test Case Data */
- // Assert for the result
- VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
- }
-}
-
-TEST_METHOD(DateCalcViewModelDateDiffIgnoreSignTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
-
- viewModel->IsDateDiffMode = true;
- VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
-
- viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[10]);
- viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[6]);
-
- VERIFY_IS_FALSE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays);
- VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult);
- viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[6]);
- viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[10]);
- VERIFY_IS_FALSE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays);
- VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult);
-}
-
-TEST_METHOD(DateCalcViewModelDateDiffTest)
-{
- // TODO - MSFT 10331900, fix this test
- // The last VERIFY checks with expected value "8398 years, 11 months, 4 weeks, 2 days"
- // The viewmodel result is something like "8398 years, 12 months, 6568892 weeks, 1 day",
- // which shows there is a problem with the viewmodel's reduction algorithm.
-
- // auto viewModel = ref new DateCalculatorViewModel();
- // viewModel->Initialize();
-
- // viewModel->IsDateDiffMode = true;
- // VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
-
- // viewModel->FromDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].startDate);
- // viewModel->ToDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].endDate);
-
- //// Assert for the result
- // VERIFY_IS_FALSE(viewModel->IsDiffInDays);
- // VERIFY_ARE_EQUAL(StringReference(L"3067670 days"), viewModel->StrDateDiffResultInDays);
- // VERIFY_ARE_EQUAL(StringReference(L"8398 years, 11 months, 4 weeks, 2 days"), viewModel->StrDateDiffResult);
-}
-
-TEST_METHOD(DateCalcViewModelDateDiffResultInPositiveDaysTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
-
- viewModel->IsDateDiffMode = true;
- VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
-
- viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[1]);
- viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[0]);
-
- // Assert for the result
- VERIFY_IS_TRUE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
- VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
-}
-
-TEST_METHOD(DateCalcViewModelDateDiffFromDateHigherThanToDate)
-{
- auto viewModel = ref new DateCalculatorViewModel();
-
- viewModel->IsDateDiffMode = true;
- VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
-
- viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[0]);
- viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[1]);
-
- // Assert for the result
- VERIFY_IS_TRUE(viewModel->IsDiffInDays);
- VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
- VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
-}
-
-// Tests that the automation name for the resulting date in Add Mode
-// contains the DayOfWeek, Day, Month, and Year
-TEST_METHOD(DateCalcViewModelAddSubtractResultAutomationNameTest)
-{
- auto viewModel = ref new DateCalculatorViewModel();
-
- auto cal = ref new Calendar();
- cal->Year = 2007;
- cal->Month = 5;
- cal->Day = 10;
- cal->Hour = 12;
- cal->Period = 2;
- cal->Nanosecond = 0;
- cal->Second = 0;
-
- DateTime startDate = cal->GetDateTime();
- viewModel->StartDate = startDate;
-
- viewModel->IsDateDiffMode = false;
- viewModel->IsAddMode = true;
-
- wstring actualValue = viewModel->StrDateResultAutomationName->Data();
-
- // Verify each component is present in the result
- wstring components[] = { L"dayofweek.full", L"month.full", L"year.full", L"day" };
-
- for (const wstring& component : components)
- {
- auto formatter = ref new DateTimeFormatter(ref new String(component.c_str()));
- wstring expectedValue = formatter->Format(startDate)->Data();
- wstring message = L"Verifying " + component + L" is present in the result";
- VERIFY_IS_TRUE(actualValue.find(expectedValue) != wstring::npos, message.c_str());
- }
-}
-}
-;
+ // Dates - DD.MM.YYYY
+ /*31.12.9999*/ date[0].wYear = 9999; date[0].wMonth = 12; date[0].wDayOfWeek = 5; date[0].wDay = 31; date[0].wHour = 0; date[0].wMinute = 0; date[0].wSecond = 0; date[0].wMilliseconds = 0;
+ /*30.12.9999*/ date[1].wYear = 9999; date[1].wMonth = 12; date[1].wDayOfWeek = 4; date[1].wDay = 30; date[1].wHour = 0; date[1].wMinute = 0; date[1].wSecond = 0; date[1].wMilliseconds = 0;
+ /*31.12.9998*/ date[2].wYear = 9998; date[2].wMonth = 12; date[2].wDayOfWeek = 4; date[2].wDay = 31; date[2].wHour = 0; date[2].wMinute = 0; date[2].wSecond = 0; date[2].wMilliseconds = 0;
+ /*01.01.1601*/ date[3].wYear = 1601; date[3].wMonth = 1; date[3].wDayOfWeek = 1; date[3].wDay = 1; date[3].wHour = 0; date[3].wMinute = 0; date[3].wSecond = 0; date[3].wMilliseconds = 0;
+ /*02.01.1601*/ date[4].wYear = 1601; date[4].wMonth = 1; date[4].wDayOfWeek = 2; date[4].wDay = 2; date[4].wHour = 0; date[4].wMinute = 0; date[4].wSecond = 0; date[4].wMilliseconds = 0;
+ /*10.05.2008*/ date[5].wYear = 2008; date[5].wMonth = 5; date[5].wDayOfWeek = 6; date[5].wDay = 10; date[5].wHour = 0; date[5].wMinute = 0; date[5].wSecond = 0; date[5].wMilliseconds = 0;
+ /*10.03.2008*/ date[6].wYear = 2008; date[6].wMonth = 3; date[6].wDayOfWeek = 1; date[6].wDay = 10; date[6].wHour = 0; date[6].wMinute = 0; date[6].wSecond = 0; date[6].wMilliseconds = 0;
+ /*29.02.2008*/ date[7].wYear = 2008; date[7].wMonth = 2; date[7].wDayOfWeek = 5; date[7].wDay = 29; date[7].wHour = 0; date[7].wMinute = 0; date[7].wSecond = 0; date[7].wMilliseconds = 0;
+ /*28.02.2007*/ date[8].wYear = 2007; date[8].wMonth = 2; date[8].wDayOfWeek = 3; date[8].wDay = 28; date[8].wHour = 0; date[8].wMinute = 0; date[8].wSecond = 0; date[8].wMilliseconds = 0;
+ /*10.03.2007*/ date[9].wYear = 2007; date[9].wMonth = 3; date[9].wDayOfWeek = 6; date[9].wDay = 10; date[9].wHour = 0; date[9].wMinute = 0; date[9].wSecond = 0; date[9].wMilliseconds = 0;
+ /*10.05.2007*/ date[10].wYear = 2007; date[10].wMonth = 5; date[10].wDayOfWeek = 4; date[10].wDay = 10; date[10].wHour = 0; date[10].wMinute = 0; date[10].wSecond = 0; date[10].wMilliseconds = 0;
+ /*29.01.2008*/ date[11].wYear = 2008; date[11].wMonth = 1; date[11].wDayOfWeek = 2; date[11].wDay = 29; date[11].wHour = 0; date[11].wMinute = 0; date[11].wSecond = 0; date[11].wMilliseconds = 0;
+ /*28.01.2007*/ date[12].wYear = 2007; date[12].wMonth = 1; date[12].wDayOfWeek = 0; date[12].wDay = 28; date[12].wHour = 0; date[12].wMinute = 0; date[12].wSecond = 0; date[12].wMilliseconds = 0;
+ /*31.01.2008*/ date[13].wYear = 2008; date[13].wMonth = 1; date[13].wDayOfWeek = 4; date[13].wDay = 31; date[13].wHour = 0; date[13].wMinute = 0; date[13].wSecond = 0; date[13].wMilliseconds = 0;
+ /*31.03.2008*/ date[14].wYear = 2008; date[14].wMonth = 3; date[14].wDayOfWeek = 1; date[14].wDay = 31; date[14].wHour = 0; date[14].wMinute = 0; date[14].wSecond = 0; date[14].wMilliseconds = 0;
+
+ // Date Differences
+ dateDifference[0].year = 1; dateDifference[0].month = 1;
+ dateDifference[1].month = 1; dateDifference[1].day = 10;
+ dateDifference[2].day = 2;
+ /*date[2]-[0]*/ dateDifference[3].week = 52; dateDifference[3].day = 1;
+ /*date[2]-[0]*/ dateDifference[4].year = 1;
+ dateDifference[5].day = 365;
+ dateDifference[6].month = 1;
+ dateDifference[7].month = 1; dateDifference[7].day = 2;
+ dateDifference[8].day = 31;
+ dateDifference[9].month = 11; dateDifference[9].day = 1;
+ dateDifference[10].year = 8398; dateDifference[10].month = 11; dateDifference[10].day = 30;
+ dateDifference[11].year = 2008;
+ dateDifference[12].year = 7991; dateDifference[12].month = 11;
+ dateDifference[13].week = 416998; dateDifference[13].day = 1;
+
+
+
+ /* Test Cases */
+
+ // Date Difference test cases
+ datetimeDifftest[0].startDate = date[0]; datetimeDifftest[0].endDate = date[3]; datetimeDifftest[0].dateDiff = dateDifference[10];
+ datetimeDifftest[1].startDate = date[0]; datetimeDifftest[1].endDate = date[2]; datetimeDifftest[1].dateDiff = dateDifference[5];
+ datetimeDifftest[2].startDate = date[0]; datetimeDifftest[2].endDate = date[2]; datetimeDifftest[2].dateDiff = dateDifference[4];
+ datetimeDifftest[3].startDate = date[0]; datetimeDifftest[3].endDate = date[2]; datetimeDifftest[3].dateDiff = dateDifference[3];
+ datetimeDifftest[4].startDate = date[14]; datetimeDifftest[4].endDate = date[7]; datetimeDifftest[4].dateDiff = dateDifference[7];
+ datetimeDifftest[5].startDate = date[14]; datetimeDifftest[5].endDate = date[7]; datetimeDifftest[5].dateDiff = dateDifference[8];
+ datetimeDifftest[6].startDate = date[11]; datetimeDifftest[6].endDate = date[8]; datetimeDifftest[6].dateDiff = dateDifference[9];
+ datetimeDifftest[7].startDate = date[13]; datetimeDifftest[7].endDate = date[0]; datetimeDifftest[7].dateDiff = dateDifference[12];
+ datetimeDifftest[8].startDate = date[13]; datetimeDifftest[8].endDate = date[0]; datetimeDifftest[8].dateDiff = dateDifference[13];
+
+ // Date Add Out of Bound test cases (Negative tests)
+ /*OutofBound*/ datetimeBoundAdd[0].startDate = date[1]; datetimeBoundAdd[0].endDate = date[0]; datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
+ /*OutofBound*/ datetimeBoundAdd[1].startDate = date[2]; datetimeBoundAdd[1].endDate = date[0]; datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
+
+ // Date Subtract Out of Bound test cases (Negative tests)
+ /*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3]; datetimeBoundSubtract[0].endDate = date[0]; datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
+ /*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14]; datetimeBoundSubtract[1].endDate = date[0]; datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
+
+ // Date Add test cases (Positive tests)
+ datetimeAddCase[0].startDate = date[13]; datetimeAddCase[0].endDate = date[7]; datetimeAddCase[0].dateDiff = dateDifference[6];// add
+ datetimeAddCase[1].startDate = date[14]; datetimeAddCase[1].endDate = date[5]; datetimeAddCase[1].dateDiff = dateDifference[1];// add
+ datetimeAddCase[2].startDate = date[13]; datetimeAddCase[2].endDate = date[6]; datetimeAddCase[2].dateDiff = dateDifference[1];// add
+
+ // Date Subtract test cases (Positive tests)
+ datetimeSubtractCase[0].startDate = date[14]; datetimeSubtractCase[0].endDate = date[7]; datetimeSubtractCase[0].dateDiff = dateDifference[6];// subtract
+ datetimeSubtractCase[1].startDate = date[6]; datetimeSubtractCase[1].endDate = date[11]; datetimeSubtractCase[1].dateDiff = dateDifference[1];// subtract
+ datetimeSubtractCase[2].startDate = date[9]; datetimeSubtractCase[2].endDate = date[12]; datetimeSubtractCase[2].dateDiff = dateDifference[1];// subtract
+ }
+
+ TEST_METHOD(DateCalcViewModelInitializationTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ // Check for the initialized values
+ VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
+ VERIFY_IS_TRUE(viewModel->IsAddMode);
+
+ VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
+ VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
+ VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
+
+ VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
+ VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
+ VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
+
+ VERIFY_IS_TRUE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
+ VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+
+ VERIFY_IS_NULL(viewModel->StrDateResult);
+ }
+
+ TEST_METHOD(DateCalcViewModelAddSubtractInitTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+ viewModel->IsDateDiffMode = false;
+
+ // Check for the initialized values
+ VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
+ VERIFY_IS_TRUE(viewModel->IsAddMode);
+
+ VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
+ VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
+ VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
+
+ VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
+ VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
+ VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
+
+ VERIFY_IS_TRUE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
+ VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+
+ VERIFY_IS_NOT_NULL(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)
+ {
+ // TODO - MSFT 10331900, fix this test
+ // A few issues to be investigated..
+ // The date returned by DateUtils::GetLongDate can be a different string than expected
+ // based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
+ // doesn't format according to UTC. If it did, the test would still be incorrect because
+ // the ViewModel is not necessarily in UTC.
+ //
+ // The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
+ // the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
+ // This means testing a specific date here, is *not* the same as selecting that date in the app.
+
+ //auto viewModel = ref new DateCalculatorViewModel();
+ //viewModel->Initialize();
+
+ //viewModel->IsDateDiffMode = false;
+ //viewModel->IsAddMode = true;
+ //VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
+ //VERIFY_IS_TRUE(viewModel->IsAddMode);
+
+ //viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeAddCase[0].startDate);
+ //viewModel->DaysOffset = datetimeAddCase[0].dateDiff.day;
+ //viewModel->MonthsOffset = datetimeAddCase[0].dateDiff.month;
+ //viewModel->YearsOffset = datetimeAddCase[0].dateDiff.year;
+
+ //// Assert for the result
+ //VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
+ }
+
+ TEST_METHOD(DateCalcViewModelSubtractTest)
+ {
+ // TODO - MSFT 10331900, fix this test
+ // A few issues to be investigated..
+ // The date returned by DateUtils::GetLongDate can be a different string than expected
+ // based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
+ // doesn't format according to UTC. If it did, the test would still be incorrect because
+ // the ViewModel is not necessarily in UTC.
+ //
+ // The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
+ // the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
+ // This means testing a specific date here, is *not* the same as selecting that date in the app.
+
+ //auto viewModel = ref new DateCalculatorViewModel();
+ //viewModel->Initialize();
+
+ //viewModel->IsDateDiffMode = false;
+ //viewModel->IsAddMode = false;
+ //VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
+ //VERIFY_IS_FALSE(viewModel->IsAddMode);
+
+ //viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeSubtractCase[0].startDate);
+ //viewModel->DaysOffset = datetimeSubtractCase[0].dateDiff.day;
+ //viewModel->MonthsOffset = datetimeSubtractCase[0].dateDiff.month;
+ //viewModel->YearsOffset = datetimeSubtractCase[0].dateDiff.year;
+
+ //// Assert for the result
+ //VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
+ }
+
+ TEST_METHOD(DateCalcViewModelAddOobTest)
+ {
+ // TODO - MSFT 10331900, fix this test
+ // Curiously enough, this test fails because it fails to go Oob.
+ // Possibly need to update test to use a new max date.
+
+ //auto viewModel = ref new DateCalculatorViewModel();
+ //viewModel->Initialize();
+
+ //viewModel->IsDateDiffMode = false;
+ //viewModel->IsAddMode = true;
+ //VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
+ //VERIFY_IS_TRUE(viewModel->IsAddMode);
+
+ //for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
+ //{
+ // viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate);
+ // viewModel->DaysOffset = datetimeBoundAdd[testIndex].dateDiff.day;
+ // viewModel->MonthsOffset = datetimeBoundAdd[testIndex].dateDiff.month;
+ // viewModel->YearsOffset = datetimeBoundAdd[testIndex].dateDiff.year;
+
+ // // Assert for the result
+ // VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
+ //}
+ }
+
+ TEST_METHOD(DateCalcViewModelSubtractOobTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ viewModel->IsDateDiffMode = false;
+ viewModel->IsAddMode = false;
+ VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
+ VERIFY_IS_FALSE(viewModel->IsAddMode);
+
+ for (int testIndex = 0; testIndex < c_numSubtractOobDate; testIndex++)
+ {
+ viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate);
+ viewModel->DaysOffset = datetimeBoundSubtract[testIndex].dateDiff.day;
+ viewModel->MonthsOffset = datetimeBoundSubtract[testIndex].dateDiff.month;
+ viewModel->YearsOffset = datetimeBoundSubtract[testIndex].dateDiff.year;
+
+ // Assert for the result
+ VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
+ }
+ }
+
+ TEST_METHOD(DateCalcViewModelDateDiffIgnoreSignTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ viewModel->IsDateDiffMode = true;
+ VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
+
+ viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[10]);
+ viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[6]);
+
+ VERIFY_IS_FALSE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult);
+ viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[6]);
+ viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[10]);
+ VERIFY_IS_FALSE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"305 days"), viewModel->StrDateDiffResultInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"10 months"), viewModel->StrDateDiffResult);
+ }
+
+ TEST_METHOD(DateCalcViewModelDateDiffTest)
+ {
+ // TODO - MSFT 10331900, fix this test
+ // The last VERIFY checks with expected value "8398 years, 11 months, 4 weeks, 2 days"
+ // The viewmodel result is something like "8398 years, 12 months, 6568892 weeks, 1 day",
+ // which shows there is a problem with the viewmodel's reduction algorithm.
+
+ //auto viewModel = ref new DateCalculatorViewModel();
+ //viewModel->Initialize();
+
+ //viewModel->IsDateDiffMode = true;
+ //VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
+
+ //viewModel->FromDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].startDate);
+ //viewModel->ToDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].endDate);
+
+ //// Assert for the result
+ //VERIFY_IS_FALSE(viewModel->IsDiffInDays);
+ //VERIFY_ARE_EQUAL(StringReference(L"3067670 days"), viewModel->StrDateDiffResultInDays);
+ //VERIFY_ARE_EQUAL(StringReference(L"8398 years, 11 months, 4 weeks, 2 days"), viewModel->StrDateDiffResult);
+ }
+
+ TEST_METHOD(DateCalcViewModelDateDiffResultInPositiveDaysTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ viewModel->IsDateDiffMode = true;
+ VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
+
+ viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[1]);
+ viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[0]);
+
+ // Assert for the result
+ VERIFY_IS_TRUE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
+ VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+ }
+
+ TEST_METHOD(DateCalcViewModelDateDiffFromDateHigherThanToDate)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ viewModel->IsDateDiffMode = true;
+ VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
+
+ viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[0]);
+ viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[1]);
+
+ // Assert for the result
+ VERIFY_IS_TRUE(viewModel->IsDiffInDays);
+ VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
+ VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
+ }
+
+ // Tests that the automation name for the resulting date in Add Mode
+ // contains the DayOfWeek, Day, Month, and Year
+ TEST_METHOD(DateCalcViewModelAddSubtractResultAutomationNameTest)
+ {
+ auto viewModel = ref new DateCalculatorViewModel();
+
+ auto cal = ref new Calendar();
+ cal->Year = 2007;
+ cal->Month = 5;
+ cal->Day = 10;
+ cal->Hour = 12;
+ cal->Period = 2;
+ cal->Nanosecond = 0;
+ cal->Second = 0;
+
+ DateTime startDate = cal->GetDateTime();
+ viewModel->StartDate = startDate;
+
+ viewModel->IsDateDiffMode = false;
+ viewModel->IsAddMode = true;
+
+ wstring actualValue = viewModel->StrDateResultAutomationName->Data();
+
+ // Verify each component is present in the result
+ wstring components[] = {
+ L"dayofweek.full",
+ L"month.full",
+ L"year.full",
+ L"day"
+ };
+
+ for (const wstring &component : components)
+ {
+ auto formatter = ref new DateTimeFormatter(ref new String(component.c_str()));
+ wstring expectedValue = formatter->Format(startDate)->Data();
+ wstring message = L"Verifying " + component + L" is present in the result";
+ VERIFY_IS_TRUE(actualValue.find(expectedValue) != wstring::npos, message.c_str());
+ }
+ }
+
+ TEST_METHOD(JaEraTransitionAddition)
+ {
+ auto viewModel = make_unique(CalendarIdentifiers::Japanese);
+ auto cal = ref new Calendar();
+
+ // Showa period ended in Jan 1989.
+ cal->Year = 1989;
+ cal->Month = 1;
+ cal->Day = 1;
+ auto startTime = cal->GetDateTime();
+
+ cal->Year = 1990;
+ cal->Month = 1;
+ cal->Day = 1;
+
+ // Expect that adding a year across boundaries adds the equivalent in the Gregorian calendar.
+ auto expectedResult = cal->GetDateTime();
+ DateDifference duration;
+ duration.year = 1;
+
+ DateTime actualResult;
+ viewModel->AddDuration(startTime, duration, &actualResult);
+
+ VERIFY_ARE_EQUAL(expectedResult.UniversalTime, actualResult.UniversalTime);
+ }
+
+ TEST_METHOD(JaEraTransitionSubtraction)
+ {
+ auto viewModel = make_unique(CalendarIdentifiers::Japanese);
+ auto cal = ref new Calendar();
+
+ // Showa period ended in Jan 1989.
+ cal->Year = 1990;
+ cal->Month = 1;
+ cal->Day = 1;
+ auto startTime = cal->GetDateTime();
+
+ cal->Year = 1989;
+ cal->Month = 1;
+ cal->Day = 1;
+
+ // Expect that adding a year across boundaries adds the equivalent in the Gregorian calendar.
+ auto expectedResult = cal->GetDateTime();
+ DateDifference duration;
+ duration.year = 1;
+
+ DateTime actualResult;
+ viewModel->SubtractDuration(startTime, duration, &actualResult);
+
+ VERIFY_ARE_EQUAL(expectedResult.UniversalTime, actualResult.UniversalTime);
+ }
+ };
}