Merge pull request #1 from Microsoft/master

Merge with master
This commit is contained in:
Pepe Rivera 2019-02-11 14:51:56 -08:00 committed by GitHub
commit 296ccc867e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 197 additions and 11429 deletions

10
.gitignore vendored
View File

@ -289,13 +289,5 @@ __pycache__/
# Calculator specific
Generated Files/
# Don't ignore anything under SpkgDefs or TrexDefs
!/SpkgDefs/**
!/TrexDefs/**
!/build/config/TRexDefs/**
# Localized strings
# LCT files are loc system artifacts that we don't want in our repo.
*.lct
WorkspaceInfo.xml
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx

View File

@ -26,7 +26,7 @@ Prerequisites:
- Install the latest Windows 10 SDK
![Visual Studio Installation Screenshot](docs/Images/VSInstallationScreenshot.png)
- Install the [XamlStyler](https://marketplace.visualstudio.com/items?itemName=TeamXavalon.XAMLStyler) Visual Studio extension
- Install the [XAML Styler](https://marketplace.visualstudio.com/items?itemName=TeamXavalon.XAMLStyler) Visual Studio extension
- Get the code:
```

View File

@ -24,18 +24,18 @@ jobs:
displayName: Download CalculatorUnitTests
inputs:
artifactName: drop
itemPattern: drop/Release/${{ parameters.platform }}/CalculatorUnitTests_VS/AppPackages/CalculatorUnitTests_Test/**
itemPattern: drop/Release/${{ parameters.platform }}/CalculatorUnitTests/AppPackages/CalculatorUnitTests_Test/**
- task: PowerShell@2
displayName: Install Certificate
inputs:
filePath: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests_VS\AppPackages\CalculatorUnitTests_Test\Add-AppDevPackage.ps1
arguments: -CertificatePath $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests_VS\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.cer -Force
filePath: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\Add-AppDevPackage.ps1
arguments: -CertificatePath $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.cer -Force
- task: VSTest@2
displayName: Run CalculatorUnitTests
inputs:
testAssemblyVer2: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests_VS\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.appx
testAssemblyVer2: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.appx
otherConsoleOptions: /Platform:${{ parameters.platform }}
- job: CleanUpUnitTests${{ parameters.platform }}

View File

@ -141,8 +141,19 @@ property and a `PropertyChanged` event will be raised, allowing the UI to respon
--------
## Model
The Model for the Calculator modes is contained in the [CalcManager][CalcManager folder] project.
<!-- TODO joshuako: Add the docs -->
The Model for the Calculator modes is contained in the [CalcManager][CalcManager folder] project. It consists of three layers: a `CalculatorManager`, which relies on a `CalcEngine`, which relies on the `Ratpack`.
### CalculatorManager
The CalculatorManager contains the logic for managing the overall Calculator app's data such as the History and Memory lists, as well as maintaining the instances of calculator engines used for the various modes. The interface to this layer is defined in [CalculatorManager.h][CalculatorManager.h].
### CalcEngine
The CalcEngine contains the logic for interpreting and performing operations according to the commands passed to it. It maintains the current state of calculations and relies on the RatPack for performing mathematical operations. The interface to this layer is defined in [CalcEngine.h][CalcEngine.h].
### 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].
[References]:####################################################################################################
@ -186,3 +197,6 @@ The Model for the Calculator modes is contained in the [CalcManager][CalcManager
[Utils.h]: ../src/CalcViewModel/Common/Utils.h
[CalcManager folder]: ../src/CalcManager
[CalculatorManager.h]: ../src/CalcManager/CalculatorManager.h
[CalcEngine.h]: ../src/CalcManager/Header&#32;Files/CalcEngine.h
[ratpak.h]: ../src/CalcManager/Ratpack/ratpak.h

View File

@ -11,16 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Calculator", "..\src\Calculator\Calculator.vcxproj", "{9447424A-0E05-4911-BEB8-E0354405F39A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "..\src\CalcViewModel\CalcViewModel.vcxproj", "{90E9761D-9262-4773-942D-CAEAE75D7140}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcManager", "..\src\CalcManager\CalcManager.vcxproj", "{311E866D-8B93-4609-A691-265941FEE101}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.TestPackage", "Calculator.TestPackage\Calculator.TestPackage.csproj", "{24767C43-CD5A-4DC9-8D6B-429F255524E5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@ -61,62 +53,6 @@ Global
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x64.Build.0 = Release|x64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x86.ActiveCfg = Release|x86
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x86.Build.0 = Release|x86
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.ActiveCfg = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Build.0 = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Deploy.0 = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.Build.0 = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.Deploy.0 = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.ActiveCfg = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.Build.0 = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.Deploy.0 = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.ActiveCfg = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.Build.0 = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.Deploy.0 = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.ActiveCfg = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.Build.0 = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.Deploy.0 = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.ActiveCfg = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.Build.0 = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.Deploy.0 = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.ActiveCfg = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.Build.0 = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.Deploy.0 = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.ActiveCfg = Release|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Build.0 = Release|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Deploy.0 = Release|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.ActiveCfg = Debug|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.Build.0 = Debug|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM64.ActiveCfg = Debug|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM64.Build.0 = Debug|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x64.ActiveCfg = Debug|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x64.Build.0 = Debug|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x86.ActiveCfg = Debug|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x86.Build.0 = Debug|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM.ActiveCfg = Release|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM.Build.0 = Release|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM64.ActiveCfg = Release|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM64.Build.0 = Release|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x64.ActiveCfg = Release|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x64.Build.0 = Release|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x86.ActiveCfg = Release|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x86.Build.0 = Release|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.ActiveCfg = Debug|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.Build.0 = Debug|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.ActiveCfg = Debug|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.Build.0 = Debug|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.ActiveCfg = Debug|x64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.Build.0 = Debug|x64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.ActiveCfg = Debug|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.Build.0 = Debug|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.ActiveCfg = Release|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.Build.0 = Release|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.ActiveCfg = Release|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.Build.0 = Release|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x64.ActiveCfg = Release|x64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x64.Build.0 = Release|x64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x86.ActiveCfg = Release|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Release|x86.Build.0 = Release|Win32
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM.ActiveCfg = Debug|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM.Build.0 = Debug|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM64.ActiveCfg = Debug|ARM64
@ -131,30 +67,6 @@ Global
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x64.Build.0 = Release|x64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x86.ActiveCfg = Release|x86
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x86.Build.0 = Release|x86
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.ActiveCfg = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.Build.0 = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.Deploy.0 = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.Build.0 = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.Deploy.0 = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.ActiveCfg = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.Build.0 = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.Deploy.0 = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.ActiveCfg = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.Build.0 = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.Deploy.0 = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.ActiveCfg = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.Build.0 = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.Deploy.0 = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.ActiveCfg = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.Build.0 = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.Deploy.0 = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.ActiveCfg = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.Build.0 = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.Deploy.0 = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.ActiveCfg = Release|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.Build.0 = Release|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.Deploy.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,225 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "CalcViewModel\Common\EngineResourceProvider.h"
using namespace std;
using namespace WEX::Common;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace CalculatorApp;
using namespace CalculationManager;
static constexpr size_t MAX_HISTORY_SIZE = 20;
namespace CalculatorUnitTests
{
class CalcEngineTests
{
TEST_CLASS(CalcEngineTests);
TEST_CLASS_SETUP(CommonSetup)
{
m_resourceProvider = make_shared<EngineResourceProvider>();
m_history = make_shared<CalculatorHistory>(CM_STD, MAX_HISTORY_SIZE);
CCalcEngine::InitialOneTimeOnlySetup(*(m_resourceProvider.get()));
m_calcEngine = make_unique<CCalcEngine>(false /* Respect Order of Operations */, false /* Set to Integer Mode */, m_resourceProvider.get(), nullptr, m_history);
return true;
}
TEST_METHOD_CLEANUP(Cleanup)
{
return true;
}
TEST_METHOD(TestGroupDigitsPerRadix)
{
// Empty/Error cases
VERIFY_IS_TRUE(m_calcEngine->GroupDigitsPerRadix(L"", 10).empty(), L"Verify grouping empty string returns empty string.");
VERIFY_ARE_EQUAL(L"12345678", m_calcEngine->GroupDigitsPerRadix(L"12345678", 9), L"Verify grouping on invalid base returns original string");
// Octal
VERIFY_ARE_EQUAL(L"1 234 567", m_calcEngine->GroupDigitsPerRadix(L"1234567", 8), L"Verify grouping in octal.");
VERIFY_ARE_EQUAL(L"123", m_calcEngine->GroupDigitsPerRadix(L"123", 8), L"Verify minimum grouping in octal.");
// Binary/Hexadecimal
VERIFY_ARE_EQUAL(L"12 3456 7890", m_calcEngine->GroupDigitsPerRadix(L"1234567890", 2), L"Verify grouping in binary.");
VERIFY_ARE_EQUAL(L"1234", m_calcEngine->GroupDigitsPerRadix(L"1234", 2), L"Verify minimum grouping in binary.");
VERIFY_ARE_EQUAL(L"12 3456 7890", m_calcEngine->GroupDigitsPerRadix(L"1234567890", 16), L"Verify grouping in hexadecimal.");
VERIFY_ARE_EQUAL(L"1234", m_calcEngine->GroupDigitsPerRadix(L"1234", 16), L"Verify minimum grouping in hexadecimal.");
// Decimal
VERIFY_ARE_EQUAL(L"1,234,567,890", m_calcEngine->GroupDigitsPerRadix(L"1234567890", 10), L"Verify grouping in base10.");
VERIFY_ARE_EQUAL(L"1,234,567.89", m_calcEngine->GroupDigitsPerRadix(L"1234567.89", 10), L"Verify grouping in base10 with decimal.");
VERIFY_ARE_EQUAL(L"1,234,567e89", m_calcEngine->GroupDigitsPerRadix(L"1234567e89", 10), L"Verify grouping in base10 with exponent.");
VERIFY_ARE_EQUAL(L"1,234,567.89e5", m_calcEngine->GroupDigitsPerRadix(L"1234567.89e5", 10), L"Verify grouping in base10 with decimal and exponent.");
VERIFY_ARE_EQUAL(L"-123,456,789", m_calcEngine->GroupDigitsPerRadix(L"-123456789", 10), L"Verify grouping in base10 with negative.");
}
TEST_METHOD(TestIsNumberInvalid)
{
// Binary Number Checks
vector<wstring> validBinStrs{ L"0", L"1", L"0011", L"1100" };
vector<wstring> invalidBinStrs{ L"2", L"A", L"0.1" };
for (wstring const& str : validBinStrs)
{
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(str, 0, 0, 2 /* Binary */));
}
for (wstring const& str : invalidBinStrs)
{
VERIFY_ARE_EQUAL(IDS_ERR_UNK_CH, m_calcEngine->IsNumberInvalid(str, 0, 0, 2 /* Binary */));
}
// Octal Number Checks
vector<wstring> validOctStrs{ L"0", L"7", L"01234567", L"76543210" };
vector<wstring> invalidOctStrs{ L"8", L"A", L"0.7" };
for (wstring const& str : validOctStrs)
{
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(str, 0, 0, 8 /* Octal */));
}
for (wstring const& str : invalidOctStrs)
{
VERIFY_ARE_EQUAL(IDS_ERR_UNK_CH, m_calcEngine->IsNumberInvalid(str, 0, 0, 8 /* Octal */));
}
// Hexadecimal Number Checks
vector<wstring> validHexStrs{ L"0", L"F", L"0123456789ABCDEF", L"FEDCBA9876543210" };
vector<wstring> invalidHexStrs{ L"G", L"abcdef", L"x", L"0.1" };
for (wstring const& str : validHexStrs)
{
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(str, 0, 0, 16 /* HEx */));
}
for (wstring const& str : invalidHexStrs)
{
VERIFY_ARE_EQUAL(IDS_ERR_UNK_CH, m_calcEngine->IsNumberInvalid(str, 0, 0, 16 /* Hex */));
}
// Decimal Number Checks
// Special case errors: long exponent, long mantissa
wstring longExp(L"1e12345");
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(longExp, 5 /* Max exp length */, 100, 10 /* Decimal */));
VERIFY_ARE_EQUAL(IDS_ERR_INPUT_OVERFLOW, m_calcEngine->IsNumberInvalid(longExp, 4 /* Max exp length */, 100, 10 /* Decimal */));
// Mantissa length is sum of:
// - digits before decimal separator, minus leading zeroes
// - digits after decimal separator, including trailing zeroes
// Each of these mantissa values should calculate as a length of 5
vector<wstring> longMantStrs{ L"10000", L"10.000", L"0000012345", L"123.45", L"0.00123", L"0.12345", L"-123.45e678" };
for (wstring const& str : longMantStrs)
{
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(str, 100, 5 /* Max mantissa length */, 10 /* Decimal */));
}
for (wstring const& str : longMantStrs)
{
VERIFY_ARE_EQUAL(IDS_ERR_INPUT_OVERFLOW, m_calcEngine->IsNumberInvalid(str, 100, 4 /* Max mantissa length */, 10 /* Decimal */));
}
// Regex matching (descriptions taken from CalcUtils.cpp)
// Use 100 for exp/mantissa length as they are tested above
vector<wstring> validDecStrs{
// Start with an optional + or -
L"+1", L"-1", L"1",
// Followed by zero or more digits
L"-", L"", L"1234567890",
// Followed by an optional decimal point
L"1.0", L"-.", L"1.",
// Followed by zero or more digits
L"0.0", L"0.123456",
// Followed by an optional exponent ('e')
L"1e", L"1.e", L"-e",
// If there's an exponent, its optionally followed by + or -
// and followed by zero or more digits
L"1e+12345", L"1e-12345", L"1e123",
// All together
L"-123.456e+789"
};
vector<wstring> invalidDecStrs{ L"x123", L"123-", L"1e1.2", L"1-e2" };
for (wstring const& str : validDecStrs)
{
VERIFY_ARE_EQUAL(0, m_calcEngine->IsNumberInvalid(str, 100, 100, 10 /* Dec */));
}
for (wstring const& str : invalidDecStrs)
{
VERIFY_ARE_EQUAL(IDS_ERR_UNK_CH, m_calcEngine->IsNumberInvalid(str, 100, 100, 10 /* Dec */));
}
}
TEST_METHOD(TestDigitGroupingStringToGroupingVector)
{
vector<uint32_t> groupingVector{};
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L""), L"Verify empty grouping");
groupingVector = { 1 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"1"), L"Verify simple grouping");
groupingVector = { 3, 0 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"3;0"), L"Verify standard grouping");
groupingVector = { 3, 0, 0 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"3;0;0"), L"Verify expanded non-repeating grouping");
groupingVector = { 5, 3, 2, 4, 6 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"5;3;2;4;6"), L"Verify long grouping");
groupingVector = { 15, 15, 15, 0 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"15;15;15;0"), L"Verify large grouping");
groupingVector = { 4, 7, 0 };
VERIFY_ARE_EQUAL(groupingVector, CCalcEngine::DigitGroupingStringToGroupingVector(L"4;16;7;25;0"), L"Verify we ignore oversize grouping");
}
TEST_METHOD(TestGroupDigits)
{
wstring result{ L"1234567" };
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L"", { 3, 0 }, L"1234567", false), L"Verify handling of empty delimiter.");
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", {}, L"1234567", false), L"Verify handling of empty grouping.");
result = L"1,234,567";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0 }, L"1234567", false), L"Verify standard digit grouping.");
result = L"1 234 567";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L" ", { 3, 0 }, L"1234567", false), L"Verify delimiter change.");
result = L"1|||234|||567";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L"|||", { 3, 0 }, L"1234567", false), L"Verify long delimiter.");
result = L"12,345e67";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0 }, L"12345e67", false), L"Verify respect of exponent.");
result = L"12,345.67";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0 }, L"12345.67", false), L"Verify respect of decimal.");
result = L"1,234.56e7";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0 }, L"1234.56e7", false), L"Verify respect of exponent and decimal.");
result = L"-1,234,567";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0 }, L"-1234567", true), L"Verify negative number grouping.");
// Test various groupings
result = L"1234567890123456";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 0, 0 }, L"1234567890123456", false), L"Verify no grouping.");
result = L"1234567890123,456";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3 }, L"1234567890123456", false), L"Verify non-repeating grouping.");
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 3, 0, 0 }, L"1234567890123456", false), L"Verify expanded form non-repeating grouping.");
result = L"12,34,56,78,901,23456";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 5, 3, 2, 0 }, L"1234567890123456", false), L"Verify multigroup with repeating grouping.");
result = L"1234,5678,9012,3456";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 4, 0 }, L"1234567890123456", false), L"Verify repeating non-standard grouping.");
result = L"123456,78,901,23456";
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 5, 3, 2 }, L"1234567890123456", false), L"Verify multigroup non-repeating grouping.");
VERIFY_ARE_EQUAL(result, m_calcEngine->GroupDigits(L",", { 5, 3, 2, 0, 0 }, L"1234567890123456", false), L"Verify expanded form multigroup non-repeating grouping.");
}
private:
unique_ptr<CCalcEngine> m_calcEngine;
shared_ptr<IResourceProvider> m_resourceProvider;
shared_ptr<CalculatorHistory> m_history;
};
}

View File

@ -1,366 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
using namespace std;
using namespace WEX::Common;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace CalculationManager;
namespace CalculatorUnitTests
{
class CalcInputTest
{
TEST_CLASS(CalcInputTest);
TEST_CLASS_SETUP(CommonSetup)
{
m_calcInput = CalcEngine::CalcInput(L'.');
return true;
}
TEST_METHOD_CLEANUP(Cleanup)
{
m_calcInput.Clear();
m_calcInput.SetDecimalSymbol(L'.');
return true;
}
TEST_METHOD(Clear)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryToggleSign(false, L"999");
m_calcInput.TryAddDecimalPt();
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
m_calcInput.TryAddDigit(3, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"-1.2e+3", m_calcInput.ToString(10, false), L"Verify input is correct.");
m_calcInput.Clear();
::Log::Comment(m_calcInput.ToString(10, false).c_str());
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify input is 0 after clear.");
}
TEST_METHOD(TryToggleSignZero)
{
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(false, L"999"), L"Verify toggling 0 succeeds.");
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify toggling 0 does not create -0.");
}
TEST_METHOD(TryToggleSignExponent)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(false, L"999"), L"Verify toggling exponent sign succeeds.");
VERIFY_ARE_EQUAL(L"1.e-2", m_calcInput.ToString(10, false), L"Verify toggling exponent sign does not toggle base sign.");
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(false, L"999"), L"Verify toggling exponent sign succeeds.");
VERIFY_ARE_EQUAL(L"1.e+2", m_calcInput.ToString(10, false), L"Verify toggling negative exponent sign does not toggle base sign.");
}
TEST_METHOD(TryToggleSignBase)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(false, L"999"), L"Verify toggling base sign succeeds.");
VERIFY_ARE_EQUAL(L"-1", m_calcInput.ToString(10, false), L"Verify toggling base sign creates negative base.");
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(false, L"999"), L"Verify toggling base sign succeeds.");
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify toggling negative base sign creates positive base.");
}
TEST_METHOD(TryToggleSignBaseIntegerMode)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(true, L"999"), L"Verify toggling base sign in integer mode succeeds.");
VERIFY_ARE_EQUAL(L"-1", m_calcInput.ToString(10, false), L"Verify toggling base sign creates negative base.");
}
TEST_METHOD(TryToggleSignRollover)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryToggleSign(true, L"127"), L"Verify toggling base sign in integer mode succeeds.");
m_calcInput.TryAddDigit(8, 10, false, L"999", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryToggleSign(true, L"127"), L"Verify toggling base sign in integer mode fails on rollover.");
VERIFY_ARE_EQUAL(L"-128", m_calcInput.ToString(10, false), L"Verify toggling base sign on rollover does not change value.");
}
TEST_METHOD(TryAddDigitLeadingZeroes)
{
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(0, 10, false, L"999", 64, 32), L"Verify TryAddDigit succeeds.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(0, 10, false, L"999", 64, 32), L"Verify TryAddDigit succeeds.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(0, 10, false, L"999", 64, 32), L"Verify TryAddDigit succeeds.");
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify leading zeroes are ignored.");
}
TEST_METHOD(TryAddDigitMaxCount)
{
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32), L"Verify TryAddDigit for base with length < maxDigits succeeds.");
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify adding digit for base with length < maxDigits succeeded.");
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 1), L"Verify TryAddDigit for base with length > maxDigits fails.");
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify digit for base was not added.");
m_calcInput.TryBeginExponent();
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32), L"Verify TryAddDigit for exponent with length < maxDigits succeeds.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32), L"Verify TryAddDigit for exponent with length < maxDigits succeeds.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(3, 10, false, L"999", 64, 32), L"Verify TryAddDigit for exponent with length < maxDigits succeeds.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(4, 10, false, L"999", 64, 32), L"Verify TryAddDigit for exponent with length < maxDigits succeeds.");
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(5, 10, false, L"999", 64, 32), L"Verify TryAddDigit for exponent with length > maxDigits fails.");
VERIFY_ARE_EQUAL(L"1.e+1234", m_calcInput.ToString(10, false), L"Verify adding digits for exponent with length < maxDigits succeeded.");
m_calcInput.Clear();
m_calcInput.TryAddDecimalPt();
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 1), L"Verify decimal point and leading zero does not count toward maxDigits.");
VERIFY_ARE_EQUAL(L"0.1", m_calcInput.ToString(10, false), L"Verify input value checking dec pt and leading zero impact on maxDigits.");
}
TEST_METHOD(TryAddDigitValues)
{
// Use an arbitrary value > 16 to test that input accepts digits > hexadecimal 0xF.
// TryAddDigit does not validate whether the digit fits within the current radix.
for (unsigned int i = 0; i < 25; i++)
{
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(i, 10, false, L"999", 64, 32), String().Format(L"Verify TryAddDigit succeeds for %d", i));
m_calcInput.Clear();
}
}
TEST_METHOD(TryAddDigitRolloverBaseCheck)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 16, true, L"999", 64, 1), L"Verify TryAddDigit rollover fails for bases other than 8,10.");
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(1, 2, true, L"999", 64, 1), L"Verify TryAddDigit rollover fails for bases other than 8,10.");
}
TEST_METHOD(TryAddDigitRolloverOctalByte)
{
m_calcInput.TryAddDigit(1, 8, true, L"777", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(2, 8, true, L"377", 8, 1), L"Verify we can add an extra digit in OctalByte if first digit <= 3.");
m_calcInput.Clear();
m_calcInput.TryAddDigit(4, 8, true, L"777", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 8, true, L"377", 8, 1), L"Verify we cannot add an extra digit in OctalByte if first digit > 3.");
}
TEST_METHOD(TryAddDigitRolloverOctalWord)
{
m_calcInput.TryAddDigit(1, 8, true, L"777", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(2, 8, true, L"377", 16, 1), L"Verify we can add an extra digit in OctalByte if first digit == 1.");
m_calcInput.Clear();
m_calcInput.TryAddDigit(2, 8, true, L"777", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 8, true, L"377", 16, 1), L"Verify we cannot add an extra digit in OctalByte if first digit > 1.");
}
TEST_METHOD(TryAddDigitRolloverOctalDword)
{
m_calcInput.TryAddDigit(1, 8, true, L"777", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(2, 8, true, L"377", 32, 1), L"Verify we can add an extra digit in OctalByte if first digit <= 3.");
m_calcInput.Clear();
m_calcInput.TryAddDigit(4, 8, true, L"777", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 8, true, L"377", 32, 1), L"Verify we cannot add an extra digit in OctalByte if first digit > 3.");
}
TEST_METHOD(TryAddDigitRolloverOctalQword)
{
m_calcInput.TryAddDigit(1, 8, true, L"777", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(2, 8, true, L"377", 64, 1), L"Verify we can add an extra digit in OctalByte if first digit == 1.");
m_calcInput.Clear();
m_calcInput.TryAddDigit(2, 8, true, L"777", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 8, true, L"377", 64, 1), L"Verify we cannot add an extra digit in OctalByte if first digit > 1.");
}
TEST_METHOD(TryAddDigitRolloverDecimal)
{
m_calcInput.TryAddDigit(1, 10, true, L"127", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(0, 10, true, L"1", 8, 1), L"Verify we cannot add a digit if input size matches maxStr size.");
m_calcInput.TryAddDigit(2, 10, true, L"127", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(2, 10, true, L"110", 8, 2), L"Verify we cannot add a digit if n char comparison > 0.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(7, 10, true, L"130", 8, 2), L"Verify we can add a digit if n char comparison < 0.");
m_calcInput.Clear();
m_calcInput.TryAddDigit(1, 10, true, L"127", 64, 32);
m_calcInput.TryAddDigit(2, 10, true, L"127", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(8, 10, true, L"127", 8, 2), L"Verify we cannot add a digit if digit exceeds max value.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(7, 10, true, L"127", 8, 2), L"Verify we can add a digit if digit does not exceed max value.");
m_calcInput.Backspace();
m_calcInput.TryToggleSign(true, L"127");
VERIFY_IS_FALSE(m_calcInput.TryAddDigit(9, 10, true, L"127", 8, 2), L"Negative value: verify we cannot add a digit if digit exceeds max value.");
VERIFY_IS_TRUE(m_calcInput.TryAddDigit(8, 10, true, L"127", 8, 2), L"Negative value: verify we can add a digit if digit does not exceed max value.");
}
TEST_METHOD(TryAddDecimalPtEmpty)
{
VERIFY_IS_FALSE(m_calcInput.HasDecimalPt(), L"Verify input has no decimal point.");
VERIFY_IS_TRUE(m_calcInput.TryAddDecimalPt(), L"Verify adding decimal to empty input.");
VERIFY_IS_TRUE(m_calcInput.HasDecimalPt(), L"Verify input has decimal point.");
VERIFY_ARE_EQUAL(L"0.", m_calcInput.ToString(10, false), L"Verify decimal on empty input.");
}
TEST_METHOD(TryAddDecimalPointTwice)
{
VERIFY_IS_FALSE(m_calcInput.HasDecimalPt(), L"Verify input has no decimal point.");
VERIFY_IS_TRUE(m_calcInput.TryAddDecimalPt(), L"Verify adding decimal to empty input.");
VERIFY_IS_TRUE(m_calcInput.HasDecimalPt(), L"Verify input has decimal point.");
VERIFY_IS_FALSE(m_calcInput.TryAddDecimalPt(), L"Verify adding decimal point fails if input has decimal point.");
}
TEST_METHOD(TryAddDecimalPointExponent)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
VERIFY_IS_FALSE(m_calcInput.TryAddDecimalPt(), L"Verify adding decimal point fails if input has exponent.");
}
TEST_METHOD(TryBeginExponentNoExponent)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryBeginExponent(), L"Verify adding exponent succeeds on input without exponent.");
VERIFY_ARE_EQUAL(L"1.e+0", m_calcInput.ToString(10, false), L"Verify exponent present.");
}
TEST_METHOD(TryBeginExponentWithExponent)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_IS_TRUE(m_calcInput.TryBeginExponent(), L"Verify adding exponent succeeds on input without exponent.");
VERIFY_IS_FALSE(m_calcInput.TryBeginExponent(), L"Verify cannot add exponent if input already has exponent.");
}
TEST_METHOD(BackspaceZero)
{
m_calcInput.Backspace();
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify backspace on 0 is still 0.");
}
TEST_METHOD(BackspaceSingleChar)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify input before backspace.");
m_calcInput.Backspace();
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify input after backspace.");
}
TEST_METHOD(BackspaceMultiChar)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"12", m_calcInput.ToString(10, false), L"Verify input before backspace.");
m_calcInput.Backspace();
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify input after backspace.");
}
TEST_METHOD(BackspaceDecimal)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryAddDecimalPt();
VERIFY_ARE_EQUAL(L"1.", m_calcInput.ToString(10, false), L"Verify input before backspace.");
VERIFY_IS_TRUE(m_calcInput.HasDecimalPt(), L"Verify input has decimal point.");
m_calcInput.Backspace();
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, false), L"Verify input after backspace.");
VERIFY_IS_FALSE(m_calcInput.HasDecimalPt(), L"Verify decimal point was removed.");
}
TEST_METHOD(BackspaceMultiCharDecimal)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryAddDecimalPt();
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(3, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"1.23", m_calcInput.ToString(10, false), L"Verify input before backspace.");
m_calcInput.Backspace();
VERIFY_ARE_EQUAL(L"1.2", m_calcInput.ToString(10, false), L"Verify input after backspace.");
}
TEST_METHOD(SetDecimalSymbol)
{
m_calcInput.TryAddDecimalPt();
VERIFY_ARE_EQUAL(L"0.", m_calcInput.ToString(10, false), L"Verify default decimal point.");
m_calcInput.SetDecimalSymbol(L',');
VERIFY_ARE_EQUAL(L"0,", m_calcInput.ToString(10, false), L"Verify new decimal point.");
}
TEST_METHOD(ToStringEmpty)
{
VERIFY_ARE_EQUAL(L"0", m_calcInput.ToString(10, false), L"Verify ToString of empty value.");
}
TEST_METHOD(ToStringNegative)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryToggleSign(false, L"999");
VERIFY_ARE_EQUAL(L"-1", m_calcInput.ToString(10, false), L"Verify ToString of negative value.");
}
TEST_METHOD(ToStringExponentBase10)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
VERIFY_ARE_EQUAL(L"1.e+0", m_calcInput.ToString(10, false), L"Verify ToString of empty base10 exponent.");
}
TEST_METHOD(ToStringExponentBase8)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
VERIFY_ARE_EQUAL(L"1.^+0", m_calcInput.ToString(8, false), L"Verify ToString of empty base8 exponent.");
}
TEST_METHOD(ToStringExponentNegative)
{
m_calcInput.TryAddDigit(1, 8, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
m_calcInput.TryToggleSign(false, L"999");
VERIFY_ARE_EQUAL(L"1.e-0", m_calcInput.ToString(10, false), L"Verify ToString of empty negative exponent.");
}
TEST_METHOD(ToStringExponentPositive)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(3, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(4, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"1.e+234", m_calcInput.ToString(10, false), L"Verify ToString of exponent with value.");
}
TEST_METHOD(ToStringInteger)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"1", m_calcInput.ToString(10, true), L"Verify ToString of integer value hides decimal.");
}
TEST_METHOD(ToStringBaseTooLong)
{
wstring maxStr{};
for (size_t i = 0; i < MAX_STRLEN + 1; i++)
{
maxStr += L"1";
m_calcInput.TryAddDigit(1, 10, false, maxStr, 64, 100);
}
auto result = m_calcInput.ToString(10, false);
VERIFY_IS_TRUE(result.empty(), L"Verify ToString of base value that is too large yields empty string.");
}
TEST_METHOD(ToStringExponentTooLong)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryBeginExponent();
wstring maxStr{L"11"};
bool exponentCapped = false;
for (size_t i = 0; i < MAX_STRLEN + 1; i++)
{
maxStr += L"1";
if (!m_calcInput.TryAddDigit(1, 10, false, maxStr, 64, MAX_STRLEN + 25))
{
exponentCapped = true;
}
}
auto result = m_calcInput.ToString(10, false);
// TryAddDigit caps the exponent length to C_EXP_MAX_DIGITS = 4, so ToString() succeeds.
// If that cap is removed, ToString() should return an empty string.
if (exponentCapped)
{
VERIFY_ARE_EQUAL(L"1.e+1111", result, L"Verify ToString succeeds; exponent length is capped at C_EXP_MAX_DIGITS.");
}
else
{
VERIFY_IS_TRUE(result.empty(), L"Verify ToString of exponent value that is too large yields empty string.");
}
}
TEST_METHOD(ToRational)
{
m_calcInput.TryAddDigit(1, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(2, 10, false, L"999", 64, 32);
m_calcInput.TryAddDigit(3, 10, false, L"999", 64, 32);
VERIFY_ARE_EQUAL(L"123", m_calcInput.ToString(10, false), L"Verify input before conversion to rational.");
auto rat = m_calcInput.ToRational(10, false);
VERIFY_ARE_EQUAL(1, rat.P().Mantissa().size(), L"Verify digit count of rational.");
VERIFY_ARE_EQUAL(123, rat.P().Mantissa().front(), L"Verify first digit of mantissa.");
}
private:
CalcEngine::CalcInput m_calcInput;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,365 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.props" Condition="Exists('..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.props')" />
<Import Project="..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.props" Condition="Exists('..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.props')" />
<Import Project="..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.props" Condition="Exists('..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.props')" />
<PropertyGroup Label="Globals">
<ProjectGuid>{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}</ProjectGuid>
<RootNamespace>CalculatorUnitTests</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.17763.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<AppxPackageName>CalculatorUnitTests</AppxPackageName>
<!-- We want to automatic replace of MinVersion/MaxVersionTested for unit tests. -->
<AppxOSMinVersionReplaceManifestVersion>true</AppxOSMinVersionReplaceManifestVersion>
<AppxOSMaxVersionTestedReplaceManifestVersion>true</AppxOSMaxVersionTestedReplaceManifestVersion>
<!-- Needed to build the testmd package -->
<GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- This has to be exactly in this place for this to work -->
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<PackageCertificateKeyFile>TemporaryKey.pfx</PackageCertificateKeyFile>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;$(SolutionDir)..\src\CalcManager;$(SolutionDir)..\src\CalcViewModel;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CalcEngineTests.cpp" />
<ClCompile Include="CalcInputTest.cpp" />
<ClCompile Include="CalculatorManagerTest.cpp" />
<ClCompile Include="CurrencyConverterUnitTests.cpp" />
<ClCompile Include="Mocks\CurrencyHttpClient.cpp" />
<ClCompile Include="Module.cpp" />
<ClCompile Include="NavCategoryUnitTests.cpp" />
<ClCompile Include="UnitConverterTest.cpp" />
<ClCompile Include="UtilsTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AsyncHelper.h" />
<ClInclude Include="DateUtils.h" />
<ClInclude Include="Helpers.h" />
<ClInclude Include="Mocks\CurrencyHttpClient.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
<ClInclude Include="UnitTestApp.xaml.h">
<DependentUpon>UnitTestApp.xaml</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="UnitTestApp.xaml">
<SubType>Designer</SubType>
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\Square44x44Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
<Image Include="Assets\StoreLogo.png" />
<Image Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AsyncHelper.cpp" />
<ClCompile Include="CopyPasteManagerTest.cpp" />
<ClCompile Include="DateCalculatorUnitTests.cpp" />
<ClCompile Include="HistoryTests.cpp" />
<ClCompile Include="MultiWindowUnitTests.cpp" />
<ClCompile Include="StandardViewModelUnitTests.cpp" />
<ClCompile Include="UnitConverterViewModelUnitTests.cpp" />
<ClCompile Include="UnitTestApp.xaml.cpp">
<DependentUpon>UnitTestApp.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Xml Include="UnitTestApp.rd.xml" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="TemporaryKey.pfx" />
<None Include="testmd.definition" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="..\..\src\Calculator\Resources\en-US\CEngineStrings.resw" />
<PRIResource Include="..\..\src\Calculator\Resources\en-US\Resources.resw" />
<PRIResource Include="Test.resw" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\CalcManager\CalcManager.vcxproj">
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
</ProjectReference>
<ProjectReference Include="..\..\src\CalcViewModel\CalcViewModel.vcxproj">
<Project>{90e9761d-9262-4773-942d-caeae75d7140}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<!-- Append the manifest version to the custom macros as we use this in the testmd.definition file. -->
<Target Name="AppendUniversalTestCustomMacros" DependsOnTargets="_CreateTestLayout" BeforeTargets="BuildUniversalTest">
<PropertyGroup>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\x86\Microsoft.VCLibs.x86.Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\x86\Microsoft.VCLibs.x86.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\x64\Microsoft.VCLibs.x64.Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\x64\Microsoft.VCLibs.x64.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\ARM\Microsoft.VCLibs.arm.Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\ARM64\Microsoft.VCLibs.arm64.Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\ARM\Microsoft.VCLibs.arm.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\ARM64\Microsoft.VCLibs.arm64.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackagePublicKeyFile=$(AppxPackagePublicKeyFile);AppxPackageOutput=$(AppxPackageOutput);</UniversalTestCustomMacros>
</PropertyGroup>
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.targets" Condition="Exists('..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.targets')" />
<Import Project="..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.targets" Condition="Exists('..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.targets')" />
<Import Project="..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.targets" Condition="Exists('..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.TestInfrastructure.UniversalTest.1.0.20181107.1\build\Microsoft.TestInfrastructure.UniversalTest.targets'))" />
<Error Condition="!Exists('..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.props'))" />
<Error Condition="!Exists('..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Taef.Native.10.34.181220007\build\native\Taef.Native.targets'))" />
<Error Condition="!Exists('..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.props'))" />
<Error Condition="!Exists('..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Taef.Native.UWP.10.34.181220007\build\native\Taef.Native.UWP.targets'))" />
</Target>
</Project>

View File

@ -1,102 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ApplicationDefinition Include="UnitTestApp.xaml" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Test.resw" />
<PRIResource Include="..\..\src\Calculator\Resources\en-US\CEngineStrings.resw" />
<PRIResource Include="..\..\src\Calculator\Resources\en-US\Resources.resw" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CalculatorManagerTest.cpp" />
<ClCompile Include="CurrencyConverterUnitTests.cpp" />
<ClCompile Include="Mocks\CurrencyHttpClient.cpp" />
<ClCompile Include="NavCategoryUnitTests.cpp" />
<ClCompile Include="UnitConverterTest.cpp" />
<ClCompile Include="UtilsTests.cpp" />
<ClCompile Include="AsyncHelper.cpp" />
<ClCompile Include="CopyPasteManagerTest.cpp" />
<ClCompile Include="DateCalculatorUnitTests.cpp" />
<ClCompile Include="HistoryTests.cpp" />
<ClCompile Include="MultiWindowUnitTests.cpp" />
<ClCompile Include="StandardViewModelUnitTests.cpp" />
<ClCompile Include="UnitConverterViewModelUnitTests.cpp" />
<ClCompile Include="UnitTestApp.xaml.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="Module.cpp" />
<ClCompile Include="CalcInputTest.cpp" />
<ClCompile Include="CalcEngineTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AsyncHelper.h" />
<ClInclude Include="DateUtils.h" />
<ClInclude Include="Helpers.h" />
<ClInclude Include="Mocks\CurrencyHttpClient.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
<ClInclude Include="UnitTestApp.xaml.h" />
</ItemGroup>
<ItemGroup>
<Xml Include="UnitTestApp.rd.xml" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\Square44x44Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
<Image Include="Assets\StoreLogo.png" />
<Image Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="TemporaryKey.pfx" />
<None Include="testmd.definition" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
<None Include="$(MSBuildThisFileDirectory)\$(Platform)\*.dll" />
</ItemGroup>
</Project>

View File

@ -1,602 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "CalcViewModel\StandardCalculatorViewModel.h"
#include "CalcViewModel\Common\CopyPasteManager.h"
using namespace CalculationManager;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel;
using namespace Platform;
using namespace std;
using namespace WEX::Logging;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Globalization;
using namespace Windows::Storage;
namespace CalculatorUnitTests
{
extern void ChangeMode(StandardCalculatorViewModel^ viewModel, int mode);
#define ASSERT_POSITIVE_TESTCASES(func, dataSet) \
{\
int size = sizeof(dataSet)/sizeof(*dataSet);\
while(--size)\
{\
VERIFY_ARE_EQUAL(func(dataSet[size]), dataSet[size]);\
}\
}
#define ASSERT_NEGATIVE_TESTCASES(func, dataSet) \
{\
int size = sizeof(dataSet)/sizeof(*dataSet);;\
while(--size)\
{\
VERIFY_ARE_EQUAL(func(dataSet[size]), StringReference(L"NoOp"));\
}\
}
// returns a iterator from end
#define START_LOOP(dataSet)\
{\
int size = sizeof(dataSet)/sizeof(*dataSet);\
while(--size)\
{
#define END_LOOP\
}\
}
class CopyPasteManagerTest
{
public:
TEST_CLASS(CopyPasteManagerTest);
TEST_METHOD(FunctionalCopyPasteTest);
TEST_METHOD(ValidateStandardPasteExpressionTest);
TEST_METHOD(ValidateScientificPasteExpressionTest);
TEST_METHOD(ValidateProgrammerDecPasteExpressionTest);
TEST_METHOD(ValidateProgrammerOctPasteExpressionTest);
TEST_METHOD(ValidateProgrammerHexPasteExpressionTest);
TEST_METHOD(ValidateProgrammerBinPasteExpressionTest);
TEST_METHOD(ValidateConverterPasteExpressionTest);
TEST_METHOD(ValidatePasteExpressionErrorStates)
{
wstring exp_TooLong = L"";
for (int i = 0; i < m_CopyPasteManager.MaxPasteableLength / 8; i++)
{
exp_TooLong += L"-1234567";
}
VERIFY_ARE_EQUAL(m_CopyPasteManager.ValidatePasteExpression(StringReference(exp_TooLong.c_str()), ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), StringReference(exp_TooLong.c_str()), L"Verify ValidatePasteExpression handles expressions up to max length");
exp_TooLong += L"1";
VERIFY_ARE_EQUAL(m_CopyPasteManager.ValidatePasteExpression(StringReference(exp_TooLong.c_str()), ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), StringReference(L"NoOp"), L"Verify ValidatePasteExpression returns NoOp for strings over max length");
VERIFY_ARE_EQUAL(m_CopyPasteManager.ValidatePasteExpression(StringReference(L""), ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), StringReference(L"NoOp"), L"Verify empty string is invalid");
VERIFY_ARE_EQUAL(m_CopyPasteManager.ValidatePasteExpression(StringReference(L"123e456"), ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), StringReference(L"NoOp"), L"Verify pasting unsupported strings for the current mode is invalid");
VERIFY_ARE_EQUAL(m_CopyPasteManager.ValidatePasteExpression(StringReference(L"123"), ViewMode::None, CategoryGroupType::None, -1, -1), StringReference(L"NoOp"), L"Verify pasting without a ViewMode or Category is invalid");
};
TEST_METHOD(ValidateExtractOperands)
{
vector<wstring> results = {};
vector<wstring> oneOperand = { L"123456" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123456", ViewMode::Standard), oneOperand);
oneOperand = { L"123^456" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123^456", ViewMode::Standard), oneOperand);
vector<wstring> twoOperands = { L"123", L"456" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123+456", ViewMode::Standard), twoOperands);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123-456", ViewMode::Standard), twoOperands);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123*456", ViewMode::Standard), twoOperands);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123/456", ViewMode::Standard), twoOperands);
vector<wstring> expOperand = { L"123e456" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123e456", ViewMode::Standard), expOperand);
expOperand = { L"123e4567" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"123e4567", ViewMode::Standard), expOperand);
vector<wstring> twoOperandsParens = { L"((45)", L"(-30))" };
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"((45)+(-30))", ViewMode::Scientific), twoOperandsParens);
};
TEST_METHOD(ValidateExtractOperandsErrors)
{
wstring exp_OperandLimit = L"";
for (int i = 0; i < m_CopyPasteManager.MaxOperandCount; i++)
{
exp_OperandLimit += L"+1";
}
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(exp_OperandLimit, ViewMode::Standard).size(), 100, L"Verify ExtractOperands handles up to MaxOperandCount operands");
exp_OperandLimit += L"+1";
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(exp_OperandLimit, ViewMode::Standard).size(), 0, L"Verify ExtractOperands returns empty vector on too many operands");
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"12e9999", ViewMode::Standard).size(), 1, L"Verify ExtractOperands handles up to 4 digit exponents");
VERIFY_ARE_EQUAL(m_CopyPasteManager.ExtractOperands(L"12e10000", ViewMode::Standard).size(), 0, L"Verify ExtractOperands returns empty vector when the exponent is too long");
};
TEST_METHOD(ValidateExpressionRegExMatch)
{
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{}, ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), L"Verify empty list of operands returns false.");
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123" }, ViewMode::None, CategoryGroupType::Calculator, -1, -1), L"Verify invalid ViewMode/CategoryGroups return false.");
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123" }, ViewMode::Currency, CategoryGroupType::None, -1, -1), L"Verify invalid ViewMode/CategoryGroups return false.");
Log::Comment(L"Verify operand lengths > max return false.");
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"12345678901234567" }, ViewMode::Standard, CategoryGroupType::Calculator, -1, -1));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123456789012345678901234567890123" }, ViewMode::Scientific, CategoryGroupType::Calculator, -1, -1));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"12345678901234567" }, ViewMode::None, CategoryGroupType::Converter, -1, -1));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"11111111111111111" }, ViewMode::Programmer, CategoryGroupType::Calculator, HexBase, QwordType));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"12345678901234567890" }, ViewMode::Programmer, CategoryGroupType::Calculator, DecBase, QwordType));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"11111111111111111111111" }, ViewMode::Programmer, CategoryGroupType::Calculator, OctBase, QwordType));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"10000000000000000000000000000000000000000000000000000000000000000" }, ViewMode::Programmer, CategoryGroupType::Calculator, BinBase, QwordType));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"9223372036854775808" }, ViewMode::Programmer, CategoryGroupType::Calculator, DecBase, QwordType), L"Verify operand values > max return false.");
VERIFY_IS_TRUE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"((((((((((((((((((((123))))))))))))))))))))" }, ViewMode::Scientific, CategoryGroupType::Calculator, -1, -1), L"Verify sanitized operand is detected as within max length.");
VERIFY_IS_TRUE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"9223372036854775807" }, ViewMode::Programmer, CategoryGroupType::Calculator, DecBase, QwordType), L"Verify operand values == max return true.");
Log::Comment(L"Verify all operands must match patterns.");
VERIFY_IS_TRUE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123", L"456" }, ViewMode::Standard, CategoryGroupType::Calculator, -1, -1));
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123", L"1e23" }, ViewMode::Standard, CategoryGroupType::Calculator, -1, -1));
VERIFY_IS_TRUE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"1.23e+456" }, ViewMode::Scientific, CategoryGroupType::Calculator, -1, -1), L"Verify operand only needs to match one pattern.");
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123", L"12345678901234567" }, ViewMode::Standard, CategoryGroupType::Calculator, -1, -1), L"Verify all operands must be within maxlength");
VERIFY_IS_FALSE(m_CopyPasteManager.ExpressionRegExMatch(vector<wstring>{ L"123", L"9223372036854775808" }, ViewMode::Programmer, CategoryGroupType::Calculator, DecBase, QwordType), L"Verify all operand must be within max value.");
};
TEST_METHOD(ValidateGetMaxOperandLengthAndValue)
{
pair<size_t, unsigned long long int> standardModeMaximums = make_pair(m_CopyPasteManager.MaxStandardOperandLength, 0);
pair<size_t, unsigned long long int> scientificModeMaximums = make_pair(m_CopyPasteManager.MaxScientificOperandLength, 0);
pair<size_t, unsigned long long int> converterModeMaximums = make_pair(m_CopyPasteManager.MaxConverterInputLength, 0);
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Standard, CategoryGroupType::None, -1, -1), standardModeMaximums, L"Verify Standard mode maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Scientific, CategoryGroupType::None, -1, -1), scientificModeMaximums, L"Verify Scientific mode maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::None, CategoryGroupType::Converter, -1, -1), converterModeMaximums, L"Verify Converter mode maximum values");
unsigned long long int ullQwordMax = UINT64_MAX;
unsigned long long int ullDwordMax = UINT32_MAX;
unsigned long long int ullWordMax = UINT16_MAX;
unsigned long long int ullByteMax = UINT8_MAX;
Log::Comment(L"Verify Programmer Mode HexBase maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, HexBase, QwordType), make_pair((size_t)16u, ullQwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, HexBase, DwordType), make_pair((size_t)8u, ullDwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, HexBase, WordType), make_pair((size_t)4u, ullWordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, HexBase, ByteType), make_pair((size_t)2u, ullByteMax));
Log::Comment(L"Verify Programmer Mode DecBase maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, DecBase, QwordType), make_pair((size_t)19u, ullQwordMax >> 1));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, DecBase, DwordType), make_pair((size_t)10u, ullDwordMax >> 1));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, DecBase, WordType), make_pair((size_t)5u, ullWordMax >> 1));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, DecBase, ByteType), make_pair((size_t)3u, ullByteMax >> 1));
Log::Comment(L"Verify Programmer Mode OctBase maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, OctBase, QwordType), make_pair((size_t)22u, ullQwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, OctBase, DwordType), make_pair((size_t)11u, ullDwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, OctBase, WordType), make_pair((size_t)6u, ullWordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, OctBase, ByteType), make_pair((size_t)3u, ullByteMax));
Log::Comment(L"Verify Programmer Mode BinBase maximum values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, BinBase, QwordType), make_pair((size_t)64u, ullQwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, BinBase, DwordType), make_pair((size_t)32u, ullDwordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, BinBase, WordType), make_pair((size_t)16u, ullWordMax));
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::Programmer, CategoryGroupType::None, BinBase, ByteType), make_pair((size_t)8u, ullByteMax));
Log::Comment(L"Verify invalid ViewModes/Categories return 0 for max values");
VERIFY_ARE_EQUAL(m_CopyPasteManager.GetMaxOperandLengthAndValue(ViewMode::None, CategoryGroupType::None, -1, -1), make_pair((size_t)0u, 0ull));
};
TEST_METHOD(ValidateSanitizeOperand)
{
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"((1234"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"1234))"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"-1234"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"12-34"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"((((1234))))"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"1'2'3'4"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"'''''1234''''"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"1_2_3_4"), L"1234");
VERIFY_ARE_EQUAL(m_CopyPasteManager.SanitizeOperand(L"______1234___"), L"1234");
};
TEST_METHOD(ValidateTryOperandToULL)
{
unsigned long long int result = 0;
Log::Comment(L"Verify TryOperandToULL HexBase conversion");
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1234", HexBase, result));
VERIFY_ARE_EQUAL(result, 0x1234ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"FF", HexBase, result));
VERIFY_ARE_EQUAL(result, 0xFFull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"FFFFFFFFFFFFFFFF", HexBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"0xFFFFFFFFFFFFFFFF", HexBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"0XFFFFFFFFFFFFFFFF", HexBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"0X0FFFFFFFFFFFFFFFF", HexBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
Log::Comment(L"Verify TryOperandToULL DecBase conversion");
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1234", DecBase, result));
VERIFY_ARE_EQUAL(result, 1234ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"18446744073709551615", DecBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"018446744073709551615", DecBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
Log::Comment(L"Verify TryOperandToULL OctBase conversion");
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"777", OctBase, result));
VERIFY_ARE_EQUAL(result, 0777ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"0777", OctBase, result));
VERIFY_ARE_EQUAL(result, 0777ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1777777777777777777777", OctBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"01777777777777777777777", OctBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
Log::Comment(L"Verify TryOperandToULL BinBase conversion");
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1111", BinBase, result));
VERIFY_ARE_EQUAL(result, 0b1111ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"0010", BinBase, result));
VERIFY_ARE_EQUAL(result, 0b10ull);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1111111111111111111111111111111111111111111111111111111111111111", BinBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"01111111111111111111111111111111111111111111111111111111111111111", BinBase, result));
VERIFY_ARE_EQUAL(result, 0xFFFF'FFFF'FFFF'FFFF);
Log::Comment(L"Verify TryOperandToULL invalid numberBase defaults to DecBase");
VERIFY_IS_TRUE(m_CopyPasteManager.TryOperandToULL(L"1234", 128, result));
VERIFY_ARE_EQUAL(result, 1234ull);
Log::Comment(L"Verify TryOperandToULL returns false when input is invalid or strtoull throws exceptions");
// Max values + 1
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"0xFFFFFFFFFFFFFFFFF1", HexBase, result));
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"18446744073709551616", DecBase, result));
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"2000000000000000000000", OctBase, result));
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"11111111111111111111111111111111111111111111111111111111111111111", BinBase, result));
// Invalid values/characters
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"-1", DecBase, result));
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"5555", BinBase, result));
VERIFY_IS_FALSE(m_CopyPasteManager.TryOperandToULL(L"xyz", BinBase, result));
};
TEST_METHOD(ValidateStandardScientificOperandLength)
{
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L""), 0);
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L"0.2"), 1);
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L"1.2"), 2);
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L"0."), 0);
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L"12345"), 5);
VERIFY_ARE_EQUAL(m_CopyPasteManager.StandardScientificOperandLength(L"-12345"), 6);
};
TEST_METHOD(ValidateProgrammerOperandLength)
{
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"1001", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"1001b", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"1001B", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0b1001", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0B1001", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0y1001", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0Y1001", BinBase), 4);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0b", BinBase), 1);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"123456", OctBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0t123456", OctBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0T123456", OctBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0o123456", OctBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0O123456", OctBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"", DecBase), 0);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"-", DecBase), 0);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"12345", DecBase), 5);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"-12345", DecBase), 5);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0n12345", DecBase), 5);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0N12345", DecBase), 5);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"123ABC", HexBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0x123ABC", HexBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"0X123ABC", HexBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"123ABCh", HexBase), 6);
VERIFY_ARE_EQUAL(m_CopyPasteManager.ProgrammerOperandLength(L"123ABCH", HexBase), 6);
};
private:
CopyPasteManager m_CopyPasteManager;
String^ ValidateStandardPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Standard, -1/*number base*/, -1/*bitlength Type*/);
}
String^ ValidateScientificPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Scientific, -1/*number base*/, -1/*bitlength Type*/);
}
String^ ValidateConverterPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::None, CategoryGroupType::Converter, -1/*number base*/, -1/*bitlength Type*/);
}
String^ ValidateProgrammerHexQwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, HexBase/*number base*/, QwordType/*bitlength Type*/);
}
String^ ValidateProgrammerHexDwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, HexBase/*number base*/, DwordType/*bitlength Type*/);
}
String^ ValidateProgrammerHexWordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, HexBase/*number base*/, WordType/*bitlength Type*/);
}
String^ ValidateProgrammerHexBytePasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, HexBase/*number base*/, ByteType/*bitlength Type*/);
}
String^ ValidateProgrammerDecQwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, DecBase/*number base*/, QwordType/*bitlength Type*/);
}
String^ ValidateProgrammerDecDwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, DecBase/*number base*/, DwordType/*bitlength Type*/);
}
String^ ValidateProgrammerDecWordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, DecBase/*number base*/, WordType/*bitlength Type*/);
}
String^ ValidateProgrammerDecBytePasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, DecBase/*number base*/, ByteType/*bitlength Type*/);
}
String^ ValidateProgrammerOctQwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, OctBase/*number base*/, QwordType/*bitlength Type*/);
}
String^ ValidateProgrammerOctDwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, OctBase/*number base*/, DwordType/*bitlength Type*/);
}
String^ ValidateProgrammerOctWordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, OctBase/*number base*/, WordType/*bitlength Type*/);
}
String^ ValidateProgrammerOctBytePasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, OctBase/*number base*/, ByteType/*bitlength Type*/);
}
String^ ValidateProgrammerBinQwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, BinBase/*number base*/, QwordType/*bitlength Type*/);
}
String^ ValidateProgrammerBinDwordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, BinBase/*number base*/, DwordType/*bitlength Type*/);
}
String^ ValidateProgrammerBinWordPasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, BinBase/*number base*/, WordType/*bitlength Type*/);
}
String^ ValidateProgrammerBinBytePasteExpression(_In_ String^ pastedText)
{
return m_CopyPasteManager.ValidatePasteExpression(pastedText, ViewMode::Programmer, BinBase/*number base*/, ByteType/*bitlength Type*/);
}
};
/*************************************
standard:
can paste simple numbers / expressions not exponential numbers / expressions
scientific :
can paste exponential numbers / expressions too
programmer :
can paste specific numbers / expressions based on radixes.Hex numbers such 13abe is allowed when radix is set to hex, but not allowed otherwise.
converter :
can paste simple numbers not expressions
List of test cases:
1. simple unsigned number
2. negative number
3. exponential number with positive exp
4. exponential number with negative exp
5. exponential number with unsigned exp
6. exponential number with very large(larger than 4 digit) exp
7. expression involving simple numbers
8. expression involving exponential numbers
9. number with random text like xyz
10. hex numbers
11. binary numbers
12. octal numbers
13. very large number
14. number with some escape characters in b/w like ",/. \n\r ", '"
15. expression involving sin, cos or other mathematic functions
16. expression having more than one operator in b/w operands
17. expression involving open and close parenthesis (, )
****************************************/
void CopyPasteManagerTest::FunctionalCopyPasteTest()
{
// Doesn't have test where converter is involved. Will add such a test later.
StandardCalculatorViewModel^ scvm = ref new StandardCalculatorViewModel();
scvm->IsStandard = true;
String^ input[] = { L"123", L"12345", L"123+456", L"1,234", L"1 2 3", L"\n\r1,234\n", L"\n 1+\n2 ", L"1\"2" };
START_LOOP(input)
// paste number in standard mode and then validate the pastability of displayed number for other modes
scvm->OnPaste(input[size], ViewMode::Standard);
VERIFY_ARE_EQUAL(ValidateStandardPasteExpression(scvm->DisplayValue), scvm->DisplayValue);
VERIFY_ARE_EQUAL(ValidateScientificPasteExpression(scvm->DisplayValue), scvm->DisplayValue);
VERIFY_ARE_EQUAL(ValidateProgrammerHexQwordPasteExpression(scvm->DisplayValue), scvm->DisplayValue);
END_LOOP
}
void CopyPasteManagerTest::ValidateStandardPasteExpressionTest()
{
String^ positiveInput[] = { L"123", L"+123", L"-133", L"12345.", L"+12.34", L"12.345", L"012.034", L"-23.032", L"-.123", L".1234", L"012.012", L"123+456", L"123+-234", L"123*-345", L"123*4*-3", L"123*+4*-3", L"1,234", L"1 2 3", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"1234567891234567"/*boundary condition <=16 digits*/, L"2+2=", L"2+2= " };
String^ negativeInput[] = { L"(123)+(456)", L"1.2e23"/*unsigned exponent*/, L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"12345678912345678"/*boundary condition: greater than 16 digits*/, L"SIN(2)", L"2+2==", L"2=+2" };
ASSERT_POSITIVE_TESTCASES(ValidateStandardPasteExpression, positiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateStandardPasteExpression, negativeInput);
}
void CopyPasteManagerTest::ValidateScientificPasteExpressionTest()
{
String^ positiveInput[] = { L"123", L"+123", L"-133", L"123+456", L"12345e+023", L"1,234", L"1.23", L"-.123", L".1234", L"012.012", L"123+-234", L"123*-345", L"123*4*-3", L"123*+4*-3", L"1 2 3", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"1.2e+023", L"12345e-23", L"(123)+(456)", L"12345678912345678123456789012345", L"(123)+(456)=", L"2+2= " };
String^ negativeInput[] = { L"1.2e23"/*unsigned exponent*/, L"abcdef", L"xyz", L"ABab", L"e+234", L"123456789123456781234567890123456"/*boundary condition: greater than 32 digits*/, L"SIN(2)", L"2+2==", L"2=+2" };
ASSERT_POSITIVE_TESTCASES(ValidateScientificPasteExpression, positiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateScientificPasteExpression, negativeInput);
}
void CopyPasteManagerTest::ValidateProgrammerHexPasteExpressionTest()
{
String^ qwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"12345e-23"/*note: here is considered as E of hex*/, L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"e+234", L"1\"2", L"(123)+(456)", L"abcdef", L"ABab", L"ABCDF21abc41a"/*within boundary*/, L"0x1234", L"0xab12", L"0X1234", L"AB12h", L"BC34H", L"1234u", L"1234ul", L"1234ULL", L"2+2=", L"2+2= " };
String^ qwordNegativeInput[] = { L"+123", L"1.23"/*floating number*/, L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e+023", L"1.2e23"/*unsigned exponent*/, L"xyz", L"ABCDEF21abc41abc7"/*outside boundary of 16 digitis*/, L"SIN(2)", L"123+-234", L"1234x", L"A0x1234", L"0xx1234", L"1234uu", L"1234ulll", L"2+2==", L"2=+2" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerHexQwordPasteExpression, qwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerHexQwordPasteExpression, qwordNegativeInput);
String^ dwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"12345e-23"/*note: here is considered as E of hex*/, L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"e+234", L"1\"2", L"(123)+(456)", L"abcdef", L"ABab", L"ABCD123a"/*within boundary*/, L"0x1234", L"0xab12", L"0X1234", L"AB12h", L"BC34H", L"1234u", L"1234ul", L"1234ULL" };
String^ dwordNegativeInput[] = { L"+123", L"1.23"/*floating number*/, L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e+023", L"1.2e23"/*unsigned exponent*/, L"xyz", L"ABCD123ab"/*outside boundary of 8 digitis*/, L"SIN(2)", L"123+-234", L"1234x", L"A0x1234", L"0xx1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerHexDwordPasteExpression, dwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerHexDwordPasteExpression, dwordNegativeInput);
String^ wordPositiveInput[] = { L"123", L"13+456", L"1,34", L"12 3", L"1'2'3'4", L"1_2_3_4", L"15e-23"/*note: here is considered as E of hex*/, L"\r1", L"\n\r1,4", L"\n1,4\n", L"\f\n1+2\t\r\v", L"\n 1+\n2 ", L"e+24", L"1\"2", L"(23)+(4)", L"aef", L"ABab", L"A1a3"/*within boundary*/, L"0x1234", L"0xab12", L"0X1234", L"AB12h", L"BC34H", L"1234u", L"1234ul", L"1234ULL" };
String^ wordNegativeInput[] = { L"+123", L"1.23"/*floating number*/, L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e+023", L"1.2e23"/*unsigned exponent*/, L"xyz", L"A1a3b"/*outside boundary of 4 digitis*/, L"SIN(2)", L"123+-234", L"1234x", L"A0x1234", L"0xx1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerHexWordPasteExpression, wordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerHexWordPasteExpression, wordNegativeInput);
String^ bytePositiveInput[] = { L"13", L"13+6", L"1,4", L"2 3", L"1'2", L"1_2", L"5e-3"/*note: here is considered as E of hex*/, L"\r1", L"a", L"ab", L"A1"/*within boundary*/, L"0x12", L"0xab", L"0X12", L"A9h", L"B8H", L"12u", L"12ul", L"12ULL" };
String^ byteNegativeInput[] = { L"+3", L"1.2"/*floating number*/, L"1''2", L"'12", L"12'", L"1__2", L"_12", L"12_", L"-3", L"1.1e+02", L"1.2e3"/*unsigned exponent*/, L"xz", L"A3a"/*outside boundary of 2 digitis*/, L"SIN(2)", L"13+-23", L"12x", L"A0x1", L"0xx12", L"12uu", L"12ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerHexBytePasteExpression, bytePositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerHexBytePasteExpression, byteNegativeInput);
}
void CopyPasteManagerTest::ValidateProgrammerDecPasteExpressionTest()
{
String^ qwordPositiveInput[] = { L"123", L"+123", L"-133", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"123+-234", L"123*-345", L"123*4*-3", L"123*+4*-3", L"9223372036854775807", L"-9223372036854775807"/*boundary condition: max/min allowed number*/, L"0n1234", L"0N1234", L"1234u", L"1234ul", L"1234ULL", L"2+2=", L"2+2= " };
String^ qwordNegativeInput[] = { L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"9223372036854775809"/*boundary condition: greater than max allowed number 9223372036854775807*/, L"SIN(2)", L"-0n123", L"0nn1234", L"1234uu", L"1234ulll", L"2+2==", L"2=+2" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerDecQwordPasteExpression, qwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerDecQwordPasteExpression, qwordNegativeInput);
String^ dwordPositiveInput[] = { L"123", L"+123", L"-133", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"123+-234", L"123*-345", L"123*4*-3", L"123*+4*-3", L"2147483647", L"-2147483647"/*boundary condition: max/min allowed number*/, L"0n1234", L"0N1234", L"1234u", L"1234ul", L"1234ULL" };
String^ dwordNegativeInput[] = { L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"2147483649"/*boundary condition: greater than max allowed number 2147483647*/, L"SIN(2)", L"-0n123", L"0nn1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerDecDwordPasteExpression, dwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerDecDwordPasteExpression, dwordNegativeInput);
String^ wordPositiveInput[] = { L"123", L"+123", L"-133", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\f\n1+2\t\r\v\x85", L"1\"2", L"(123)+(456)", L"123+-234", L"123*-345", L"123*4*-3", L"123*+4*-3", L"32767", L"-32767"/*boundary condition: max/min allowed number*/, L"0n1234", L"0N1234", L"1234u", L"1234ul", L"1234ULL" };
String^ wordNegativeInput[] = { L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"32769"/*boundary condition: greater than max allowed number 32769*/, L"SIN(2)", L"-0n123", L"0nn1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerDecWordPasteExpression, wordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerDecWordPasteExpression, wordNegativeInput);
String^ bytePositiveInput[] = { L"13", L"+13", L"-13", L"13+46", L"13+-34", L"13*-3", L"3*4*-3", L"3*+4*-3", L"1,3", L"1 3", L"1'2'3", L"1_2_3", L"1\"2", L"127", L"-127"/*boundary condition: max/min allowed number*/, L"0n123", L"0N123", L"123u", L"123ul", L"123ULL" };
String^ byteNegativeInput[] = { L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"15e-23", L"abcdef", L"xyz", L"ABab", L"e+24", L"129"/*boundary condition: greater than max allowed number 127*/, L"SIN(2)", L"-0n123", L"0nn1234", L"123uu", L"123ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerDecBytePasteExpression, bytePositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerDecBytePasteExpression, byteNegativeInput);
}
void CopyPasteManagerTest::ValidateProgrammerOctPasteExpressionTest()
{
String^ qwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"0t1234", L"0T1234", L"0o1234", L"0O1234", L"1234u", L"1234ul", L"1234ULL", L"2+2=", L"2+2= " };
String^ qwordNegativeInput[] = { L"+123", L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"12345678901234567890123"/*boundary condition: greater than max allowed digits 22*/, L"SIN(2)", L"123+-234", L"0ot1234", L"1234uu", L"1234ulll", L"2+2==", L"2=+2" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerOctQwordPasteExpression, qwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerOctQwordPasteExpression, qwordNegativeInput);
String^ dwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"37777777777"/*boundary condition: max allowed number*/, L"0t1234", L"0T1234", L"0o1234", L"0O1234", L"1234u", L"1234ul", L"1234ULL" };
String^ dwordNegativeInput[] = { L"+123", L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"377777777771"/*boundary condition: greater than max allowed number 37777777777*/, L"SIN(2)", L"123+-234", L"0ot1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerOctDwordPasteExpression, dwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerOctDwordPasteExpression, dwordNegativeInput);
String^ wordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\f\n1+2\t\r\v\x85", L"1\"2", L"(123)+(456)", L"177777"/*boundary condition: max allowed number*/, L"0t1234", L"0T1234", L"0o1234", L"0O1234", L"1234u", L"1234ul", L"1234ULL" };
String^ wordNegativeInput[] = { L"+123", L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-133", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"12345e-23", L"abcdef", L"xyz", L"ABab", L"e+234", L"1777771"/*boundary condition: greater than max allowed number 177777*/, L"SIN(2)", L"123+-234", L"0ot1234", L"1234uu", L"1234ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerOctWordPasteExpression, wordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerOctWordPasteExpression, wordNegativeInput);
String^ bytePositiveInput[] = { L"13", L"13+46", L"1,3", L"1 3", L"1'2'3", L"1_2_3", L"1\"2", L"377"/*boundary condition: max allowed number*/, L"0t123", L"0T123", L"0o123", L"0O123", L"123u", L"123ul", L"123ULL" };
String^ byteNegativeInput[] = { L"+123", L"1.23", L"1''2", L"'123", L"123'", L"1__2", L"_123", L"123_", L"-13", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"15e-23", L"abcdef", L"xyz", L"ABab", L"e+24", L"477"/*boundary condition: greater than max allowed number 377*/, L"SIN(2)", L"123+-34", L"0ot123", L"123uu", L"123ulll" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerOctBytePasteExpression, bytePositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerOctBytePasteExpression, byteNegativeInput);
}
void CopyPasteManagerTest::ValidateProgrammerBinPasteExpressionTest()
{
String^ qwordPositiveInput[] = { L"100", L"100+101", L"1,001", L"1 0 1", L"1'0'0'1", L"1_0_0_1", L"\n\r1,010\n", L"\f\n1+11\t\r\v\x85", L"\n 1+\n1 ", L"1\"1", L"(101)+(10)", L"0b1001", L"0B1111", L"0y1001", L"0Y1001", L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"1010101010101010101010101011110110100100101010101001010101001010"/*boundary condition: max allowed digits 64*/, L"1+10=", L"1+10= " };
String^ qwordNegativeInput[] = { L"+10101", L"1.01", L"1''0", L"'101", L"101'", L"1__0", L"_101", L"101_", L"-10101001", L"123", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"101010e-1010", L"abcdef", L"xyz", L"ABab", L"e+10101", L"b1001", L"10b01", L"0x10", L"1001x", L"1001h", L"0bb1111", L"1111uu", L"1111ulll", L"10101010101010101010101010111101101001001010101010010101010010100"/*boundary condition: greater than max allowed digits 64*/, L"SIN(01010)", L"10+-10101010101", L"1+10==", L"1=+10" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerBinQwordPasteExpression, qwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerBinQwordPasteExpression, qwordNegativeInput);
String^ dwordPositiveInput[] = { L"100", L"100+101", L"1,001", L"1 0 1", L"1'0'0'1", L"1_0_0_1", L"\n\r1,010\n", L"\f\n1+11\t\r\v\x85", L"\n 1+\n1 ", L"1\"1", L"(101)+(10)", L"0b1001", L"0B1111", L"0y1001", L"0Y1001", L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"10101001001010101101010111111100"/*boundary condition: max allowed number*/ };
String^ dwordNegativeInput[] = { L"+10101", L"1.01", L"1''0", L"'101", L"101'", L"1__0", L"_101", L"101_", L"-10101001", L"123", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"101010e-1010", L"abcdef", L"xyz", L"ABab", L"e+10101", L"b1001", L"10b01", L"0x10", L"1001x", L"1001h", L"0bb1111", L"1111uu", L"1111ulll", L"101010010010101011010101111111001"/*boundary condition: greater than max allowed digits 32*/, L"SIN(01010)", L"10+-10101010101" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerBinDwordPasteExpression, dwordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerBinDwordPasteExpression, dwordNegativeInput);
String^ wordPositiveInput[] = { L"100", L"100+101", L"1,001", L"1 0 1", L"1'0'0'1", L"1_0_0_1", L"\n\r1,010\n", L"\f\n1+11\t\r\v\x85", L"\n 1+\n1 ", L"1\"1", L"(101)+(10)", L"0b1001", L"0B1111", L"0y1001", L"0Y1001", L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"1010101010010010"/*boundary condition: max allowed number*/ };
String^ wordNegativeInput[] = { L"+10101", L"1.01", L"1''0", L"'101", L"101'", L"1__0", L"_101", L"101_", L"-10101001", L"123", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"101010e-1010", L"abcdef", L"xyz", L"ABab", L"e+10101", L"b1001", L"10b01", L"0x10", L"1001x", L"1001h", L"0bb1111", L"1111uu", L"1111ulll", L"10101010100100101"/*boundary condition: greater than max allowed digits 16*/, L"SIN(01010)", L"10+-10101010101" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerBinWordPasteExpression, wordPositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerBinWordPasteExpression, wordNegativeInput);
String^ bytePositiveInput[] = { L"100", L"100+101", L"1,001", L"1 0 1", L"1'0'0'1", L"1_0_0_1", L"\n\r1,010\n", L"\n 1+\n1 ", L"1\"1", L"(101)+(10)", L"0b1001", L"0B1111", L"0y1001", L"0Y1001", L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"10100010"/*boundary condition: max allowed number*/ };
String^ byteNegativeInput[] = { L"+10101", L"1.01", L"1''0", L"'101", L"101'", L"1__0", L"_101", L"101_", L"-10101001", L"123", L"1.2e23"/*unsigned exponent*/, L"1.2e+023", L"101010e-1010", L"abcdef", L"xyz", L"ABab", L"e+10101", L"b1001", L"10b01", L"0x10", L"1001x", L"1001h", L"0bb1111", L"1111uu", L"1111ulll", L"101000101"/*boundary condition: greater than max allowed digits 8*/, L"SIN(01010)", L"10+-1010101" };
ASSERT_POSITIVE_TESTCASES(ValidateProgrammerBinBytePasteExpression, bytePositiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateProgrammerBinBytePasteExpression, byteNegativeInput);
}
void CopyPasteManagerTest::ValidateConverterPasteExpressionTest()
{
String^ positiveInput[] = { L"123", L"+123", L"-133", L"12345.", L"012.012", L"1,234", L"1 2 3", L"\n\r1,234\n", L"\f\n12\t\r\v\x85", L"1\"2", L"100=", L"100= " };
String^ negativeInput[] = { L"(123)+(456)", L"1.2e23"/*unsigned exponent*/, L"12345e-23", L"\n 1+\n2 ", L"123+456", L"abcdef", L"\n 1+\n2 ", L"xyz", L"ABab", L"e+234", L"12345678912345678"/*boundary condition: greater than 16 bits*/, L"SIN(2)", L"123+-234", L"100==", L"=100" };
ASSERT_POSITIVE_TESTCASES(ValidateConverterPasteExpression, positiveInput);
ASSERT_NEGATIVE_TESTCASES(ValidateConverterPasteExpression, negativeInput);
}
}

View File

@ -1,605 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "CalcViewModel\DataLoaders\CurrencyDataLoader.h"
#include "CalcViewModel\Common\LocalizationService.h"
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Common::LocalizationServiceProperties;
using namespace CalculatorApp::DataLoaders;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorUnitTests;
using namespace Concurrency;
using namespace Platform;
using namespace std;
using namespace UnitConversionManager;
using namespace Windows::Foundation;
using namespace Windows::Storage;
using namespace Windows::Web::Http;
namespace CalculatorApp
{
namespace DataLoaders
{
class MockCurrencyHttpClientWithResult : public CurrencyHttpClient
{
public:
MockCurrencyHttpClientWithResult(String^ staticResponse, String^ allRatiosResponse) :
m_staticResponse(staticResponse),
m_allRatiosResponse(allRatiosResponse)
{
}
IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyMetadata() override
{
return ref new MockAsyncOperationWithProgress(m_staticResponse);
}
IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyRatios() override
{
return ref new MockAsyncOperationWithProgress(m_allRatiosResponse);
}
private:
String^ m_staticResponse;
String^ m_allRatiosResponse;
};
class MockCurrencyHttpClientThrowsException : public CurrencyHttpClient
{
public:
MockCurrencyHttpClientThrowsException() {}
IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyMetadata() override
{
throw ref new NotImplementedException();
}
IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyRatios() override
{
throw ref new NotImplementedException();
}
};
}
}
class DataLoadedCallback : public UnitConversionManager::IViewModelCurrencyCallback
{
public:
DataLoadedCallback(task_completion_event<void> tce) :
m_task_completion_event{ tce }
{}
void CurrencyDataLoadFinished(bool didLoad) override
{
m_task_completion_event.set();
}
void CurrencySymbolsCallback(_In_ const wstring& fromSymbol, _In_ const wstring& toSymbol) override {}
void CurrencyRatiosCallback(_In_ const wstring& ratioEquality, _In_ const wstring& accRatioEquality) override {}
void CurrencyTimestampCallback(_In_ const std::wstring& timestamp, bool isWeekOldData) override {}
void NetworkBehaviorChanged(_In_ int newBehavior) override {}
private:
Concurrency::task_completion_event<void> m_task_completion_event;
};
namespace CalculatorUnitTests
{
constexpr auto sc_Language_EN = L"en-US";
const UCM::Category CURRENCY_CATEGORY = { NavCategory::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
unique_ptr<CurrencyDataLoader> MakeLoaderWithResults(String^ staticResponse, String^ allRatiosResponse)
{
auto client = make_unique<MockCurrencyHttpClientWithResult>(staticResponse, allRatiosResponse);
client->SetSourceCurrencyCode(StringReference(DefaultCurrencyCode.data()));
return make_unique<CurrencyDataLoader>(move(client));
}
String^ SerializeContent(const vector<String^>& data)
{
String^ result = L"";
String^ delimiter = CurrencyDataLoaderConstants::CacheDelimiter;
for (String^ content : data)
{
result += (delimiter + content);
}
return result;
}
bool WriteToFileInLocalCacheFolder(String^ filename, String^ content)
{
try
{
StorageFolder^ localFolder = ApplicationData::Current->LocalCacheFolder;
StorageFile^ file = create_task(localFolder->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting)).get();
create_task(FileIO::WriteTextAsync(file, content)).wait();
return true;
}
catch (Exception^ ex)
{
return false;
}
}
bool DeleteFileFromLocalCacheFolder(String^ filename)
{
try
{
StorageFolder^ folder = ApplicationData::Current->LocalCacheFolder;
IAsyncOperation<StorageFile^>^ fileOperation = folder->GetFileAsync(filename);
StorageFile^ file = create_task(fileOperation).get();
create_task(file->DeleteAsync()).get();
return true;
}
catch (Platform::Exception^ ex)
{
// FileNotFoundException is a valid result
return ex->HResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
catch (...)
{
return false;
}
}
bool DeleteCurrencyCacheFiles()
{
try
{
bool deletedStaticData = DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename);
bool deletedAllRatiosData = DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename);
return deletedStaticData && deletedAllRatiosData;
}
catch (...)
{
return false;
}
}
void InsertToLocalSettings(String^ key, Object^ value)
{
ApplicationData::Current->LocalSettings->Values->Insert(key, value);
}
void RemoveFromLocalSettings(String^ key)
{
// Safe to call, even if the key does not exist.
ApplicationData::Current->LocalSettings->Values->Remove(key);
}
void StandardCacheSetup()
{
// Insert current time so data is less than a day old.
DateTime now = Utils::GetUniversalSystemTime();
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, StringReference(sc_Language_EN));
VERIFY_IS_TRUE(DeleteCurrencyCacheFiles());
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
}
class CurrencyConverterLoadTests
{
public:
TEST_CLASS(CurrencyConverterLoadTests);
TEST_METHOD_SETUP(DeleteCacheFiles)
{
return DeleteCurrencyCacheFiles();
}
TEST_METHOD(LoadFromCache_Fail_NoCacheKey)
{
RemoveFromLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey);
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromCache_Fail_OlderThanADay)
{
// Insert 24 hours ago so data is considered stale.
// This will cause the load from cache to fail.
DateTime now = Utils::GetUniversalSystemTime();
DateTime dayOld;
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromCache_Fail_StaticDataFileDoesNotExist)
{
// Insert current time so data is less than a day old.
// This will cause the load to continue to attempt to load the file.
DateTime now = Utils::GetUniversalSystemTime();
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename));
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromCache_Fail_AllRatiosDataFileDoesNotExist)
{
// Insert current time so data is less than a day old.
// This will cause the load to continue to attempt to load the file.
DateTime now = Utils::GetUniversalSystemTime();
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromCache_Fail_ResponseLanguageChanged)
{
DateTime now = Utils::GetUniversalSystemTime();
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
// Tests always use en-US as response language. Insert a different lang-code to fail the test.
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, L"ar-SA");
VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromCache_Success)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromCacheAsync().get();
VERIFY_IS_TRUE(didLoad);
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
}
TEST_METHOD(LoadFromWeb_Fail_ClientIsNullptr)
{
CurrencyDataLoader loader{ nullptr };
bool didLoad = loader.TryLoadDataFromWebAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
}
TEST_METHOD(LoadFromWeb_Fail_WebException)
{
CurrencyDataLoader loader{ make_unique<MockCurrencyHttpClientThrowsException>() };
bool didLoad = loader.TryLoadDataFromWebAsync().get();
VERIFY_IS_FALSE(didLoad);
VERIFY_IS_FALSE(loader.LoadFinished());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
}
TEST_METHOD(LoadFromWeb_Success)
{
String^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
String^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
bool didLoad = loader->TryLoadDataFromWebAsync().get();
VERIFY_IS_TRUE(didLoad);
VERIFY_IS_TRUE(loader->LoadFinished());
VERIFY_IS_TRUE(loader->LoadedFromWeb());
}
TEST_METHOD(Load_Success_LoadedFromCache)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
}
TEST_METHOD(Load_Success_LoadedFromWeb)
{
// Insert 24 hours ago so data is considered stale.
// This will cause the load from cache to fail.
DateTime now = Utils::GetUniversalSystemTime();
DateTime dayOld;
dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
String^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
String^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
auto data_loaded_event = task_completion_event<void>();
loader->SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader->LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader->LoadFinished());
VERIFY_IS_FALSE(loader->LoadedFromCache());
VERIFY_IS_TRUE(loader->LoadedFromWeb());
}
};
class CurrencyConverterUnitTests
{
TEST_CLASS(CurrencyConverterUnitTests);
const UCM::Unit GetUnit(const vector<UCM::Unit>& unitList, const wstring& target)
{
return *find_if(begin(unitList), end(unitList), [&target](const UCM::Unit& u) { return u.abbreviation == target; });
}
TEST_METHOD(Loaded_LoadOrderedUnits)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
VERIFY_ARE_EQUAL(StringReference(L"United States - Dollar"), ref new String(usdUnit.name.c_str()));
VERIFY_ARE_EQUAL(StringReference(L"USD"), ref new String(usdUnit.abbreviation.c_str()));
VERIFY_ARE_EQUAL(StringReference(L"Europe - Euro"), ref new String(eurUnit.name.c_str()));
VERIFY_ARE_EQUAL(StringReference(L"EUR"), ref new String(eurUnit.abbreviation.c_str()));
}
TEST_METHOD(Loaded_LoadOrderedRatios)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> ratios = loader.LoadOrderedRatios(usdUnit);
VERIFY_ARE_EQUAL(size_t{ 2 }, ratios.size());
UCM::ConversionData usdRatioData = ratios[usdUnit];
VERIFY_IS_TRUE((std::abs(1.0 - usdRatioData.ratio) < 1e-1));
UCM::ConversionData eurRatioData = ratios[eurUnit];
VERIFY_IS_TRUE((std::abs(0.920503 - eurRatioData.ratio) < 1e-6));
}
TEST_METHOD(Loaded_GetCurrencySymbols_Valid)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
const pair<wstring, wstring> symbols = loader.GetCurrencySymbols(usdUnit, eurUnit);
VERIFY_ARE_EQUAL(ref new String(L"$"), StringReference(symbols.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.second.c_str()));
}
TEST_METHOD(Loaded_GetCurrencySymbols_Invalid)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
const UCM::Unit fakeUnit1 = {
1, L"fakeUnit1", L"FUD1", false, false, false
};
const UCM::Unit fakeUnit2 = {
2, L"fakeUnit2", L"FUD2", false, false, false
};
pair<wstring, wstring> symbols = loader.GetCurrencySymbols(fakeUnit1, fakeUnit2);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.second.c_str()));
// Verify that when only one unit is valid, both symbols return as empty string.
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
symbols = loader.GetCurrencySymbols(fakeUnit1, usdUnit);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.second.c_str()));
symbols = loader.GetCurrencySymbols(usdUnit, fakeUnit1);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(symbols.second.c_str()));
}
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Valid)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
const pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(usdUnit, eurUnit);
VERIFY_ARE_EQUAL(ref new String(L"1 USD = 0.9205 EUR"), StringReference(ratio.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L"1 United States Dollar = 0.9205 Europe Euro"), StringReference(ratio.second.c_str()));
}
TEST_METHOD(Loaded_GetCurrencyRatioEquality_Invalid)
{
StandardCacheSetup();
CurrencyDataLoader loader{ nullptr };
auto data_loaded_event = task_completion_event<void>();
loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
auto data_loaded_task = create_task(data_loaded_event);
loader.LoadData();
data_loaded_task.wait();
VERIFY_IS_TRUE(loader.LoadFinished());
VERIFY_IS_TRUE(loader.LoadedFromCache());
VERIFY_IS_FALSE(loader.LoadedFromWeb());
const UCM::Unit fakeUnit1 = {
1, L"fakeUnit1", L"fakeCountry1", L"FUD1", false, false, false
};
const UCM::Unit fakeUnit2 = {
2, L"fakeUnit2", L"fakeCountry2", L"FUD2", false, false, false
};
pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(fakeUnit1, fakeUnit2);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.second.c_str()));
// Verify that when only one unit is valid, both symbols return as empty string.
vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
ratio = loader.GetCurrencyRatioEquality(fakeUnit1, usdUnit);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.second.c_str()));
ratio = loader.GetCurrencyRatioEquality(usdUnit, fakeUnit1);
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.first.c_str()));
VERIFY_ARE_EQUAL(ref new String(L""), StringReference(ratio.second.c_str()));
}
};
}

View File

@ -1,582 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "DateUtils.h"
#include "CalcViewModel\Common\DateCalculator.h"
#include "CalcViewModel\DateCalculatorViewModel.h"
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Globalization;
using namespace Windows::Globalization::DateTimeFormatting;
using namespace CalculatorApp::Common::DateCalculation;
using namespace CalculatorApp::ViewModel;
namespace DateCalculationUnitTests
{
const int c_numDate = 15;
const int c_diffTestCase = 9;
const int c_numAddOobDate = 2;
const int c_numSubtractOobDate = 2;
const int c_addCases = 3;
const int c_subtractCases = 3;
const int c_dateDiff = 14;
DateCalculationEngine m_DateCalcEngine(CalendarIdentifiers::Gregorian);
typedef struct
{
SYSTEMTIME startDate;
SYSTEMTIME endDate;
DateDifference dateDiff;
} DateTimeTestCase;
SYSTEMTIME date[c_numDate];
DateDifference dateDifference[c_dateDiff];
DateTimeTestCase datetimeDifftest[c_diffTestCase];
DateTimeTestCase datetimeBoundAdd[c_numAddOobDate];
DateTimeTestCase datetimeBoundSubtract[c_numSubtractOobDate];
DateTimeTestCase datetimeAddCase[c_addCases];
DateTimeTestCase datetimeSubtractCase[c_subtractCases];
// Test Class
class DateCalculatorUnitTests
{
public:
TEST_CLASS(DateCalculatorUnitTests);
TEST_CLASS_SETUP(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
return true;
}
/* 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++)
{
DateTime endDate;
// Subtract Duration
bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate), datetimeBoundSubtract[testIndex].dateDiff, &endDate);
// Assert for the result
VERIFY_IS_FALSE(isValid);
}
}
// 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);
// // Assert for the result
// VERIFY_IS_TRUE(isValid);
// 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_TRUE(isValid);
//}
}
// Subtract Tests
TEST_METHOD(TestSubtraction)
{
// TODO - MSFT 10331900, fix this test
//for (int testIndex = 0; testIndex < c_subtractCases; testIndex++)
//{
// DateTime endDate;
// // Subtract Duration
// bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeSubtractCase[testIndex].startDate), datetimeSubtractCase[testIndex].dateDiff, &endDate);
// // assert for the result
// VERIFY_IS_TRUE(isValid);
// 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_TRUE(isValid);
//}
}
private:
};
class DateCalculatorViewModelTests
{
public:
TEST_CLASS(DateCalculatorViewModelTests);
TEST_CLASS_SETUP(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
return true;
}
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(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(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(DateCalcViewModelDateDiffResultInDaysTest)
{
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());
}
}
};
}

View File

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
namespace DateCalculationUnitTests
{
/** Date Utils **/
class DateUtils
{
public:
// Converts SYSTEMTIME structure to DateTime value
// Converts: SYSTEMTIME -> FILETIME -> DateTime
static Windows::Foundation::DateTime SystemTimeToDateTime(SYSTEMTIME systemTime)
{
LPFILETIME lpFileTime = new FILETIME();
SystemTimeToFileTime(&systemTime, lpFileTime);
Windows::Foundation::DateTime dateTime;
dateTime.UniversalTime = (DWORD)lpFileTime->dwHighDateTime;
dateTime.UniversalTime <<= 32;
dateTime.UniversalTime |= (DWORD)lpFileTime->dwLowDateTime;
return dateTime;
}
// Converts DateTime value to SYSTEMTIME structure
// Converts: DateTime -> FILETIME -> SYSTEMTIME
static SYSTEMTIME DateTimeToSystemTime(Windows::Foundation::DateTime dateTime)
{
FILETIME fileTime;
fileTime.dwLowDateTime = (DWORD)(dateTime.UniversalTime & 0xffffffff);
fileTime.dwHighDateTime = (DWORD)(dateTime.UniversalTime >> 32);
SYSTEMTIME systemTime;
FileTimeToSystemTime(&fileTime, &systemTime);
return systemTime;
}
// Returns long date format for a date
static Platform::String^ GetLongDate(SYSTEMTIME systemTime)
{
auto formatter = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter(
L"longdate",
Windows::Globalization::ApplicationLanguages::Languages,
Windows::System::UserProfile::GlobalizationPreferences::HomeGeographicRegion,
Windows::Globalization::CalendarIdentifiers::Gregorian,
Windows::Globalization::ClockIdentifiers::TwentyFourHour);
Windows::Foundation::DateTime dateTime = SystemTimeToDateTime(systemTime);
return formatter->Format(dateTime);
}
};
}

View File

@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#pragma once
#include "CalcViewModel\Common\CalculatorButtonUser.h"
namespace CalculatorUnitTests
{
#define StandardModePrecision 16
#define ScientificModePrecision 32
#define ProgrammerModePrecision 64
typedef struct item
{
CalculatorApp::NumbersAndOperatorsEnum command;
std::wstring expectedPrimaryDisplay;
std::wstring expectedExpressions;
} TESTITEM;
namespace UtfUtils {
constexpr wchar_t LRE = 0x202a; // Left-to-Right Embedding
constexpr wchar_t PDF = 0x202c; // Pop Directional Formatting
constexpr wchar_t LRO = 0x202d; // Left-to-Right Override
constexpr wchar_t MUL = 0x00d7; // Multiplication Symbol
}
}

View File

@ -1,533 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "CalcViewModel\HistoryViewModel.h"
#include "CalcViewModel\StandardCalculatorViewModel.h"
using namespace CalculationManager;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorUnitTests;
using namespace Platform;
using namespace std;
using namespace Windows::Storage;
using namespace Windows::ApplicationModel::Resources;
namespace CalculatorFunctionalTests
{
class HistoryTests
{
public:
TEST_CLASS(HistoryTests);
TEST_METHOD(TestHistoryItemClicked);
TEST_METHOD(TestHistoryItemAddSingleItem);
TEST_METHOD(TestHistoryItemAddMaxItems);
TEST_METHOD(TestHistoryClearCommand);
TEST_METHOD(TestHistoryClearCommandWithEmptyHistory);
TEST_METHOD(TestReLoadHistory);
TEST_METHOD(TestSaveAndReloadHistory);
TEST_METHOD(TestSerializeDeSerializeHistoryItem);
TEST_METHOD(TestHistoryItemWithPrettyExpressions);
TEST_METHOD(TestHistoryItemWithPrettyExpressionsMixedRadix);
TEST_METHOD(TestHistoryItemLoadAndContinueCalculation);
TEST_METHOD(TestDisplayValueAutomationNames);
TEST_METHOD(TestRadixAutomationName);
TEST_METHOD(TestHistoryEmpty);
private:
HistoryViewModel^ m_historyViewModel;
StandardCalculatorViewModel^ m_standardViewModel;
void Initialize(unsigned int windowId = 0)
{
m_standardViewModel = ref new StandardCalculatorViewModel();
m_standardViewModel->IsStandard = true;
m_historyViewModel = ref new HistoryViewModel(m_standardViewModel->m_standardCalculatorManager.get());
m_historyViewModel->SetCalculatorDisplay(m_standardViewModel->m_calculatorDisplay);
}
void Cleanup(unsigned int windowId = 0)
{
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
m_historyViewModel->OnClearCommand(nullptr);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_historyViewModel->OnClearCommand(nullptr);
m_standardViewModel->m_standardCalculatorManager->Reset();
}
bool IsHistoryContainerEmpty(_In_ String^ historyContainerKey)
{
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
return !(localSettings->Containers->HasKey(historyContainerKey));
}
String^ GetHistoryContainerKeyHelper(CalculationManager::CALCULATOR_MODE cMode)
{
ValueType^ modeValue = static_cast<int>(cMode);
return String::Concat(modeValue->ToString(), L"_History");
}
void MockOnHistoryItemClicked(CalculatorApp::ViewModel::HistoryItemViewModel^ e)
{
m_standardViewModel->SetHistoryExpressionDisplay(e->GetTokens(), e->GetCommands());
m_standardViewModel->SetExpressionDisplay(e->GetTokens(), e->GetCommands());
m_standardViewModel->SetPrimaryDisplay(e->Result->Data(), false/*IsError*/);
m_standardViewModel->IsFToEEnabled = false;
}
void AddSingleHistoryItem(unsigned int windowId = 0)
{
Initialize(windowId);
int initialSize = m_historyViewModel->ItemSize;
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command8);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
int sizeAfterItemAdd = m_historyViewModel->ItemSize;
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
String^ expression = UtfUtils::LRO + L"1 + 8 =" + UtfUtils::PDF;
String ^result = StringReference(L"9");
VERIFY_ARE_EQUAL(initialSize + 1, sizeAfterItemAdd);
VERIFY_ARE_EQUAL(expression, StringReference(historyItem->historyItemVector.expression.c_str()));
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
Cleanup(windowId);
}
void AddMaxHistoryItems(unsigned int windowId = 0)
{
Initialize(windowId);
int initialSize = m_historyViewModel->ItemSize;
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
for (int i = 1; i < m_standardViewModel->m_standardCalculatorManager->MaxHistorySize(); i++)
{
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
}
VERIFY_ARE_EQUAL(m_historyViewModel->ItemSize, m_standardViewModel->m_standardCalculatorManager->MaxHistorySize());
String ^expression = UtfUtils::LRO + L"1 + 1 =" + UtfUtils::PDF;
int output = 2;
String ^result = output.ToString();
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
VERIFY_ARE_EQUAL(expression, StringReference(historyItem->historyItemVector.expression.c_str()));
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command5);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
VERIFY_ARE_EQUAL(m_historyViewModel->ItemSize, m_standardViewModel->m_standardCalculatorManager->MaxHistorySize());
expression = UtfUtils::LRO + L"1 + 2 =" + UtfUtils::PDF;
output = 3;
result = output.ToString();
historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
VERIFY_ARE_EQUAL(expression, StringReference(historyItem->historyItemVector.expression.c_str()));
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
Cleanup(windowId);
}
void ReloadHistory(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->Reset();
int scientificItems = 5;
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
for (int i = 0; i < scientificItems; i++)
{
Command nextCommand = Command(130 + i);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(nextCommand);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
}
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
int standardItems = 2;
for (int i = 0; i < standardItems; i++)
{
Command nextCommand = Command(130 + i);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(nextCommand);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
}
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_historyViewModel->ReloadHistory(ViewMode::Scientific);
VERIFY_ARE_EQUAL(scientificItems, m_historyViewModel->ItemSize);
for (int i = 0; i < scientificItems; i++)
{
wstring expr = L"1 + " + wstring(i.ToString()->Data()) + L" =";
expr = UtfUtils::LRO + expr + UtfUtils::PDF;
int output = 1 + i;
String ^result = output.ToString();
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(i);
VERIFY_ARE_EQUAL(expr, historyItem->historyItemVector.expression);
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
}
m_historyViewModel->ReloadHistory(ViewMode::Standard);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
VERIFY_ARE_EQUAL(standardItems, m_historyViewModel->ItemSize);
for (int i = 0; i < standardItems; i++)
{
wstring expr = L"1 + " + wstring(i.ToString()->Data()) + L" =";
expr = UtfUtils::LRO + expr + UtfUtils::PDF;
int output = 1 + i;
String ^result = output.ToString();
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(i);
VERIFY_ARE_EQUAL(expr, historyItem->historyItemVector.expression);
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
}
Cleanup(windowId);
}
void ClearHistory(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
m_historyViewModel->OnClearCommand(nullptr);
VERIFY_ARE_EQUAL(0, m_historyViewModel->ItemSize);
VERIFY_IS_TRUE(IsHistoryContainerEmpty(GetHistoryContainerKeyHelper(CM_STD)));
VERIFY_IS_TRUE(IsHistoryContainerEmpty(GetHistoryContainerKeyHelper(CM_SCI)));
Cleanup(windowId);
}
void SerializeDeSerializeHistoryItem(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
auto itemBeforeSerializeDeserialize = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
m_historyViewModel->SaveHistory();
m_historyViewModel->ReloadHistory(ViewMode::Scientific);
auto itemAfterSerializeDeserialize = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
VERIFY_IS_TRUE((itemBeforeSerializeDeserialize->historyItemVector.expression == itemAfterSerializeDeserialize->historyItemVector.expression) && (itemBeforeSerializeDeserialize->historyItemVector.result == itemAfterSerializeDeserialize->historyItemVector.result) && (itemBeforeSerializeDeserialize->historyItemVector.spCommands == itemAfterSerializeDeserialize->historyItemVector.spCommands) && (itemBeforeSerializeDeserialize->historyItemVector.spTokens == itemAfterSerializeDeserialize->historyItemVector.spTokens));
Cleanup(windowId);
}
void SaveAndReloadHistory(unsigned int windowid = 0)
{
Initialize(windowid);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command8);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command6);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
int itemsBeforeSaveAndReload = m_historyViewModel->ItemSize;
m_historyViewModel->SaveHistory();
m_historyViewModel->ReloadHistory(ViewMode::Scientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
wstring expr = L"1 + 8 =";
// add double quotes around the expression
expr = UtfUtils::LRO + expr + UtfUtils::PDF;
String ^result = StringReference(L"9");
int itemsAfterSaveAndReload = m_historyViewModel->ItemSize;
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
VERIFY_ARE_EQUAL(expr, historyItem->historyItemVector.expression);
VERIFY_ARE_EQUAL(result, StringReference(historyItem->historyItemVector.result.c_str()));
VERIFY_ARE_NOT_EQUAL(itemsBeforeSaveAndReload, itemsAfterSaveAndReload);
VERIFY_ARE_EQUAL(itemsBeforeSaveAndReload, itemsAfterSaveAndReload + 1);
Cleanup(windowid);
}
void HistoryItemWithPrettyExpressions(unsigned int windowId = 0)
{
Initialize(windowId);
Command commands[] = { Command::CommandSIN, Command::CommandCOS, Command::CommandTAN, Command::CommandASIN, Command::CommandACOS, Command::CommandATAN };
Command mode[] = { Command::CommandDEG, Command::CommandRAD, Command::CommandGRAD };
int modes = sizeof(mode) / sizeof(Command);
int commandsSize = sizeof(commands) / sizeof(Command);
ResourceLoader^ m_uiResourceLoader = ResourceLoader::GetForViewIndependentUse(L"CEngineStrings");
int itemIndex = 0;
int commandResource = 67;
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
for (int index = 0; index < modes; index++)
{
m_standardViewModel->m_standardCalculatorManager->SendCommand(mode[index]);
for (int command = 0; command < commandsSize; command++)
{
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(commands[command]);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(itemIndex);
String^ expression = m_uiResourceLoader->GetString(commandResource.ToString());
expression += L"( 1 ) =";
wstring expr = wstring(expression->Data());
expr = UtfUtils::LRO + expr + UtfUtils::PDF;
VERIFY_ARE_EQUAL(historyItem->historyItemVector.expression, expr);
commandResource++;
itemIndex++;
}
}
Cleanup(windowId);
}
void HistoryItemWithPrettyExpressionsMixedRadix(unsigned int windowId = 0)
{
Initialize(windowId);
ResourceLoader^ m_uiResourceLoader = ResourceLoader::GetForViewIndependentUse(L"CEngineStrings");
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandDEG);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandSIN);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandRAD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandSIN);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandGRAD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandSIN);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
String^ expression = m_uiResourceLoader->GetString(L"67");
expression += L"( 1 ) + ";
expression += m_uiResourceLoader->GetString(L"73");
expression += L"( 1 ) + ";
expression += m_uiResourceLoader->GetString(L"79");
expression += L"( 1 ) =";
wstring expr = wstring(expression->Data());
expr = UtfUtils::LRO + expr + UtfUtils::PDF;
VERIFY_ARE_EQUAL(historyItem->historyItemVector.expression,expr);
Cleanup(windowId);
}
void HistoryItemClicked(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command5);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command3);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
String^ expression = StringReference(historyItem->historyItemVector.expression.c_str());
String^ result = StringReference(historyItem->historyItemVector.result.c_str());
HistoryItemViewModel ^ item = ref new HistoryItemViewModel(expression, result, historyItem->historyItemVector.spTokens, historyItem->historyItemVector.spCommands);
MockOnHistoryItemClicked(item);
VERIFY_ARE_EQUAL(StringReference(L"9"), m_standardViewModel->DisplayValue);
VERIFY_ARE_EQUAL(StringReference(L"1"), m_standardViewModel->ExpressionTokens->GetAt(0)->Token);
VERIFY_ARE_EQUAL(StringReference(L" "), m_standardViewModel->ExpressionTokens->GetAt(1)->Token);
VERIFY_ARE_EQUAL(StringReference(L"+"), m_standardViewModel->ExpressionTokens->GetAt(2)->Token);
VERIFY_ARE_EQUAL(StringReference(L" "), m_standardViewModel->ExpressionTokens->GetAt(3)->Token);
VERIFY_ARE_EQUAL(StringReference(L"5"), m_standardViewModel->ExpressionTokens->GetAt(4)->Token);
VERIFY_ARE_EQUAL(StringReference(L" "), m_standardViewModel->ExpressionTokens->GetAt(5)->Token);
VERIFY_ARE_EQUAL(StringReference(L"+"), m_standardViewModel->ExpressionTokens->GetAt(6)->Token);
VERIFY_ARE_EQUAL(StringReference(L" "), m_standardViewModel->ExpressionTokens->GetAt(7)->Token);
Cleanup(windowId);
}
void HistoryItemLoadAndContinueCalculation(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeBasic);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command5);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command3);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
auto historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
String^ expression = StringReference(historyItem->historyItemVector.expression.c_str());
String^ result = StringReference(historyItem->historyItemVector.result.c_str());
HistoryItemViewModel ^ item = ref new HistoryItemViewModel(expression, result, historyItem->historyItemVector.spTokens, historyItem->historyItemVector.spCommands);
MockOnHistoryItemClicked(item);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command5);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
VERIFY_ARE_EQUAL(StringReference(L"14"), m_standardViewModel->DisplayValue);
historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(0);
expression = StringReference(historyItem->historyItemVector.expression.c_str());
result = StringReference(historyItem->historyItemVector.result.c_str());
item = ref new HistoryItemViewModel(expression, result, historyItem->historyItemVector.spTokens, historyItem->historyItemVector.spCommands);
MockOnHistoryItemClicked(item);
VERIFY_ARE_EQUAL(StringReference(L"9"), m_standardViewModel->DisplayValue);
historyItem = m_standardViewModel->m_standardCalculatorManager->GetHistoryItem(1);
expression = StringReference(historyItem->historyItemVector.expression.c_str());
result = StringReference(historyItem->historyItemVector.result.c_str());
item = ref new HistoryItemViewModel(expression, result, historyItem->historyItemVector.spTokens, historyItem->historyItemVector.spCommands);
MockOnHistoryItemClicked(item);
VERIFY_ARE_EQUAL(StringReference(L"14"), m_standardViewModel->DisplayValue);
Cleanup(windowId);
}
void DisplayValueAutomationNames(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command8);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
String ^expression = StringReference(L"Display is 9");
VERIFY_ARE_EQUAL(expression, m_standardViewModel->CalculationResultAutomationName);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command5);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
expression = StringReference(L"Display is 6");
VERIFY_ARE_EQUAL(expression, m_standardViewModel->CalculationResultAutomationName);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeProgrammer);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command2);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
expression = StringReference(L"Display is 3");
VERIFY_ARE_EQUAL(expression, m_standardViewModel->CalculationResultAutomationName);
Cleanup(windowId);
}
void RadixAutomationName(unsigned int windowId = 0)
{
Initialize(windowId);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeProgrammer);
m_standardViewModel->IsProgrammer = true;
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command1);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandADD);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::Command7);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::CommandEQU);
String ^expression = L"HexaDecimal" + L" 8";
String ^result = L"HexaDecimal " + Utils::GetStringValue(m_standardViewModel->HexDisplayValue);
VERIFY_ARE_EQUAL(expression, result);
expression = StringReference(L"Octal 10");
result = L"Octal " + Utils::GetStringValue(m_standardViewModel->OctalDisplayValue);
VERIFY_ARE_EQUAL(expression, result);
expression = StringReference(L"Binary 1000");
result = L"Binary " + Utils::GetStringValue(m_standardViewModel->BinaryDisplayValue);
VERIFY_ARE_EQUAL(expression, result);
Cleanup(windowId);
}
void HistoryEmpty(unsigned int windowId = 0)
{
Initialize(windowId);
VERIFY_ARE_EQUAL(0, m_historyViewModel->ItemSize);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
VERIFY_ARE_EQUAL(0, m_historyViewModel->ItemSize);
Cleanup(windowId);
}
void HistoryClearCommandWithEmptyHistory(unsigned int windowId = 0)
{
Initialize(windowId);
VERIFY_ARE_EQUAL(0, m_historyViewModel->ItemSize);
m_standardViewModel->m_standardCalculatorManager->SendCommand(Command::ModeScientific);
m_historyViewModel->OnClearCommand(nullptr);
VERIFY_ARE_EQUAL(0, m_historyViewModel->ItemSize);
Cleanup(windowId);
}
};
void HistoryTests::TestHistoryItemAddSingleItem()
{
AddSingleHistoryItem();
}
void HistoryTests::TestHistoryItemAddMaxItems()
{
AddMaxHistoryItems();
}
void HistoryTests::TestReLoadHistory()
{
ReloadHistory();
}
void HistoryTests::TestHistoryClearCommand()
{
ClearHistory();
}
void HistoryTests::TestSerializeDeSerializeHistoryItem()
{
SerializeDeSerializeHistoryItem();
}
void HistoryTests::TestSaveAndReloadHistory()
{
SaveAndReloadHistory();
}
void HistoryTests::TestHistoryItemWithPrettyExpressions()
{
HistoryItemWithPrettyExpressions();
}
void HistoryTests::TestHistoryItemWithPrettyExpressionsMixedRadix()
{
HistoryItemWithPrettyExpressionsMixedRadix();
}
void HistoryTests::TestHistoryItemClicked()
{
HistoryItemClicked();
}
void HistoryTests::TestHistoryItemLoadAndContinueCalculation()
{
HistoryItemLoadAndContinueCalculation();
}
void HistoryTests::TestDisplayValueAutomationNames()
{
DisplayValueAutomationNames();
}
void HistoryTests::TestRadixAutomationName()
{
RadixAutomationName();
}
void HistoryTests::TestHistoryEmpty()
{
HistoryEmpty();
}
void HistoryTests::TestHistoryClearCommandWithEmptyHistory()
{
HistoryClearCommandWithEmptyHistory();
}
}

View File

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "pch.h"
#include "CurrencyHttpClient.h"
#include "CalcViewModel\Common\NetworkManager.h"
using namespace CalculatorApp::DataLoaders;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::System::UserProfile;
using namespace Windows::Web::Http;
// Generic responses so unit tests will pass.
static constexpr auto STATIC_DATA_RESPONSE = LR"([{"CountryCode":"USA","CountryName":"United States","CurrencyCode":"USD","CurrencyName":"Dollar","CurrencySymbol":"$"},{"CountryCode":"EUR","CountryName":"Europe","CurrencyCode":"EUR","CurrencyName":"Euro","CurrencySymbol":""}])";
static constexpr auto ALL_RATIOS_RESPONSE = LR"([{"An":"USD","Ch":0,"Pc":0,"Rt":1},{"An":"EUR","Ch":0.003803,"Pc":0.4149,"Rt":0.920503,"Yh":0.9667,"Yl":0.86701}])";
CurrencyHttpClient::CurrencyHttpClient()
{
}
String^ CurrencyHttpClient::GetRawStaticDataResponse()
{
return StringReference(STATIC_DATA_RESPONSE);
}
String^ CurrencyHttpClient::GetRawAllRatiosDataResponse()
{
return StringReference(ALL_RATIOS_RESPONSE);
}
IAsyncOperationWithProgress<String^, HttpProgress>^ CurrencyHttpClient::GetCurrencyMetadata()
{
return ref new MockAsyncOperationWithProgress(StringReference(STATIC_DATA_RESPONSE));
}
IAsyncOperationWithProgress<String^, HttpProgress>^ CurrencyHttpClient::GetCurrencyRatios()
{
return ref new MockAsyncOperationWithProgress(StringReference(ALL_RATIOS_RESPONSE));
}
MockAsyncOperationWithProgress::MockAsyncOperationWithProgress(String^ result) :
m_result(result)
{
}
HResult MockAsyncOperationWithProgress::ErrorCode::get()
{
HResult okayResult;
okayResult.Value = S_OK;
return okayResult;
}

View File

@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
namespace CalculatorUnitTests
{
BEGIN_MODULE()
MODULE_PROPERTY(L"APPX:CertificateFileName", L"CalculatorUnitTests.cer:TrustedPeople")
END_MODULE()
MODULE_SETUP(ModuleSetup)
{
return true;
}
MODULE_CLEANUP(ModuleCleanup)
{
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,410 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
using namespace CalculatorApp::Common;
using namespace CalculatorUnitTests;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation::Collections;
namespace CalculatorUnitTests
{
class NavCategoryUnitTests
{
public:
TEST_CLASS(NavCategoryUnitTests);
TEST_METHOD(Serialize);
TEST_METHOD(Deserialize_AllValid);
TEST_METHOD(Deserialize_AllInvalid);
TEST_METHOD(IsValidViewMode_AllValid);
TEST_METHOD(IsValidViewMode_AllInvalid);
TEST_METHOD(IsCalculatorViewMode);
TEST_METHOD(IsDateCalculatorViewMode);
TEST_METHOD(IsConverterViewMode);
TEST_METHOD(GetFriendlyName);
TEST_METHOD(GetGroupType);
TEST_METHOD(GetIndex);
TEST_METHOD(GetPosition);
TEST_METHOD(GetIndex_GetPosition_Relationship);
TEST_METHOD(GetIndexInGroup);
TEST_METHOD(GetViewModeForVirtualKey);
};
void NavCategoryUnitTests::Serialize()
{
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(0, NavCategory::Serialize(ViewMode::Standard));
VERIFY_ARE_EQUAL(1, NavCategory::Serialize(ViewMode::Scientific));
VERIFY_ARE_EQUAL(2, NavCategory::Serialize(ViewMode::Programmer));
VERIFY_ARE_EQUAL(3, NavCategory::Serialize(ViewMode::Date));
VERIFY_ARE_EQUAL(16, NavCategory::Serialize(ViewMode::Currency));
VERIFY_ARE_EQUAL(4, NavCategory::Serialize(ViewMode::Volume));
VERIFY_ARE_EQUAL(5, NavCategory::Serialize(ViewMode::Length));
VERIFY_ARE_EQUAL(6, NavCategory::Serialize(ViewMode::Weight));
VERIFY_ARE_EQUAL(7, NavCategory::Serialize(ViewMode::Temperature));
VERIFY_ARE_EQUAL(8, NavCategory::Serialize(ViewMode::Energy));
VERIFY_ARE_EQUAL(9, NavCategory::Serialize(ViewMode::Area));
VERIFY_ARE_EQUAL(10, NavCategory::Serialize(ViewMode::Speed));
VERIFY_ARE_EQUAL(11, NavCategory::Serialize(ViewMode::Time));
VERIFY_ARE_EQUAL(12, NavCategory::Serialize(ViewMode::Power));
VERIFY_ARE_EQUAL(13, NavCategory::Serialize(ViewMode::Data));
VERIFY_ARE_EQUAL(14, NavCategory::Serialize(ViewMode::Pressure));
VERIFY_ARE_EQUAL(15, NavCategory::Serialize(ViewMode::Angle));
VERIFY_ARE_EQUAL(-1, NavCategory::Serialize(ViewMode::None));
}
void NavCategoryUnitTests::Deserialize_AllValid()
{
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategory::Deserialize(ref new Box<int>(0)));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategory::Deserialize(ref new Box<int>(1)));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategory::Deserialize(ref new Box<int>(2)));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategory::Deserialize(ref new Box<int>(3)));
VERIFY_ARE_EQUAL(ViewMode::Currency, NavCategory::Deserialize(ref new Box<int>(16)));
VERIFY_ARE_EQUAL(ViewMode::Volume, NavCategory::Deserialize(ref new Box<int>(4)));
VERIFY_ARE_EQUAL(ViewMode::Length, NavCategory::Deserialize(ref new Box<int>(5)));
VERIFY_ARE_EQUAL(ViewMode::Weight, NavCategory::Deserialize(ref new Box<int>(6)));
VERIFY_ARE_EQUAL(ViewMode::Temperature, NavCategory::Deserialize(ref new Box<int>(7)));
VERIFY_ARE_EQUAL(ViewMode::Energy, NavCategory::Deserialize(ref new Box<int>(8)));
VERIFY_ARE_EQUAL(ViewMode::Area, NavCategory::Deserialize(ref new Box<int>(9)));
VERIFY_ARE_EQUAL(ViewMode::Speed, NavCategory::Deserialize(ref new Box<int>(10)));
VERIFY_ARE_EQUAL(ViewMode::Time, NavCategory::Deserialize(ref new Box<int>(11)));
VERIFY_ARE_EQUAL(ViewMode::Power, NavCategory::Deserialize(ref new Box<int>(12)));
VERIFY_ARE_EQUAL(ViewMode::Data, NavCategory::Deserialize(ref new Box<int>(13)));
VERIFY_ARE_EQUAL(ViewMode::Pressure, NavCategory::Deserialize(ref new Box<int>(14)));
VERIFY_ARE_EQUAL(ViewMode::Angle, NavCategory::Deserialize(ref new Box<int>(15)));
}
void NavCategoryUnitTests::Deserialize_AllInvalid()
{
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(nullptr));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new String(L"fail")));
// Boundary testing
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new Box<int>(-1)));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new Box<int>(17)));
}
void NavCategoryUnitTests::IsValidViewMode_AllValid()
{
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Standard));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Scientific));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Programmer));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Date));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Currency));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Volume));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Length));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Weight));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Temperature));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Energy));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Area));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Speed));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Time));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Power));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Data));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Pressure));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::IsValidViewMode_AllInvalid()
{
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(ViewMode::None));
// There are 17 total options so int 17 should be the first invalid
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(static_cast<ViewMode>(16)));
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(static_cast<ViewMode>(17)));
// Also verify the lower bound
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(static_cast<ViewMode>(0)));
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(static_cast<ViewMode>(-1)));
}
void NavCategoryUnitTests::IsCalculatorViewMode()
{
VERIFY_IS_TRUE(NavCategory::IsCalculatorViewMode(ViewMode::Standard));
VERIFY_IS_TRUE(NavCategory::IsCalculatorViewMode(ViewMode::Scientific));
VERIFY_IS_TRUE(NavCategory::IsCalculatorViewMode(ViewMode::Programmer));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Date));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Currency));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Volume));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Length));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Weight));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Temperature));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Energy));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Area));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Speed));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Time));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Power));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Data));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Pressure));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::IsDateCalculatorViewMode()
{
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Standard));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Scientific));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Programmer));
VERIFY_IS_TRUE(NavCategory::IsDateCalculatorViewMode(ViewMode::Date));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Currency));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Volume));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Length));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Weight));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Temperature));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Energy));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Area));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Speed));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Time));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Power));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Data));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Pressure));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::IsConverterViewMode()
{
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Standard));
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Scientific));
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Programmer));
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Date));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Currency));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Volume));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Length));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Weight));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Temperature));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Energy));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Area));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Speed));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Time));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Power));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Data));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Pressure));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::GetFriendlyName()
{
VERIFY_ARE_EQUAL(StringReference(L"Standard"), NavCategory::GetFriendlyName(ViewMode::Standard));
VERIFY_ARE_EQUAL(StringReference(L"Scientific"), NavCategory::GetFriendlyName(ViewMode::Scientific));
VERIFY_ARE_EQUAL(StringReference(L"Programmer"), NavCategory::GetFriendlyName(ViewMode::Programmer));
VERIFY_ARE_EQUAL(StringReference(L"Date"), NavCategory::GetFriendlyName(ViewMode::Date));
VERIFY_ARE_EQUAL(StringReference(L"Currency"), NavCategory::GetFriendlyName(ViewMode::Currency));
VERIFY_ARE_EQUAL(StringReference(L"Volume"), NavCategory::GetFriendlyName(ViewMode::Volume));
VERIFY_ARE_EQUAL(StringReference(L"Length"), NavCategory::GetFriendlyName(ViewMode::Length));
VERIFY_ARE_EQUAL(StringReference(L"Weight and Mass"), NavCategory::GetFriendlyName(ViewMode::Weight));
VERIFY_ARE_EQUAL(StringReference(L"Temperature"), NavCategory::GetFriendlyName(ViewMode::Temperature));
VERIFY_ARE_EQUAL(StringReference(L"Energy"), NavCategory::GetFriendlyName(ViewMode::Energy));
VERIFY_ARE_EQUAL(StringReference(L"Area"), NavCategory::GetFriendlyName(ViewMode::Area));
VERIFY_ARE_EQUAL(StringReference(L"Speed"), NavCategory::GetFriendlyName(ViewMode::Speed));
VERIFY_ARE_EQUAL(StringReference(L"Time"), NavCategory::GetFriendlyName(ViewMode::Time));
VERIFY_ARE_EQUAL(StringReference(L"Power"), NavCategory::GetFriendlyName(ViewMode::Power));
VERIFY_ARE_EQUAL(StringReference(L"Data"), NavCategory::GetFriendlyName(ViewMode::Data));
VERIFY_ARE_EQUAL(StringReference(L"Pressure"), NavCategory::GetFriendlyName(ViewMode::Pressure));
VERIFY_ARE_EQUAL(StringReference(L"Angle"), NavCategory::GetFriendlyName(ViewMode::Angle));
VERIFY_ARE_EQUAL(StringReference(L"None"), NavCategory::GetFriendlyName(ViewMode::None));
}
void NavCategoryUnitTests::GetGroupType()
{
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Standard));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Scientific));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Programmer));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Date));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Currency));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Volume));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Length));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Weight));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Temperature));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Energy));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Area));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Speed));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Time));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Power));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Data));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Pressure));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Angle));
}
void NavCategoryUnitTests::GetIndex()
{
// Index is the 0-based ordering of modes
vector<ViewMode> orderedModes = {
ViewMode::Standard,
ViewMode::Scientific,
ViewMode::Programmer,
ViewMode::Date,
ViewMode::Currency,
ViewMode::Volume,
ViewMode::Length,
ViewMode::Weight,
ViewMode::Temperature,
ViewMode::Energy,
ViewMode::Area,
ViewMode::Speed,
ViewMode::Time,
ViewMode::Power,
ViewMode::Data,
ViewMode::Pressure,
ViewMode::Angle
};
for (size_t index = 0; index < orderedModes.size(); index++)
{
ViewMode mode = orderedModes[index];
VERIFY_ARE_EQUAL(index, NavCategory::GetIndex(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndex(ViewMode::None));
}
void NavCategoryUnitTests::GetPosition()
{
// Position is the 1-based ordering of modes
vector<ViewMode> orderedModes = {
ViewMode::Standard,
ViewMode::Scientific,
ViewMode::Programmer,
ViewMode::Date,
ViewMode::Currency,
ViewMode::Volume,
ViewMode::Length,
ViewMode::Weight,
ViewMode::Temperature,
ViewMode::Energy,
ViewMode::Area,
ViewMode::Speed,
ViewMode::Time,
ViewMode::Power,
ViewMode::Data,
ViewMode::Pressure,
ViewMode::Angle
};
for (size_t pos = 1; pos <= orderedModes.size(); pos++)
{
ViewMode mode = orderedModes[pos - 1];
VERIFY_ARE_EQUAL(pos, NavCategory::GetPosition(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategory::GetPosition(ViewMode::None));
}
void NavCategoryUnitTests::GetIndex_GetPosition_Relationship()
{
// Index should be 1 less than Position.
// The other checks verify the order of Index and Position.
// Just verify the relationship here.
VERIFY_ARE_EQUAL(NavCategory::GetIndex(ViewMode::Standard) + 1, NavCategory::GetPosition(ViewMode::Standard));
VERIFY_ARE_EQUAL(NavCategory::GetPosition(ViewMode::Volume) - 1, NavCategory::GetIndex(ViewMode::Volume));
}
void NavCategoryUnitTests::GetIndexInGroup()
{
VERIFY_ARE_EQUAL(0, NavCategory::GetIndexInGroup(ViewMode::Standard, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(1, NavCategory::GetIndexInGroup(ViewMode::Scientific, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(2, NavCategory::GetIndexInGroup(ViewMode::Programmer, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(3, NavCategory::GetIndexInGroup(ViewMode::Date, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(0, NavCategory::GetIndexInGroup(ViewMode::Currency, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(1, NavCategory::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(2, NavCategory::GetIndexInGroup(ViewMode::Length, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(3, NavCategory::GetIndexInGroup(ViewMode::Weight, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(4, NavCategory::GetIndexInGroup(ViewMode::Temperature, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(5, NavCategory::GetIndexInGroup(ViewMode::Energy, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(6, NavCategory::GetIndexInGroup(ViewMode::Area, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(7, NavCategory::GetIndexInGroup(ViewMode::Speed, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(8, NavCategory::GetIndexInGroup(ViewMode::Time, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(9, NavCategory::GetIndexInGroup(ViewMode::Power, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(10, NavCategory::GetIndexInGroup(ViewMode::Data, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(11, NavCategory::GetIndexInGroup(ViewMode::Pressure, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(12, NavCategory::GetIndexInGroup(ViewMode::Angle, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndexInGroup(ViewMode::None, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndexInGroup(ViewMode::None, CategoryGroupType::Converter));
}
void NavCategoryUnitTests::GetViewModeForVirtualKey()
{
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number1));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number2));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number3));
}
class NavCategoryGroupUnitTests
{
public:
TEST_CLASS(NavCategoryGroupUnitTests);
TEST_METHOD(CreateNavCategoryGroup);
private:
void ValidateNavCategory(IObservableVector<NavCategory^>^ categories, unsigned int index, ViewMode expectedMode, int expectedPosition)
{
VERIFY_IS_LESS_THAN(0u, categories->Size);
VERIFY_IS_GREATER_THAN(categories->Size, index);
NavCategory^ category = categories->GetAt(index);
VERIFY_ARE_EQUAL(expectedMode, category->Mode);
VERIFY_ARE_EQUAL(expectedPosition, category->Position);
}
};
void NavCategoryGroupUnitTests::CreateNavCategoryGroup()
{
IObservableVector<NavCategoryGroup^>^ menuOptions = NavCategoryGroup::CreateMenuOptions();
VERIFY_ARE_EQUAL(2, menuOptions->Size);
NavCategoryGroup^ calculatorGroup = menuOptions->GetAt(0);
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, calculatorGroup->GroupType);
IObservableVector<NavCategory^>^ calculatorCategories = calculatorGroup->Categories;
VERIFY_ARE_EQUAL(4, calculatorCategories->Size);
ValidateNavCategory(calculatorCategories, 0u, ViewMode::Standard, 1);
ValidateNavCategory(calculatorCategories, 1u, ViewMode::Scientific, 2);
ValidateNavCategory(calculatorCategories, 2u, ViewMode::Programmer, 3);
ValidateNavCategory(calculatorCategories, 3u, ViewMode::Date, 4);
NavCategoryGroup^ converterGroup = menuOptions->GetAt(1);
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, converterGroup->GroupType);
IObservableVector<NavCategory^>^ converterCategories = converterGroup->Categories;
VERIFY_ARE_EQUAL(13, converterCategories->Size);
ValidateNavCategory(converterCategories, 0u, ViewMode::Currency, 5);
ValidateNavCategory(converterCategories, 1u, ViewMode::Volume, 6);
ValidateNavCategory(converterCategories, 2u, ViewMode::Length, 7);
ValidateNavCategory(converterCategories, 3u, ViewMode::Weight, 8);
ValidateNavCategory(converterCategories, 4u, ViewMode::Temperature, 9);
ValidateNavCategory(converterCategories, 5u, ViewMode::Energy, 10);
ValidateNavCategory(converterCategories, 6u, ViewMode::Area, 11);
ValidateNavCategory(converterCategories, 7u, ViewMode::Speed, 12);
ValidateNavCategory(converterCategories, 8u, ViewMode::Time, 13);
ValidateNavCategory(converterCategories, 9u, ViewMode::Power, 14);
ValidateNavCategory(converterCategories, 10u, ViewMode::Data, 15);
ValidateNavCategory(converterCategories, 11u, ViewMode::Pressure, 16);
ValidateNavCategory(converterCategories, 12u, ViewMode::Angle, 17);
}
}

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="bb12762c-62f1-4063-95c9-170805a2cb5b" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="bb12762c-62f1-4063-95c9-170805a2cb5b" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>CalculatorUnitTests</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="taef.executionengine.universal.App" Executable="$targetnametoken$.exe" EntryPoint="CalculatorUnitTests.App">
<uap:VisualElements DisplayName="CalculatorUnitTests" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="CalculatorUnitTests" BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="internetClientServer" />
</Capabilities>
</Package>

File diff suppressed because it is too large Load Diff

View File

@ -1,440 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Square meters-Acres">
<value>4046.8564224</value></data>
<data name="Square meters-Square meters">
<value>1</value></data>
<data name="Square meters-Square feet">
<value>0.09290304</value></data>
<data name="Square meters-Square yards">
<value>0.83612736</value></data>
<data name="Square meters-Square millimeters">
<value>0.000001</value></data>
<data name="Square meters-Square centimeters">
<value>0.0001</value></data>
<data name="Square meters-Square inches">
<value>0.00064516</value></data>
<data name="Square meters-Square miles">
<value>2589988.110336</value></data>
<data name="Square meters-Square kilometers">
<value>1000000</value></data>
<data name="Square meters-Hectares">
<value>10000</value></data>
<data name="Square meters-hands">
<value>0.012516104</value></data>
<data name="Square meters-sheets of paper">
<value>0.06032246</value></data>
<data name="Square meters-soccer fields">
<value>10869.66</value></data>
<data name="Square meters-castles">
<value>100000</value></data>
<data name="Megabytes-Bits">
<value>0.000000125</value></data>
<data name="Megabytes-Bytes">
<value>0.000001</value></data>
<data name="Megabytes-Kilobytes">
<value>0.001</value></data>
<data name="Megabytes-Megabytes">
<value>1</value></data>
<data name="Megabytes-Gigabytes">
<value>1000</value></data>
<data name="Megabytes-Terabytes">
<value>1000000</value></data>
<data name="Megabytes-Petabytes">
<value>1000000000</value></data>
<data name="Megabytes-Exabytes">
<value>1000000000000</value></data>
<data name="Megabytes-Zetabytes">
<value>1000000000000000</value></data>
<data name="Megabytes-Yottabyte">
<value>1000000000000000000</value></data>
<data name="Megabytes-Kilobits">
<value>0.000125</value></data>
<data name="Megabytes-Megabits">
<value>0.125</value></data>
<data name="Megabytes-Gigabits">
<value>125</value></data>
<data name="Megabytes-Terabits">
<value>125000</value></data>
<data name="Megabytes-Petabits">
<value>125000000</value></data>
<data name="Megabytes-Exabits">
<value>125000000000</value></data>
<data name="Megabytes-Zetabits">
<value>125000000000000</value></data>
<data name="Megabytes-Yottabit">
<value>125000000000000000</value></data>
<data name="Megabytes-Gibibits">
<value>134.217728</value></data>
<data name="Megabytes-Gibibytes">
<value>1073.741824</value></data>
<data name="Megabytes-Kibibits">
<value>0.000128</value></data>
<data name="Megabytes-Kibibytes">
<value>0.001024</value></data>
<data name="Megabytes-Mebibits">
<value>0.131072</value></data>
<data name="Megabytes-Mebibytes">
<value>1.048576</value></data>
<data name="Megabytes-Pebibits">
<value>140737488.355328</value></data>
<data name="Megabytes-Pebibytes">
<value>1125899906.842624</value></data>
<data name="Megabytes-Tebibits">
<value>137438.953472</value></data>
<data name="Megabytes-Tebibytes">
<value>1099511.627776</value></data>
<data name="Megabytes-Exbibits">
<value>144115188075.855872</value></data>
<data name="Megabytes-Exbibytes">
<value>1152921504606.846976</value></data>
<data name="Megabytes-Zebibits">
<value>147573952589676.412928</value></data>
<data name="Megabytes-Zebibytes">
<value>1180591620717411.303424</value></data>
<data name="Megabytes-Yobibits">
<value>151115727451828646.838272</value></data>
<data name="Megabytes-Yobibytes">
<value>1208925819614629174.706176</value></data>
<data name="Megabytes-floppy disks">
<value>1.509949</value></data>
<data name="Megabytes-CDs">
<value>734.003200</value></data>
<data name="Megabytes-DVDs">
<value>5046.586573</value></data>
<data name="Joules-Thermal calories">
<value>4.184</value></data>
<data name="Joules-Food calories">
<value>4184</value></data>
<data name="Joules-British thermal units">
<value>1055.056</value></data>
<data name="Joules-Kilojoules">
<value>1000</value></data>
<data name="Joules-FahrenheitVolt">
<value>0.0000000000000000001602176565</value></data>
<data name="Joules-Joules">
<value>1</value></data>
<data name="Joules-Foot-pounds">
<value>1.3558179483314</value></data>
<data name="Joules-batteries">
<value>9000</value></data>
<data name="Joules-bananas">
<value>439614</value></data>
<data name="Joules-slices of cake">
<value>1046700</value></data>
<data name="Meters-Inches">
<value>0.0254</value></data>
<data name="Meters-Feet">
<value>0.3048</value></data>
<data name="Meters-Yards">
<value>0.9144</value></data>
<data name="Meters-Miles">
<value>1609.344</value></data>
<data name="Meters-Microns">
<value>0.000001</value></data>
<data name="Meters-Millimeters">
<value>0.001</value></data>
<data name="Meters-Nanometers">
<value>0.000000001</value></data>
<data name="Meters-Centimeters">
<value>0.01</value></data>
<data name="Meters-Meters">
<value>1</value></data>
<data name="Meters-Kilometers">
<value>1000</value></data>
<data name="Meters-Nautical Miles">
<value>1852</value></data>
<data name="Meters-paperclips">
<value>0.035052</value></data>
<data name="Meters-hands">
<value>0.18669</value></data>
<data name="Meters-jumbo jets">
<value>76</value></data>
<data name="Watts-British thermal unitsPerMinute">
<value>17.58426666666667</value></data>
<data name="Watts-Foot-pounds/minute">
<value>0.0225969658055233</value></data>
<data name="Watts-Watts">
<value>1</value></data>
<data name="Watts-Kilowatts">
<value>1000</value></data>
<data name="Watts-Horsepower (US)">
<value>745.69987158227022</value></data>
<data name="Watts-light bulbs">
<value>60</value></data>
<data name="Watts-horses">
<value>745.7</value></data>
<data name="Watts-train engines">
<value>2982799.486329081</value></data>
<data name="Seconds-Days">
<value>86400</value></data>
<data name="Seconds-Seconds">
<value>1</value></data>
<data name="Seconds-Weeks">
<value>604800</value></data>
<data name="Seconds-Years">
<value>31557600</value></data>
<data name="Seconds-Milliseconds">
<value>0.001</value></data>
<data name="Seconds-Microseconds">
<value>0.000001</value></data>
<data name="Seconds-Minutes">
<value>60</value></data>
<data name="Seconds-Hours">
<value>3600</value></data>
<data name="Cubic centimeters-Cups (US)">
<value>236.588237</value></data>
<data name="Cubic centimeters-Pints (US)">
<value>473.176473</value></data>
<data name="Cubic centimeters-Pints (UK)">
<value>568.26125</value></data>
<data name="Cubic centimeters-Quarts (US)">
<value>946.352946</value></data>
<data name="Cubic centimeters-Quarts (UK)">
<value>1136.5225</value></data>
<data name="Cubic centimeters-Gallons (US)">
<value>3785.411784</value></data>
<data name="Cubic centimeters-Gallons (UK)">
<value>4546.09</value></data>
<data name="Cubic centimeters-Liters">
<value>1000</value></data>
<data name="Cubic centimeters-Teaspoons (US)">
<value>4.928922</value></data>
<data name="Cubic centimeters-Tablespoons (US)">
<value>14.786765</value></data>
<data name="Cubic centimeters-Cubic centimeters">
<value>1</value></data>
<data name="Cubic centimeters-Cubic yards">
<value>764554.857984</value></data>
<data name="Cubic centimeters-Cubic meters">
<value>1000000</value></data>
<data name="Cubic centimeters-Milliliters">
<value>1</value></data>
<data name="Cubic centimeters-Cubic inches">
<value>16.387064</value></data>
<data name="Cubic centimeters-Cubic feet">
<value>28316.846592</value></data>
<data name="Cubic centimeters-Fluid ounces (US)">
<value>29.5735295625</value></data>
<data name="Cubic centimeters-Fluid ounces (UK)">
<value>28.4130625</value></data>
<data name="Cubic centimeters-Teaspoons (UK)">
<value>5.91938802083333333333</value></data>
<data name="Cubic centimeters-Tablespoons (UK)">
<value>17.7581640625</value></data>
<data name="Cubic centimeters-coffee cups">
<value>236.5882</value></data>
<data name="Cubic centimeters-bathtubs">
<value>378541.2</value></data>
<data name="Cubic centimeters-swimming pools">
<value>3750000000</value></data>
<data name="Kilograms-Kilograms">
<value>1</value></data>
<data name="Kilograms-Hectograms">
<value>0.1</value></data>
<data name="Kilograms-Dekagrams">
<value>0.01</value></data>
<data name="Kilograms-Grams">
<value>0.001</value></data>
<data name="Kilograms-Pounds">
<value>0.45359237</value></data>
<data name="Kilograms-Ounces">
<value>0.028349523125</value></data>
<data name="Kilograms-Milligrams">
<value>0.000001</value></data>
<data name="Kilograms-Centigrams">
<value>0.00001</value></data>
<data name="Kilograms-Decigrams">
<value>0.0001</value></data>
<data name="Kilograms-Long tons (UK)">
<value>1016.0469088</value></data>
<data name="Kilograms-Metric tonnes">
<value>1000</value></data>
<data name="Kilograms-Stone">
<value>6.35029318</value></data>
<data name="Kilograms-Carats">
<value>0.0002</value></data>
<data name="Kilograms-Short tons (US)">
<value>907.18474</value></data>
<data name="Kilograms-snowflakes">
<value>0.000002</value></data>
<data name="Kilograms-soccer balls">
<value>0.4325</value></data>
<data name="Kilograms-elephants">
<value>4000</value></data>
<data name="Kilograms-whales">
<value>90000</value></data>
<data name="CentimetersPerSecond-CentimetersPerSecond">
<value>1</value></data>
<data name="CentimetersPerSecond-Feet per second">
<value>30.48</value></data>
<data name="CentimetersPerSecond-Kilometers per hour">
<value>27.777777777777777777778</value></data>
<data name="CentimetersPerSecond-Knots">
<value>51.44</value></data>
<data name="CentimetersPerSecond-Mach">
<value>34030</value></data>
<data name="CentimetersPerSecond-Meters per second">
<value>100</value></data>
<data name="CentimetersPerSecond-Miles per hour">
<value>44.7</value></data>
<data name="CentimetersPerSecond-turtles">
<value>8.94</value></data>
<data name="CentimetersPerSecond-horses">
<value>2011.5</value></data>
<data name="CentimetersPerSecond-jets">
<value>24585</value></data>
<data name="Degrees-Degrees">
<value>1</value></data>
<data name="Degrees-Radians">
<value>57.29577951308233</value></data>
<data name="Degrees-Gradians">
<value>0.9</value></data>
<data name="Atmospheres-Atmospheres">
<value>1</value></data>
<data name="Atmospheres-Bars">
<value>0.9869232667160128</value></data>
<data name="Atmospheres-Kilopascals">
<value>0.0098692326671601</value></data>
<data name="Atmospheres-Millimeters of mercury ">
<value>0.0013155687145324</value></data>
<data name="Atmospheres-Pascals">
<value>9.869232667160128e-6</value></data>
<data name="Atmospheres-Pounds per square inch">
<value>0.068045961016531</value></data>
<data name="Liters-Cubic meters-2" xml:space="preserve">
<value>0.002</value>
</data>
<data name="Milliliters-Cubic centimeters" xml:space="preserve">
<value>1</value>
</data>
<data name="Milliliters-Cubic centimeters-1" xml:space="preserve">
<value>1</value>
</data>
<data name="Milliliters-Liters" xml:space="preserve">
<value>1000</value>
</data>
<data name="Milliliters-Milliliters" xml:space="preserve">
<value>1</value>
</data>
<data name="Nanometers-Microns-3" xml:space="preserve">
<value>0.003</value>
</data>
</root>

View File

@ -1,600 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
using namespace UnitConversionManager;
using namespace std;
namespace UnitConverterUnitTests
{
void SetUnitParams(Unit* type, int id, wstring name, wstring abbreviation, bool conversionSource, bool conversionTarget, bool isWhimsical)
{
type->id = id;
type->name = name;
type->abbreviation = abbreviation;
type->isConversionSource = conversionSource;
type->isConversionTarget = conversionTarget;
type->isWhimsical = isWhimsical;
}
void SetCategoryParams(Category* type, int id, wstring name, bool supportsNegative)
{
type->id = id;
type->name = name;
type->supportsNegative = supportsNegative;
}
void SetConversionDataParams(ConversionData* type, double ratio, double offset, bool offsetFirst)
{
type->ratio = ratio;
type->offset = offset;
type->offsetFirst = offsetFirst;
}
class TestUnitConverterConfigLoader : public IConverterDataLoader
{
public:
TestUnitConverterConfigLoader() :
m_loadDataCallCount(0)
{
Category c1, c2;
SetCategoryParams(&c1, 1, L"Length", true);
SetCategoryParams(&c2, 2, L"Weight", false);
m_categories.push_back(c1);
m_categories.push_back(c2);
Unit u1, u2, u3, u4;
SetUnitParams(&u1, 1, L"Inches", L"In", true, true, false);
SetUnitParams(&u2, 2, L"Feet", L"Ft", false, false, false);
SetUnitParams(&u3, 3, L"Pounds", L"Lb", true, true, false);
SetUnitParams(&u4, 4, L"Kilograms", L"Kg", false, false, false);
vector<Unit> c1units = vector<Unit>();
vector<Unit> c2units = vector<Unit>();
c1units.push_back(u1);
c1units.push_back(u2);
c2units.push_back(u3);
c2units.push_back(u4);
m_units[c1] = c1units;
m_units[c2] = c2units;
unordered_map<Unit, ConversionData, UnitHash> unit1Map = unordered_map<Unit, ConversionData, UnitHash>();
unordered_map<Unit, ConversionData, UnitHash> unit2Map = unordered_map<Unit, ConversionData, UnitHash>();
unordered_map<Unit, ConversionData, UnitHash> unit3Map = unordered_map<Unit, ConversionData, UnitHash>();
unordered_map<Unit, ConversionData, UnitHash> unit4Map = unordered_map<Unit, ConversionData, UnitHash>();
ConversionData conversion1, conversion2, conversion3, conversion4, conversion5;
SetConversionDataParams(&conversion1, 1.0, 0, false);
SetConversionDataParams(&conversion2, 0.08333333333333333333333333333333, 0, false);
SetConversionDataParams(&conversion3, 12.0, 0, false);
SetConversionDataParams(&conversion4, 0.453592, 0, false);
SetConversionDataParams(&conversion5, 2.20462, 0, false);
//Setting the conversion ratios for testing
unit1Map[u1] = conversion1;
unit1Map[u2] = conversion2;
unit2Map[u1] = conversion3;
unit2Map[u2] = conversion1;
unit3Map[u3] = conversion1;
unit3Map[u4] = conversion4;
unit4Map[u3] = conversion5;
unit4Map[u4] = conversion1;
m_ratioMaps[u1] = unit1Map;
m_ratioMaps[u2] = unit2Map;
m_ratioMaps[u3] = unit3Map;
m_ratioMaps[u4] = unit4Map;
}
void LoadData()
{
m_loadDataCallCount++;
}
vector<Category> LoadOrderedCategories()
{
return m_categories;
}
vector<Unit> LoadOrderedUnits(const Category& c)
{
return m_units[c];
}
unordered_map<Unit, ConversionData, UnitHash> LoadOrderedRatios(const Unit& u)
{
return m_ratioMaps[u];
}
bool SupportsCategory(const Category& target)
{
return true;
}
UINT m_loadDataCallCount;
private:
vector<Category> m_categories;
CategoryToUnitVectorMap m_units;
UnitToUnitToConversionDataMap m_ratioMaps;
};
class TestUnitConverterVMCallback : public IUnitConverterVMCallback
{
public:
void Reset()
{
m_maxDigitsReachedCallCount = 0;
}
void DisplayCallback(const wstring& from, const wstring& to) override
{
m_lastFrom = from;
m_lastTo = to;
}
void SuggestedValueCallback(const vector<tuple<wstring, Unit>>& suggestedValues) override
{
m_lastSuggested = suggestedValues;
}
void MaxDigitsReached() override
{
m_maxDigitsReachedCallCount++;
}
int GetMaxDigitsReachedCallCount()
{
return m_maxDigitsReachedCallCount;
}
bool CheckDisplayValues(wstring from, wstring to)
{
return (from == m_lastFrom && to == m_lastTo);
}
bool CheckSuggestedValues(vector<tuple<wstring, Unit>> suggested)
{
if (suggested.size() != m_lastSuggested.size())
{
return false;
}
bool returnValue = true;
for (unsigned int i = 0; i < suggested.size(); i++)
{
if (suggested[i] != m_lastSuggested[i])
{
returnValue = false;
break;
}
}
return returnValue;
}
private:
wstring m_lastFrom;
wstring m_lastTo;
vector<tuple<wstring, Unit>> m_lastSuggested;
int m_maxDigitsReachedCallCount = 0;
};
class UnitConverterTest
{
public:
// Declare this class as a TestClass, and supply metadata if necessary.
TEST_CLASS(UnitConverterTest);
TEST_CLASS_SETUP(CommonSetup);
TEST_METHOD_CLEANUP(Cleanup);
TEST_METHOD(UnitConverterTestInit);
TEST_METHOD(UnitConverterTestBasic);
TEST_METHOD(UnitConverterTestGetters);
TEST_METHOD(UnitConverterTestGetCategory);
TEST_METHOD(UnitConverterTestUnitTypeSwitching);
TEST_METHOD(UnitConverterTestSerialization);
TEST_METHOD(UnitConverterTestDeSerialization);
TEST_METHOD(UnitConverterTestQuote);
TEST_METHOD(UnitConverterTestUnquote);
TEST_METHOD(UnitConverterTestBackspace);
TEST_METHOD(UnitConverterTestScientificInputs);
TEST_METHOD(UnitConverterTestSupplementaryResultRounding);
TEST_METHOD(UnitConverterTestMaxDigitsReached);
TEST_METHOD(UnitConverterTestMaxDigitsReached_LeadingDecimal);
TEST_METHOD(UnitConverterTestMaxDigitsReached_TrailingDecimal);
TEST_METHOD(UnitConverterTestMaxDigitsReached_MultipleTimes);
private:
static void ExecuteCommands(vector<Command> commands);
static shared_ptr<UnitConverter> s_unitConverter;
static shared_ptr<TestUnitConverterConfigLoader> s_xmlLoader;
static shared_ptr<TestUnitConverterVMCallback> s_testVMCallback;
static Category s_testLength;
static Category s_testWeight;
static Unit s_testInches;
static Unit s_testFeet;
static Unit s_testPounds;
static Unit s_testKilograms;
};
shared_ptr<UnitConverter> UnitConverterTest::s_unitConverter;
shared_ptr<TestUnitConverterConfigLoader> UnitConverterTest::s_xmlLoader;
shared_ptr<TestUnitConverterVMCallback> UnitConverterTest::s_testVMCallback;
Category UnitConverterTest::s_testLength;
Category UnitConverterTest::s_testWeight;
Unit UnitConverterTest::s_testInches;
Unit UnitConverterTest::s_testFeet;
Unit UnitConverterTest::s_testPounds;
Unit UnitConverterTest::s_testKilograms;
// Creates instance of UnitConverter before running tests
bool UnitConverterTest::CommonSetup()
{
s_testVMCallback = make_shared<TestUnitConverterVMCallback>();
s_xmlLoader = make_shared<TestUnitConverterConfigLoader>();
s_unitConverter = make_shared<UnitConverter>(s_xmlLoader);
s_unitConverter->SetViewModelCallback(s_testVMCallback);
SetCategoryParams(&s_testLength, 1, L"Length", true);
SetCategoryParams(&s_testWeight, 2, L"Weight", false);
SetUnitParams(&s_testInches, 1, L"Inches", L"In", true, true, false);
SetUnitParams(&s_testFeet, 2, L"Feet", L"Ft", false, false, false);
SetUnitParams(&s_testPounds, 3, L"Pounds", L"Lb", true, true, false);
SetUnitParams(&s_testKilograms, 4, L"Kilograms", L"Kg", false, false, false);
return true;
}
// Resets calculator state to start state after each test
bool UnitConverterTest::Cleanup()
{
s_unitConverter->DeSerialize(wstring());
s_testVMCallback->Reset();
return true;
}
void UnitConverterTest::ExecuteCommands(vector<Command> commands)
{
for (size_t i = 0; i < commands.size() && commands[i] != Command::None; i++)
{
s_unitConverter->SendCommand(commands[i]);
}
}
// Test ctor/initialization states
void UnitConverterTest::UnitConverterTestInit()
{
VERIFY_ARE_EQUAL((UINT)0, s_xmlLoader->m_loadDataCallCount); // shouldn't have initialized the loader yet
s_unitConverter->Initialize();
VERIFY_ARE_EQUAL((UINT)1, s_xmlLoader->m_loadDataCallCount); // now we should have loaded
}
// Verify a basic input command stream.'3', '2', '.', '0'
void UnitConverterTest::UnitConverterTestBasic()
{
tuple<wstring, Unit> test1[] = {tuple<wstring,Unit>(wstring(L"0.25"), s_testFeet)};
tuple<wstring, Unit> test2[] = {tuple<wstring,Unit>(wstring(L"2.5"), s_testFeet)};
s_unitConverter->SendCommand(Command::Three);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"3"), wstring(L"3")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test1),end(test1))));
s_unitConverter->SendCommand(Command::Zero);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30"), wstring(L"30")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test2),end(test2))));
s_unitConverter->SendCommand(Command::Decimal);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30."), wstring(L"30")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test2),end(test2))));
s_unitConverter->SendCommand(Command::Zero);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30.0"), wstring(L"30")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test2),end(test2))));
}
// Check the getter functions
void UnitConverterTest::UnitConverterTestGetters()
{
Category test1[] = {s_testLength, s_testWeight};
Unit test2[] = {s_testInches, s_testFeet};
VERIFY_IS_TRUE(s_unitConverter->GetCategories() == vector<Category>(begin(test1),end(test1)));
VERIFY_IS_TRUE(get<0>(s_unitConverter->SetCurrentCategory(test1[0])) == vector<Unit>(begin(test2),end(test2)));
}
// Test getting category after it has been set.
void UnitConverterTest::UnitConverterTestGetCategory()
{
s_unitConverter->SetCurrentCategory(s_testWeight);
VERIFY_IS_TRUE(s_unitConverter->GetCurrentCategory() == s_testWeight);
}
// Test switching of unit types
void UnitConverterTest::UnitConverterTestUnitTypeSwitching()
{
// Enter 57 into the from field, then switch focus to the to field (making it the new from field)
s_unitConverter->SendCommand(Command::Five);
s_unitConverter->SendCommand(Command::Seven);
s_unitConverter->SwitchActive(wstring(L"57"));
// Now set unit conversion to go from kilograms to pounds
s_unitConverter->SetCurrentCategory(s_testWeight);
s_unitConverter->SetCurrentUnitTypes(s_testKilograms, s_testPounds);
s_unitConverter->SendCommand(Command::Five);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"5"), wstring(L"11.0231")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>()));
}
// Test serialization
void UnitConverterTest::UnitConverterTestSerialization()
{
wstring test1 = wstring(L"4;Kilograms;Kg;0;0;0;|3;Pounds;Lb;1;1;0;|2;0;Weight;|1;1;0;52.8;116.4039;|1;1;Length;,2;0;Weight;,|1;1;Length;[1;Inches;In;1;1;0;,2;Feet;Ft;0;0;0;,[]2;0;Weight;[3;Pounds;Lb;1;1;0;,4;Kilograms;Kg;0;0;0;,[]|1;Inches;In;1;1;0;[1;Inches;In;1;1;0;:1;0;0;:,2;Feet;Ft;0;0;0;:0.08333333333333332870740406406185;0;0;:,[]2;Feet;Ft;0;0;0;[1;Inches;In;1;1;0;:12;0;0;:,2;Feet;Ft;0;0;0;:1;0;0;:,[]3;Pounds;Lb;1;1;0;[3;Pounds;Lb;1;1;0;:1;0;0;:,4;Kilograms;Kg;0;0;0;:0.45359199999999999519673110626172;0;0;:,[]4;Kilograms;Kg;0;0;0;[3;Pounds;Lb;1;1;0;:2.20461999999999980204279381723609;0;0;:,4;Kilograms;Kg;0;0;0;:1;0;0;:,[]|");
s_unitConverter->SendCommand(Command::Five);
s_unitConverter->SendCommand(Command::Two);
s_unitConverter->SendCommand(Command::Decimal);
s_unitConverter->SendCommand(Command::Eight);
s_unitConverter->SetCurrentCategory(s_testWeight);
s_unitConverter->SetCurrentUnitTypes(s_testKilograms, s_testPounds);
VERIFY_IS_TRUE(s_unitConverter->Serialize().compare(test1) == 0);
}
// Test input escaping
void UnitConverterTest::UnitConverterTestQuote()
{
wstring input1 = L"Weight";
wstring output1 = L"Weight";
wstring input2 = L"{p}Weig;[ht|";
wstring output2 = L"{lb}p{rb}Weig{sc}{lc}ht{p}";
wstring input3 = L"{{{t;s}}},:]";
wstring output3 = L"{lb}{lb}{lb}t{sc}s{rb}{rb}{rb}{cm}{co}{rc}";
VERIFY_IS_TRUE(UnitConverter::Quote(input1) == output1);
VERIFY_IS_TRUE(UnitConverter::Quote(input2) == output2);
VERIFY_IS_TRUE(UnitConverter::Quote(input3) == output3);
}
// Test output unescaping
void UnitConverterTest::UnitConverterTestUnquote()
{
wstring input1 = L"Weight";
wstring input2 = L"{p}Weig;[ht|";
wstring input3 = L"{{{t;s}}},:]";
VERIFY_IS_TRUE(UnitConverter::Unquote(input1) == input1);
VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input1)) == input1);
VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input2)) == input2);
VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input3)) == input3);
}
// Test de-serialization
void UnitConverterTest::UnitConverterTestDeSerialization()
{
wstring test1 = wstring(L"4;Kilograms;Kg;0;0;0;|3;Pounds;Lb;1;1;0;|2;0;Weight;|1;1;0;52.8;116.4039;|1;1;Length;,2;0;Weight;,|1;1;Length;[1;Inches;In;1;1;0;,2;Feet;Ft;0;0;0;,[]2;0;Weight;[3;Pounds;Lb;1;1;0;,4;Kilograms;Kg;0;0;0;,[]|1;Inches;In;1;1;0;[1;Inches;In;1;1;0;:1;0;0;:,2;Feet;Ft;0;0;0;:0.08333333333333332870740406406185;0;0;:,[]2;Feet;Ft;0;0;0;[1;Inches;In;1;1;0;:12;0;0;:,2;Feet;Ft;0;0;0;:1;0;0;:,[]3;Pounds;Lb;1;1;0;[3;Pounds;Lb;1;1;0;:1;0;0;:,4;Kilograms;Kg;0;0;0;:0.45359199999999999519673110626172;0;0;:,[]4;Kilograms;Kg;0;0;0;[3;Pounds;Lb;1;1;0;:2.20461999999999980204279381723609;0;0;:,4;Kilograms;Kg;0;0;0;:1;0;0;:,[]|");
s_unitConverter->DeSerialize(test1);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"52.8"), wstring(L"116.4039")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>()));
}
// Test backspace commands
void UnitConverterTest::UnitConverterTestBackspace()
{
tuple<wstring, Unit> test1[] = {tuple<wstring,Unit>(wstring(L"13.66"), s_testKilograms)};
tuple<wstring, Unit> test2[] = {tuple<wstring,Unit>(wstring(L"13.65"), s_testKilograms)};
tuple<wstring, Unit> test3[] = {tuple<wstring,Unit>(wstring(L"13.61"), s_testKilograms)};
tuple<wstring, Unit> test4[] = {tuple<wstring,Unit>(wstring(L"1.36"), s_testKilograms)};
s_unitConverter->SetCurrentCategory(s_testWeight);
s_unitConverter->SetCurrentUnitTypes(s_testPounds, s_testPounds);
s_unitConverter->SendCommand(Command::Three);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Decimal);
s_unitConverter->SendCommand(Command::One);
s_unitConverter->SendCommand(Command::Two);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30.12"), wstring(L"30.12")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test1),end(test1))));
s_unitConverter->SendCommand(Command::Backspace);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30.1"), wstring(L"30.1")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test2),end(test2))));
s_unitConverter->SendCommand(Command::Backspace);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30."), wstring(L"30")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test3),end(test3))));
s_unitConverter->SendCommand(Command::Backspace);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"30"), wstring(L"30")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test3),end(test3))));
s_unitConverter->SendCommand(Command::Backspace);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"3"), wstring(L"3")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test4),end(test4))));
s_unitConverter->SendCommand(Command::Backspace);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"0"), wstring(L"0")));
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>()));
}
// Test large values
void UnitConverterTest::UnitConverterTestScientificInputs()
{
s_unitConverter->SetCurrentCategory(s_testWeight);
s_unitConverter->SetCurrentUnitTypes(s_testPounds, s_testKilograms);
s_unitConverter->SendCommand(Command::Decimal);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::Zero);
s_unitConverter->SendCommand(Command::One);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"0.00000000000001"), wstring(L"4.535920e-15")));
s_unitConverter->SwitchActive(wstring(L"4.535920e-15"));
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
s_unitConverter->SendCommand(Command::Nine);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"999999999999999"), wstring(L"2.204620e+15")));
s_unitConverter->SwitchActive(wstring(L"2.20463e+15"));
s_unitConverter->SendCommand(Command::One);
s_unitConverter->SendCommand(Command::Two);
s_unitConverter->SendCommand(Command::Three);
s_unitConverter->SendCommand(Command::Four);
s_unitConverter->SendCommand(Command::Five);
s_unitConverter->SendCommand(Command::Six);
s_unitConverter->SendCommand(Command::Seven);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"1234567"), wstring(L"559989.7")));
s_unitConverter->SwitchActive(wstring(L"559989.7"));
s_unitConverter->SendCommand(Command::One);
s_unitConverter->SendCommand(Command::Two);
s_unitConverter->SendCommand(Command::Three);
s_unitConverter->SendCommand(Command::Four);
s_unitConverter->SendCommand(Command::Five);
s_unitConverter->SendCommand(Command::Six);
s_unitConverter->SendCommand(Command::Seven);
s_unitConverter->SendCommand(Command::Eight);
VERIFY_IS_TRUE(s_testVMCallback->CheckDisplayValues(wstring(L"12345678"), wstring(L"27217528.63236")));
}
// Test large values
void UnitConverterTest::UnitConverterTestSupplementaryResultRounding()
{
tuple<wstring, Unit> test1[] = {tuple<wstring,Unit>(wstring(L"27.75"), s_testFeet)};
tuple<wstring, Unit> test2[] = {tuple<wstring,Unit>(wstring(L"277.8"), s_testFeet)};
tuple<wstring, Unit> test3[] = {tuple<wstring,Unit>(wstring(L"2778"), s_testFeet)};
s_unitConverter->SendCommand(Command::Three);
s_unitConverter->SendCommand(Command::Three);
s_unitConverter->SendCommand(Command::Three);
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test1),end(test1))));
s_unitConverter->SendCommand(Command::Three);
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test2),end(test2))));
s_unitConverter->SendCommand(Command::Three);
VERIFY_IS_TRUE(s_testVMCallback->CheckSuggestedValues(vector<tuple<wstring, Unit>>(begin(test3),end(test3))));
}
void UnitConverterTest::UnitConverterTestMaxDigitsReached()
{
ExecuteCommands({
Command::One,
Command::Two,
Command::Three,
Command::Four,
Command::Five,
Command::Six,
Command::Seven,
Command::Eight,
Command::Nine,
Command::One,
Command::Zero,
Command::One,
Command::One,
Command::One,
Command::Two
});
VERIFY_ARE_EQUAL(0, s_testVMCallback->GetMaxDigitsReachedCallCount());
ExecuteCommands({ Command::One });
VERIFY_ARE_EQUAL(1, s_testVMCallback->GetMaxDigitsReachedCallCount());
}
void UnitConverterTest::UnitConverterTestMaxDigitsReached_LeadingDecimal()
{
ExecuteCommands({
Command::Zero,
Command::Decimal,
Command::One,
Command::Two,
Command::Three,
Command::Four,
Command::Five,
Command::Six,
Command::Seven,
Command::Eight,
Command::Nine,
Command::One,
Command::Zero,
Command::One,
Command::One,
Command::One
});
VERIFY_ARE_EQUAL(0, s_testVMCallback->GetMaxDigitsReachedCallCount());
ExecuteCommands({ Command::Two });
VERIFY_ARE_EQUAL(1, s_testVMCallback->GetMaxDigitsReachedCallCount());
}
void UnitConverterTest::UnitConverterTestMaxDigitsReached_TrailingDecimal()
{
ExecuteCommands({
Command::One,
Command::Two,
Command::Three,
Command::Four,
Command::Five,
Command::Six,
Command::Seven,
Command::Eight,
Command::Nine,
Command::One,
Command::Zero,
Command::One,
Command::One,
Command::One,
Command::Two,
Command::Decimal
});
VERIFY_ARE_EQUAL(0, s_testVMCallback->GetMaxDigitsReachedCallCount());
ExecuteCommands({ Command::One });
VERIFY_ARE_EQUAL(1, s_testVMCallback->GetMaxDigitsReachedCallCount());
}
void UnitConverterTest::UnitConverterTestMaxDigitsReached_MultipleTimes()
{
ExecuteCommands({
Command::One,
Command::Two,
Command::Three,
Command::Four,
Command::Five,
Command::Six,
Command::Seven,
Command::Eight,
Command::Nine,
Command::One,
Command::Zero,
Command::One,
Command::One,
Command::One,
Command::Two
});
VERIFY_ARE_EQUAL(0, s_testVMCallback->GetMaxDigitsReachedCallCount());
for (auto count = 1; count <= 10; count++)
{
ExecuteCommands({ Command::Three });
VERIFY_ARE_EQUAL(count, s_testVMCallback->GetMaxDigitsReachedCallCount(), to_wstring(count).c_str());
}
}
}

View File

@ -1,70 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
namespace UCM = UnitConversionManager;
#pragma once
namespace CalculatorUnitTests
{
static UCM::Unit UNIT1 = { 1, L"UNIT1", L"U1", true, false, false };
static UCM::Unit UNIT2 = { 2, L"UNIT2", L"U2", false, true, false };
static UCM::Unit UNIT3 = { 3, L"UNIT3", L"U3", false, false, false };
static UCM::Unit UNIT4 = { 4, L"UNIT4", L"U4", true, false, false };
static UCM::Unit UNIT5 = { 5, L"UNIT5", L"U5", false, false, false };
static UCM::Unit UNIT6 = { 6, L"UNIT6", L"U6", false, true, false };
static UCM::Unit UNIT7 = { 7, L"UNIT7", L"U7", false, true, false };
static UCM::Unit UNIT8 = { 8, L"UNIT8", L"U8", false, false, false };
static UCM::Unit UNIT9 = { 9, L"UNIT9", L"U9", true, false, false };
static UCM::Unit UNITWHIMSY = { 10, L"Whimsy", L"UW", true, false, true };
static UCM::Category CAT1 = { 1, L"CAT1", false }; // contains Unit1 - Unit3
static UCM::Category CAT2 = { 2, L"CAT2", false }; // contains Unit4 - Unit6
static UCM::Category CAT3 = { 3, L"CAT3", false }; // contains Unit7 - Unit9
class UnitConverterMock : public UnitConversionManager::IUnitConverter
{
public:
UnitConverterMock();
void Initialize() override;
std::vector<UCM::Category> GetCategories() override;
UCM::CategorySelectionInitializer SetCurrentCategory(const UCM::Category& input) override;
UCM::Category GetCurrentCategory();
void SetCurrentUnitTypes(const UCM::Unit& fromType, const UCM::Unit& toType) override;
void SwitchActive(const std::wstring& newValue);
std::wstring Serialize() override;
void DeSerialize(const std::wstring& serializedData) override;
std::wstring SaveUserPreferences() override;
void RestoreUserPreferences(_In_ const std::wstring& userPreferences) override;
void SendCommand(UCM::Command command) override;
void SetViewModelCallback(const std::shared_ptr<UCM::IUnitConverterVMCallback>& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<UCM::IViewModelCurrencyCallback>& newCallback) override {}
concurrency::task<std::pair<bool, std::wstring>> RefreshCurrencyRatios() override
{
co_return std::make_pair(L"", L"");
}
UINT m_initCallCount;
UINT m_getCategoriesCallCount;
UINT m_setCurrentCategoryCallCount;
UINT m_setCurUnitTypesCallCount;
UINT m_switchActiveCallCount;
UINT m_sendCommandCallCount;
UINT m_setVMCallbackCallCount;
UINT m_serializeCallCount;
UINT m_deSerializeCallCount;
UCM::Category m_curCategory;
UCM::Unit m_curFrom;
UCM::Unit m_curTo;
UCM::Command m_lastCommand;
std::shared_ptr<UCM::IUnitConverterVMCallback> m_vmCallback;
std::vector<std::tuple<std::wstring, UCM::Unit>> m_suggestedList;
std::wstring m_curValue;
};
}

View File

@ -1,30 +0,0 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Seralize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>

View File

@ -1,8 +0,0 @@
<Application
x:Class="CalculatorUnitTests.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CalculatorUnitTests"
RequestedTheme="Light">
</Application>

View File

@ -1,111 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.cpp
// Implementation of the App class.
//
#include "pch.h"
#include "UnitTestApp.xaml.h"
using namespace CalculatorUnitTests;
using namespace Platform;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
App::App()
{
InitializeComponent();
Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
#if _DEBUG
// Show graphics profiling information while debugging.
if (IsDebuggerPresent())
{
// Display the current frame rate counters
DebugSettings->EnableFrameRateCounter = true;
}
#endif
auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
rootFrame = ref new Frame();
rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed);
if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
{
// TODO: Restore the saved session state only when appropriate, scheduling the
// final launch steps after the restore is complete
}
// Place the frame in the current Window
Window::Current->Content = rootFrame;
}
Microsoft::VisualStudio::TestPlatform::TestExecutor::WinRTCore::UnitTestClient::CreateDefaultUI();
Window::Current->Activate();
Microsoft::VisualStudio::TestPlatform::TestExecutor::WinRTCore::UnitTestClient::Run(e->Arguments);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
{
(void) sender; // Unused parameter
(void) e; // Unused parameter
//TODO: Save application state and stop any background activity
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e)
{
throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name);
}

View File

@ -1,35 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.h
// Declaration of the App class.
//
#pragma once
#include "UnitTestApp.g.h"
#include "CalcViewModel\DateCalculatorViewModel.h"
#include "CalcViewModel\StandardCalculatorViewModel.h"
#include "CalcViewModel\UnitConverterViewModel.h"
#include "CalcViewModel\MemoryItemViewModel.h"
namespace CalculatorUnitTests
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
ref class App sealed
{
protected:
virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override;
internal:
App();
private:
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e);
};
}

View File

@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
namespace CalculatorUnitTests
{
class UtilsTests
{
public:
TEST_CLASS(UtilsTests);
TEST_METHOD(IsLastCharacterSuccess)
{
VERIFY_IS_TRUE(Utils::IsLastCharacterTarget(L"Test.", L'.'));
}
TEST_METHOD(IsLastCharacterSuccessMultipleSuffices)
{
VERIFY_IS_TRUE(Utils::IsLastCharacterTarget(L"Test..", L'.'));
}
TEST_METHOD(IsLastCharacterFailure)
{
VERIFY_IS_FALSE(Utils::IsLastCharacterTarget(L"Test", L'.'));
}
TEST_METHOD(IsLastCharacterFailureAllButLastMatch)
{
VERIFY_IS_FALSE(Utils::IsLastCharacterTarget(L".....T", L'.'));
}
TEST_METHOD(IsLastCharacterFailureEmptyInput)
{
VERIFY_IS_FALSE(Utils::IsLastCharacterTarget({}, L'.'));
}
TEST_METHOD(IsLastCharacterFailureNullTarget)
{
VERIFY_IS_FALSE(Utils::IsLastCharacterTarget({}, NULL));
}
};
}

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.TestInfrastructure.UniversalTest" version="1.0.20181107.1" targetFramework="native" />
<package id="Taef.Native" version="10.34.181220007" targetFramework="native" />
<package id="Taef.Native.UWP" version="10.34.181220007" targetFramework="native" />
</packages>

View File

@ -1,10 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// pch.cpp
// Include the standard header and generate the precompiled header.
//
#include "pch.h"

View File

@ -1,120 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// pch.h
// Header for standard system include files.
//
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define UNIT_TESTS
#include <windows.h>
#include <collection.h>
#include <ppltasks.h>
#include <assert.h>
#include <concrt.h>
#include <string>
#include <bitset>
#include <memory>
#include <vector>
#include <map>
#include <list>
#include <stack>
#include <deque>
#include <regex>
#include <concurrent_vector.h>
#include <experimental/resumable>
#include <pplawait.h>
#include <unordered_map>
#include <mutex>
#include <locale>
#include <sal.h>
#include <sstream>
// C++\WinRT Headers
#include "winrt\base.h"
#include "winrt\Windows.Foundation.Diagnostics.h"
#include "winrt\Windows.Globalization.h"
#include "winrt\Windows.Globalization.DateTimeFormatting.h"
#include "winrt\Windows.System.UserProfile.h"
namespace CalculatorApp
{
namespace WF = Windows::Foundation;
namespace WUC = Windows::UI::Core;
namespace WX = Windows::UI::Xaml;
namespace WXC = Windows::UI::Xaml::Controls;
namespace WXCP = Windows::UI::Xaml::Controls::Primitives;
namespace P = Platform;
namespace PC = Platform::Collections;
namespace WXI = Windows::UI::Xaml::Input;
namespace WFC = Windows::Foundation::Collections;
namespace WS = Windows::System;
namespace WAR = Windows::ApplicationModel::Resources;
namespace WXMA = Windows::UI::Xaml::Media::Animation;
namespace WXD = Windows::UI::Xaml::Data;
namespace WXInt = Windows::UI::Xaml::Interop;
namespace WXM = Windows::UI::Xaml::Markup;
namespace WXA = Windows::UI::Xaml::Automation;
}
// The following namespaces exist as a convenience to resolve
// ambiguity for Windows types in the Windows::UI::Xaml::Automation::Peers
// namespace that only exist on RS3.
// Once the app switches to min version RS3, the namespaces can be removed.
// TODO - MSFT 12735088
namespace StandardPeers = Windows::UI::Xaml::Automation::Peers;
namespace CalculatorApp::Common::Automation {}
namespace CustomPeers = CalculatorApp::Common::Automation;
//CalcManager Headers
#include "CalcManager\CalculatorVector.h"
#include "CalcManager\ExpressionCommand.h"
#include "CalcManager\CalculatorResource.h"
#include "CalcManager\CalculatorManager.h"
#include "CalcManager\UnitConverter.h"
// CalcViewModel Headers
#include "CalcViewModel\Common\DelegateCommand.h"
#include "CalcViewModel\Common\Utils.h"
#include "CalcViewModel\Common\MyVirtualKey.h"
#include "CalcViewModel\Common\NavCategory.h"
#include "CalcViewModel\Common\CalculatorButtonUser.h"
#include "CalcViewModel\Common\NetworkManager.h"
#include "Mocks\CurrencyHttpClient.h"
#include "Helpers.h"
#include "UnitTestApp.xaml.h"
#define TEST_METHOD_IGNORE();\
BEGIN_TEST_METHOD_PROPERTIES()\
TEST_METHOD_PROPERTY(L"Ignore", L"true")\
END_TEST_METHOD_PROPERTIES()
#define VERIFY_THROWS_WINRT(__operation, __exception, ...) \
{ \
bool __exceptionHit = false; \
try \
{ \
__operation; \
} \
catch(__exception __e) \
{ \
WEX::TestExecution::Private::MacroVerify::ExpectedExceptionThrown(__e, L#__exception, L#__operation, __VA_ARGS__); \
__exceptionHit = true; \
} \
\
if (!__exceptionHit) \
{ \
WEX::TestExecution::Private::MacroVerify::ExpectedExceptionNotThrown(L#__exception, L#__operation, PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__); \
} \
}

View File

@ -1,34 +0,0 @@
{
"$schema": "http://universaltest/schema/testmddefinition-4.json",
"Package": {
"ComponentName": "Calculator",
"SubComponentName": "UnitTests"
},
"SupportedArchitectures": [ "All" ],
"Execution": {
"Type": "TAEF",
"Parameter": "/APPX:CertificateFileName=CalculatorUnitTests.cer:TrustedPeople /screenCaptureOnError /TestMode:EnsureLoggedOnUser /TestMode:EtwLogger",
"ExecutionTimeoutInMinutes": "30"
},
"Dependencies": {
"Files": [
{
"SourcePath": "$(AppxPackagePublicKeyFile)",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
},
{
"SourcePath": "$(AppxPackageVCLibsDependency)",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
}
],
"Packages": [
"Microsoft-Windows-Test-Taef",
"Microsoft-Windows-Test-EtwProcessor",
"Microsoft-Test-Taef-EnsureLoggedOnUserTestMode",
"Microsoft-Test-Taef-EtwLoggerTestMode"
]
},
"Logs": [],
"Plugins": [],
"Profiles": []
}

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -12,6 +12,7 @@
constexpr int ASCII_0 = 48;
using namespace std;
using namespace CalcEngine;
void CHistoryCollector::ReinitHistory()
{
@ -51,7 +52,7 @@ CHistoryCollector::~CHistoryCollector()
}
}
void CHistoryCollector::AddOpndToHistory(wstring_view numStr, PRAT hNoNum, bool fRepetition)
void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition)
{
std::shared_ptr<CalculatorVector<int>> commands = std::make_shared<CalculatorVector<int>>();
// Check for negate
@ -92,7 +93,7 @@ void CHistoryCollector::AddOpndToHistory(wstring_view numStr, PRAT hNoNum, bool
}
auto operandCommand = std::make_shared<COpndCommand>(commands, fNegative, fDecimal, fSciFmt);
operandCommand->Initialize(hNoNum);
operandCommand->Initialize(rat);
int iCommandEnd = AddCommand(operandCommand);
m_lastOpStartIndex = IchAddSzToEquationSz(numStr, iCommandEnd);

View File

@ -211,9 +211,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
if (!m_HistoryCollector.FOpndAddedToHistory())
{
// if the prev command was ) or unop then it is already in history as a opnd form (...)
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
/* m_bChangeOp is true if there was an operation done and the */
@ -310,10 +308,7 @@ DoPrecedenceCheckAgain:
{
if (!m_HistoryCollector.FOpndAddedToHistory())
{
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
m_HistoryCollector.AddUnaryOpToHistory((INT)wParam, m_bInv, m_angletype);
@ -339,9 +334,7 @@ DoPrecedenceCheckAgain:
if(wParam == IDC_PERCENT)
{
CheckAndAddLastBinOpToHistory();
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat, true);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal, true /* Add to primary and secondary display */);
}
/* reset the m_bInv flag and indicators if it is set
@ -464,9 +457,7 @@ DoPrecedenceCheckAgain:
if (!m_HistoryCollector.FOpndAddedToHistory())
{
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
do {
@ -485,9 +476,7 @@ DoPrecedenceCheckAgain:
m_currentVal = m_holdVal;
DisplayNum(); // to update the m_numberString
m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false);
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat); // Adding the repeated last op to history
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history
}
// Do the current or last operation.
@ -595,9 +584,7 @@ DoPrecedenceCheckAgain:
if (!m_HistoryCollector.FOpndAddedToHistory())
{
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
// Get the operation and number and return result.
@ -701,9 +688,7 @@ DoPrecedenceCheckAgain:
if (!m_HistoryCollector.FOpndAddedToHistory())
{
PRAT curRat = m_currentVal.ToPRAT();
m_HistoryCollector.AddOpndToHistory(m_numberString, curRat);
destroyrat(curRat);
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
PRAT curRat = m_currentVal.ToPRAT();

View File

@ -288,7 +288,7 @@
<ClInclude Include="UnitConverter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CalculatorHistory.Cpp" />
<ClCompile Include="CalculatorHistory.cpp" />
<ClCompile Include="CalculatorManager.cpp" />
<ClCompile Include="CEngine\calc.cpp" />
<ClCompile Include="CEngine\CalcUtils.cpp" />
@ -315,9 +315,6 @@
<ClCompile Include="Ratpack\support.cpp" />
<ClCompile Include="Ratpack\trans.cpp" />
<ClCompile Include="Ratpack\transh.cpp" />
<!-- <ClCompile Include="Source Files\CalculatorController.cpp" />
<ClCompile Include="Source Files\CalculatorHistory.Cpp" />
<ClCompile Include="Source Files\CalculatorManager.cpp" /> -->
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="CEngine">
<UniqueIdentifier>{957a8e3c-00c7-48bc-b63c-83b2140a8251}</UniqueIdentifier>
</Filter>
@ -81,7 +77,7 @@
<ClCompile Include="Ratpack\transh.cpp">
<Filter>RatPack</Filter>
</ClCompile>
<ClCompile Include="CalculatorHistory.Cpp" />
<ClCompile Include="CalculatorHistory.cpp" />
<ClCompile Include="CalculatorManager.cpp" />
<ClCompile Include="UnitConverter.cpp" />
<ClCompile Include="CEngine\CalcInput.cpp">

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -7,6 +7,7 @@
#include "ExpressionCommand.h"
using namespace std;
using namespace CalcEngine;
constexpr wchar_t chNegate = L'-';
constexpr wchar_t chExp = L'e';
@ -94,25 +95,19 @@ void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
commandVisitor.Visit(*this);
}
COpndCommand::COpndCommand(_In_ shared_ptr<CalculatorVector<int>> const &commands,
_In_ bool fNegative,
_In_ bool fDecimal,
_In_ bool fSciFmt) :
m_commands(commands), m_fNegative(fNegative), m_fDecimal(fDecimal), m_fSciFmt(fSciFmt)
{
m_hnoNum = nullptr;
}
COpndCommand::COpndCommand(shared_ptr<CalculatorVector<int>> const &commands, bool fNegative, bool fDecimal, bool fSciFmt) :
m_commands(commands),
m_fNegative(fNegative),
m_fDecimal(fDecimal),
m_fSciFmt(fSciFmt),
m_fInitialized(false),
m_value{}
{}
void COpndCommand::Initialize(_In_ PRAT hNoNum)
void COpndCommand::Initialize(Rational const& rat)
{
assert(&m_hnoNum != nullptr);
if (m_hnoNum != nullptr)
{
destroyrat(m_hnoNum);
m_hnoNum = nullptr;
}
DUPRAT(m_hnoNum, hNoNum);
m_value = rat;
m_fInitialized = true;
}
const shared_ptr<CalculatorVector<int>> & COpndCommand::GetCommands() const
@ -294,18 +289,16 @@ const wstring & COpndCommand::GetToken(wchar_t decimalSymbol)
wstring COpndCommand::GetString(uint32_t radix, int32_t precision, wchar_t decimalSymbol)
{
wstring numString{};
if (m_hnoNum != nullptr)
wstring result{};
if (m_fInitialized)
{
numString = NumObjToString(m_hnoNum, radix, eNUMOBJ_FMT::FMT_FLOAT, precision);
PRAT valRat = m_value.ToPRAT();
result = NumObjToString(valRat, radix, eNUMOBJ_FMT::FMT_FLOAT, precision);
destroyrat(valRat);
}
return numString;
}
COpndCommand::~COpndCommand()
{
destroyrat(m_hnoNum);
return result;
}
void COpndCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)

View File

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "ExpressionCommandInterface.h"
#include "Header Files\CalcEngine.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/Rational.h"
class CParentheses : public IParenthesisCommand
{
@ -48,12 +49,12 @@ private:
class COpndCommand : public IOpndCommand
{
public:
COpndCommand(_In_ std::shared_ptr<CalculatorVector<int>> const &commands,
_In_ bool fNegative,
_In_ bool fDecimal,
_In_ bool fSciFmt);
~COpndCommand();
void Initialize(_In_ PRAT hNoNum);
COpndCommand(
std::shared_ptr<CalculatorVector<int>> const &commands,
bool fNegative,
bool fDecimal,
bool fSciFmt);
void Initialize(CalcEngine::Rational const& rat);
const std::shared_ptr<CalculatorVector<int>> & GetCommands() const;
void SetCommands(std::shared_ptr<CalculatorVector<int>> const& commands);
@ -73,8 +74,9 @@ private:
bool m_fNegative;
bool m_fSciFmt;
bool m_fDecimal;
bool m_fInitialized;
std::wstring m_token;
PRAT m_hnoNum;
CalcEngine::Rational m_value;
void ClearAllAndAppendCommand(CalculationManager::Command command);
};

View File

@ -5,6 +5,7 @@
#include "ICalcDisplay.h"
#include "IHistoryDisplay.h"
#include "Rational.h"
// maximum depth you can get by precedence. It is just an array's size limit.
static constexpr size_t MAXPRECDEPTH = 25;
@ -16,7 +17,7 @@ class CHistoryCollector {
public:
CHistoryCollector(ICalcDisplay *pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol); // Can throw errors
~CHistoryCollector();
void AddOpndToHistory(std::wstring_view numStr, PRAT hNoNum, bool fRepetition = false);
void AddOpndToHistory(std::wstring_view numStr, CalcEngine::Rational const& rat, bool fRepetition = false);
void RemoveLastOpndFromHistory();
void AddBinOpToHistory(int nOpCode, bool fNoRepetition = true);
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher);

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Common">
<UniqueIdentifier>{1daab7c4-63f6-4266-a259-f34acad66d09}</UniqueIdentifier>
</Filter>

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -273,13 +273,27 @@ bool DateCalculationEngine::TryGetCalendarDaysInYear(_In_ DateTime date, _Out_ U
// Adds/Subtracts certain value for a particular date unit
DateTime DateCalculationEngine::AdjustCalendarDate(Windows::Foundation::DateTime date, DateUnit dateUnit, int difference)
{
m_calendar->SetDateTime(date);
switch (dateUnit)
{
case DateUnit::Year:
{
// In the Japanese calendar, transition years have 2 partial years.
// It is not guaranteed that adding 1 year will always add 365 days in the Japanese Calendar.
// To work around this quirk, we will change the calendar system to Gregorian before adding 1 year in the Japanese Calendar case only.
// We will then return the calendar system back to the Japanese Calendar.
auto currentCalendarSystem = m_calendar->GetCalendarSystem();
if (currentCalendarSystem == CalendarIdentifiers::Japanese)
{
m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian);
}
m_calendar->AddYears(difference);
m_calendar->ChangeCalendarSystem(currentCalendarSystem);
break;
}
case DateUnit::Month:
m_calendar->AddMonths(difference);
break;

View File

@ -14,7 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "CalcViewModel\CalcViewModel.vcxproj", "{90E9761D-9262-4773-942D-CAEAE75D7140}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests_VS", "CalculatorUnitTests_VS\CalculatorUnitTests_VS.vcxproj", "{D3BAED2C-4B07-4E1D-8807-9D6499450349}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{D3BAED2C-4B07-4E1D-8807-9D6499450349}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -12,7 +12,6 @@
#include "CalcViewModel\Common\Automation\NarratorNotifier.h"
#include "CalcViewModel\Common\AppResourceProvider.h"
#include "CalcViewModel\Common\LocalizationSettings.h"
#include "Common\SuspensionManager.h"
#include "Views\MainPage.xaml.h"
using namespace CalculatorApp;
@ -283,10 +282,8 @@ void App::OnAppLaunch(IActivatedEventArgs^ args, String^ argument)
}
}
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
// Create a Frame to act as the navigation context
rootFrame = App::CreateFrame();
//SuspensionManager::RegisterFrame(rootFrame, "AppFrame");
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation

View File

@ -136,11 +136,6 @@
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<AppxBundle>Never</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(XefOutputRoot)' != ''">
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>$(Platform)</AppxBundlePlatforms>
<AppxBundlePlatforms Condition="'$(Platform)'=='win32'">x86</AppxBundlePlatforms>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 </AdditionalOptions>
@ -209,6 +204,11 @@
<AdditionalDependencies>WindowsApp.lib;$(VC_ReferencesPath_VC_x64)\pgort.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(IsStoreBuild)' == 'True'">
<ClCompile>
<AdditionalOptions>/DSEND_TELEMETRY %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<AppVersion Condition="'$(AppVersion)' == ''">0.0.0.0</AppVersion>
</PropertyGroup>
@ -224,8 +224,6 @@
<ClInclude Include="Controls\OverflowTextBlockAutomationPeer.h" />
<ClInclude Include="Common\AlwaysSelectedCollectionView.h" />
<ClInclude Include="Common\BindableBase.h" />
<ClInclude Include="Common\LayoutAwarePage.h" />
<ClInclude Include="Common\SuspensionManager.h" />
<ClInclude Include="Controls\AppBar.h" />
<ClInclude Include="Controls\CalculationResult.h" />
<ClInclude Include="Controls\CalculatorButton.h" />
@ -360,8 +358,6 @@
<ClCompile Include="Controls\CalculationResultAutomationPeer.cpp" />
<ClCompile Include="Controls\OverflowTextBlockAutomationPeer.cpp" />
<ClCompile Include="Common\BindableBase.cpp" />
<ClCompile Include="Common\LayoutAwarePage.cpp" />
<ClCompile Include="Common\SuspensionManager.cpp" />
<ClCompile Include="Controls\CalculationResult.cpp" />
<ClCompile Include="Controls\CalculatorButton.cpp" />
<ClCompile Include="Controls\FlipButtons.cpp" />
@ -822,9 +818,6 @@
</Font>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
</ProjectReference>
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
<Project>{90e9761d-9262-4773-942d-caeae75d7140}</Project>
</ProjectReference>

View File

@ -14,9 +14,6 @@
<Filter Include="Converters">
<UniqueIdentifier>{5a666ef7-54fb-46cc-9588-5cbcfaed3465}</UniqueIdentifier>
</Filter>
<Filter Include="PerfTrack">
<UniqueIdentifier>{1cba827f-63eb-4cda-8bf0-eea60190725e}</UniqueIdentifier>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{f9b88d9e-918b-49ac-869b-a1a380ec3201}</UniqueIdentifier>
</Filter>
@ -231,12 +228,6 @@
<ClCompile Include="Common\BindableBase.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\LayoutAwarePage.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\SuspensionManager.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Controls\CalculationResult.cpp">
<Filter>Controls</Filter>
</ClCompile>
@ -327,12 +318,6 @@
<ClInclude Include="Common\BindableBase.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\LayoutAwarePage.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\SuspensionManager.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Controls\AppBar.h">
<Filter>Controls</Filter>
</ClInclude>
@ -428,7 +413,6 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Calculator_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Page Include="Views\Calculator.xaml">
@ -1579,4 +1563,7 @@
<Filter>Assets</Filter>
</Font>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Calculator.rc" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -15,12 +15,21 @@ using namespace winrt::Windows::UI::ViewManagement;
namespace CalculatorApp
{
#ifdef SEND_TELEMETRY
// c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords
// c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords
constexpr int64_t MICROSOFT_KEYWORD_CRITICAL_DATA = 0x0000800000000000; // Bit 47
constexpr int64_t MICROSOFT_KEYWORD_MEASURES = 0x0000400000000000; // Bit 46
constexpr int64_t MICROSOFT_KEYWORD_TELEMETRY = 0x0000200000000000; // Bit 45
constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0x0000100000000000; // Bit 44 (reserved for future assignment)
#else
// define all Keyword options as 0 when we do not want to upload app telemetry
constexpr int64_t MICROSOFT_KEYWORD_CRITICAL_DATA = 0;
constexpr int64_t MICROSOFT_KEYWORD_MEASURES = 0;
constexpr int64_t MICROSOFT_KEYWORD_TELEMETRY = 0;
constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0;
#endif
#pragma region TraceLogger setup and cleanup

View File

@ -1,322 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "LayoutAwarePage.h"
#include "SuspensionManager.h"
#include "CalcViewModel\Common\LocalizationService.h"
#include "App.xaml.h"
using namespace CalculatorApp::Common;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Navigation;
/// <summary>
/// Initializes a new instance of the <see cref="LayoutAwarePage"/> class.
/// </summary>
LayoutAwarePage::LayoutAwarePage()
{
if (Windows::ApplicationModel::DesignMode::DesignModeEnabled)
{
return;
}
// Create an empty default view model
DefaultViewModel = ref new Map<String^, Object^>(std::less<String^>());
// When this page is part of the visual tree make two changes:
// 1) Map application view state to visual state for the page
// 2) Handle keyboard and mouse navigation requests
Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded);
// Undo the same changes when the page is no longer visible
Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded);
Language = LocalizationService::GetInstance()->GetLanguage();
}
static DependencyProperty^ _defaultViewModelProperty =
DependencyProperty::Register("DefaultViewModel",
TypeName(IObservableMap<String^, Object^>::typeid), TypeName(LayoutAwarePage::typeid), nullptr);
/// <summary>
/// Identifies the <see cref="DefaultViewModel"/> dependency property.
/// </summary>
DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get()
{
return _defaultViewModelProperty;
}
/// <summary>
/// Gets an implementation of <see cref="IObservableMap&lt;String, Object&gt;"/> designed to be
/// used as a trivial view model.
/// </summary>
IObservableMap<String^, Object^>^ LayoutAwarePage::DefaultViewModel::get()
{
return safe_cast<IObservableMap<String^, Object^>^>(GetValue(DefaultViewModelProperty));
}
/// <summary>
/// Sets an implementation of <see cref="IObservableMap&lt;String, Object&gt;"/> designed to be
/// used as a trivial view model.
/// </summary>
void LayoutAwarePage::DefaultViewModel::set(IObservableMap<String^, Object^>^ value)
{
SetValue(DefaultViewModelProperty, value);
}
/// <summary>
/// Invoked when the page is part of the visual tree
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
// Keyboard and mouse navigation only apply when occupying the entire window
if (this->ActualHeight == Window::Current->Bounds.Height &&
this->ActualWidth == Window::Current->Bounds.Width)
{
// Listen to the window directly so focus isn't required
_acceleratorKeyEventToken = Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated +=
ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^>(this,
&LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated);
_pointerPressedEventToken = Window::Current->CoreWindow->PointerPressed +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this,
&LayoutAwarePage::CoreWindow_PointerPressed);
_navigationShortcutsRegistered = true;
}
}
/// <summary>
/// Invoked when the page is removed from visual tree
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
if (_navigationShortcutsRegistered)
{
Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated -= _acceleratorKeyEventToken;
Window::Current->CoreWindow->PointerPressed -= _pointerPressedEventToken;
_navigationShortcutsRegistered = false;
}
}
#pragma region Navigation support
/// <summary>
/// Invoked as an event handler to navigate backward in the page's associated <see cref="Frame"/>
/// until it reaches the top of the navigation stack.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Unused parameter
(void) e; // Unused parameter
// Use the navigation frame to return to the topmost page
if (Frame != nullptr)
{
while (Frame->CanGoBack)
{
Frame->GoBack();
}
}
}
/// <summary>
/// Invoked as an event handler to navigate backward in the navigation stack
/// associated with this page's <see cref="Frame"/>.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Unused parameter
(void) e; // Unused parameter
// Use the navigation frame to return to the previous page
if (Frame != nullptr && Frame->CanGoBack)
{
Frame->GoBack();
}
}
/// <summary>
/// Invoked as an event handler to navigate forward in the navigation stack
/// associated with this page's <see cref="Frame"/>.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Unused parameter
(void) e; // Unused parameter
// Use the navigation frame to advance to the next page
if (Frame != nullptr && Frame->CanGoForward)
{
Frame->GoForward();
}
}
/// <summary>
/// Invoked on every keystroke, including system keys such as Alt key combinations, when
/// this page is active and occupies the entire window. Used to detect keyboard navigation
/// between pages even when the page itself doesn't have focus.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="args">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender,
AcceleratorKeyEventArgs^ args)
{
auto virtualKey = args->VirtualKey;
// Only investigate further when Left, Right, or the dedicated Previous or Next keys
// are pressed
if ((args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown ||
args->EventType == CoreAcceleratorKeyEventType::KeyDown) &&
(virtualKey == VirtualKey::Left || virtualKey == VirtualKey::Right ||
(int)virtualKey == 166 || (int)virtualKey == 167))
{
auto coreWindow = Window::Current->CoreWindow;
auto downState = Windows::UI::Core::CoreVirtualKeyStates::Down;
bool menuKey = (coreWindow->GetKeyState(VirtualKey::Menu) & downState) == downState;
bool controlKey = (coreWindow->GetKeyState(VirtualKey::Control) & downState) == downState;
bool shiftKey = (coreWindow->GetKeyState(VirtualKey::Shift) & downState) == downState;
bool noModifiers = !menuKey && !controlKey && !shiftKey;
bool onlyAlt = menuKey && !controlKey && !shiftKey;
if (((int)virtualKey == 166 && noModifiers) ||
(virtualKey == VirtualKey::Left && onlyAlt))
{
// When the previous key or Alt+Left are pressed navigate back
args->Handled = true;
GoBack(this, ref new RoutedEventArgs());
}
else if (((int)virtualKey == 167 && noModifiers) ||
(virtualKey == VirtualKey::Right && onlyAlt))
{
// When the next key or Alt+Right are pressed navigate forward
args->Handled = true;
GoForward(this, ref new RoutedEventArgs());
}
}
}
/// <summary>
/// Invoked on every mouse click, touch screen tap, or equivalent interaction when this
/// page is active and occupies the entire window. Used to detect browser-style next and
/// previous mouse button clicks to navigate between pages.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="args">Event data describing the conditions that led to the event.</param>
void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
auto properties = args->CurrentPoint->Properties;
// Ignore button chords with the left, right, and middle buttons
if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed ||
properties->IsMiddleButtonPressed) return;
// If back or foward are pressed (but not both) navigate appropriately
bool backPressed = properties->IsXButton1Pressed;
bool forwardPressed = properties->IsXButton2Pressed;
if (backPressed ^ forwardPressed)
{
args->Handled = true;
if (backPressed) GoBack(this, ref new RoutedEventArgs());
if (forwardPressed) GoForward(this, ref new RoutedEventArgs());
}
}
#pragma endregion
#pragma region Process lifetime management
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property provides the group to be displayed.</param>
void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e)
{
// Returning to a cached page through navigation shouldn't trigger state loading
if (_pageKey != nullptr) return;
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
_pageKey = "Page-" + Frame->BackStackDepth;
if (e->NavigationMode == NavigationMode::New)
{
// Clear existing state for forward navigation when adding a new page to the
// navigation stack
auto nextPageKey = _pageKey;
int nextPageIndex = Frame->BackStackDepth;
while (frameState->HasKey(nextPageKey))
{
frameState->Remove(nextPageKey);
nextPageIndex++;
nextPageKey = "Page-" + nextPageIndex;
}
// Pass the navigation parameter to the new page
LoadState(e->Parameter, nullptr);
}
else
{
// Pass the navigation parameter and preserved page state to the page, using
// the same strategy for loading suspended state and recreating pages discarded
// from cache
LoadState(e->Parameter, safe_cast<IMap<String^, Object^>^>(frameState->Lookup(_pageKey)));
}
}
/// <summary>
/// Invoked when this page will no longer be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property provides the group to be displayed.</param>
void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e)
{
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
auto pageState = ref new Map<String^, Object^>();
SaveState(pageState);
frameState->Insert(_pageKey, pageState);
}
/// <summary>
/// Populates the page with content passed during navigation. Any saved state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
/// </param>
/// <param name="pageState">A map of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited.</param>
void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap<String^, Object^>^ pageState)
{
}
/// <summary>
/// Preserves state associated with this page in case the application is suspended or the
/// page is discarded from the navigation cache. Values must conform to the serialization
/// requirements of <see cref="SuspensionManager.SessionState"/>.
/// </summary>
/// <param name="pageState">An empty map to be populated with serializable state.</param>
void LayoutAwarePage::SaveState(IMap<String^, Object^>^ pageState)
{
}
#pragma endregion

View File

@ -1,75 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <collection.h>
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// Typical implementation of Page that provides several important conveniences:
/// <list type="bullet">
/// <item>
/// <description>Application view state to visual state mapping</description>
/// </item>
/// <item>
/// <description>GoBack, GoForward, and GoHome event handlers</description>
/// </item>
/// <item>
/// <description>Mouse and keyboard shortcuts for navigation</description>
/// </item>
/// <item>
/// <description>State management for navigation and process lifetime management</description>
/// </item>
/// <item>
/// <description>A default view model</description>
/// </item>
/// </list>
/// </summary>
[Windows::Foundation::Metadata::WebHostHidden]
public ref class LayoutAwarePage : Windows::UI::Xaml::Controls::Page
{
internal:
LayoutAwarePage();
public:
static property Windows::UI::Xaml::DependencyProperty^ DefaultViewModelProperty
{
Windows::UI::Xaml::DependencyProperty^ get();
};
property Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::Object^>^ DefaultViewModel
{
Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::Object^>^ get();
void set(Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::Object^>^ value);
}
protected:
virtual void GoHome(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual void GoBack(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual void GoForward(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
virtual void LoadState(Platform::Object^ navigationParameter,
Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ pageState);
virtual void SaveState(Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ pageState);
private:
Platform::String^ _pageKey;
bool _navigationShortcutsRegistered;
Platform::Collections::Map<Platform::String^, Platform::Object^>^ _defaultViewModel;
Windows::Foundation::EventRegistrationToken _windowSizeEventToken,
_acceleratorKeyEventToken, _pointerPressedEventToken;
Platform::Collections::Vector<Windows::UI::Xaml::Controls::Control^>^ _layoutAwareControls;
void OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void CoreDispatcher_AcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher^ sender,
Windows::UI::Core::AcceleratorKeyEventArgs^ args);
void CoreWindow_PointerPressed(Windows::UI::Core::CoreWindow^ sender,
Windows::UI::Core::PointerEventArgs^ args);
LayoutAwarePage^ _this; // Strong reference to self, cleaned up in OnUnload
};
}
}

View File

@ -1,494 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// SuspensionManager.cpp
// Implementation of the SuspensionManager class
//
#include "pch.h"
#include "SuspensionManager.h"
using namespace CalculatorApp::Common;
using namespace Concurrency;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Storage;
using namespace Windows::Storage::FileProperties;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Interop;
namespace
{
Map<String^, Object^>^ _sessionState = ref new Map<String^, Object^>();
String^ sessionStateFilename = "_sessionState.dat";
// Forward declarations for object object read / write support
void WriteObject(Windows::Storage::Streams::DataWriter^ writer, Platform::Object^ object);
Platform::Object^ ReadObject(Windows::Storage::Streams::DataReader^ reader);
}
/// <summary>
/// Provides access to global session state for the current session. This state is serialized by
/// <see cref="SaveAsync"/> and restored by <see cref="RestoreAsync"/> which require values to be
/// one of the following: boxed values including integers, floating-point singles and doubles,
/// wide characters, boolean, Strings and Guids, or Map<String^, Object^> where map values are
/// subject to the same constraints. Session state should be as compact as possible.
/// </summary>
IMap<String^, Object^>^ SuspensionManager::SessionState::get(void)
{
return _sessionState;
}
/// <summary>
/// Wrap a WeakReference as a reference object for use in a collection.
/// </summary>
private ref class WeakFrame sealed
{
private:
WeakReference _frameReference;
internal:
WeakFrame(Frame^ frame) { _frameReference = frame; }
property Frame^ ResolvedFrame
{
Frame^ get(void) { return _frameReference.Resolve<Frame>(); }
};
};
namespace
{
std::vector<WeakFrame^> _registeredFrames;
DependencyProperty^ FrameSessionStateKeyProperty =
DependencyProperty::RegisterAttached("_FrameSessionStateKeyProperty",
TypeName(String::typeid), TypeName(SuspensionManager::typeid), nullptr);
DependencyProperty^ FrameSessionStateProperty =
DependencyProperty::RegisterAttached("_FrameSessionStateProperty",
TypeName(IMap<String^, Object^>::typeid), TypeName(SuspensionManager::typeid), nullptr);
}
/// <summary>
/// Registers a <see cref="Frame"/> instance to allow its navigation history to be saved to
/// and restored from <see cref="SessionState"/>. Frames should be registered once
/// immediately after creation if they will participate in session state management. Upon
/// registration if state has already been restored for the specified key
/// the navigation history will immediately be restored. Subsequent invocations of
/// <see cref="RestoreAsync(String)"/> will also restore navigation history.
/// </summary>
/// <param name="frame">An instance whose navigation history should be managed by
/// <see cref="SuspensionManager"/></param>
/// <param name="sessionStateKey">A unique key into <see cref="SessionState"/> used to
/// store navigation-related information.</param>
void SuspensionManager::RegisterFrame(Frame^ frame, String^ sessionStateKey)
{
if (frame->GetValue(FrameSessionStateKeyProperty) != nullptr)
{
throw ref new FailureException("Frames can only be registered to one session state key");
}
if (frame->GetValue(FrameSessionStateProperty) != nullptr)
{
throw ref new FailureException("Frames must be either be registered before accessing frame session state, or not registered at all");
}
// Use a dependency property to associate the session key with a frame, and keep a list of frames whose
// navigation state should be managed
frame->SetValue(FrameSessionStateKeyProperty, sessionStateKey);
_registeredFrames.insert(_registeredFrames.begin(), ref new WeakFrame(frame));
// Check to see if navigation state can be restored
RestoreFrameNavigationState(frame);
}
/// <summary>
/// Disassociates a <see cref="Frame"/> previously registered by <see cref="RegisterFrame"/>
/// from <see cref="SessionState"/>. Any navigation state previously captured will be
/// removed.
/// </summary>
/// <param name="frame">An instance whose navigation history should no longer be
/// managed.</param>
void SuspensionManager::UnregisterFrame(Frame^ frame)
{
// Remove session state and remove the frame from the list of frames whose navigation
// state will be saved (along with any weak references that are no longer reachable)
auto key = safe_cast<String^>(frame->GetValue(FrameSessionStateKeyProperty));
if (SessionState->HasKey(key)) SessionState->Remove(key);
_registeredFrames.erase(
std::remove_if(_registeredFrames.begin(), _registeredFrames.end(), [=](WeakFrame^& e)
{
auto testFrame = e->ResolvedFrame;
return testFrame == nullptr || testFrame == frame;
}),
_registeredFrames.end()
);
}
/// <summary>
/// Provides storage for session state associated with the specified <see cref="Frame"/>.
/// Frames that have been previously registered with <see cref="RegisterFrame"/> have
/// their session state saved and restored automatically as a part of the global
/// <see cref="SessionState"/>. Frames that are not registered have transient state
/// that can still be useful when restoring pages that have been discarded from the
/// navigation cache.
/// </summary>
/// <remarks>Apps may choose to rely on <see cref="LayoutAwarePage"/> to manage
/// page-specific state instead of working with frame session state directly.</remarks>
/// <param name="frame">The instance for which session state is desired.</param>
/// <returns>A collection of state subject to the same serialization mechanism as
/// <see cref="SessionState"/>.</returns>
IMap<String^, Object^>^ SuspensionManager::SessionStateForFrame(Frame^ frame)
{
auto frameState = safe_cast<IMap<String^, Object^>^>(frame->GetValue(FrameSessionStateProperty));
if (frameState == nullptr)
{
auto frameSessionKey = safe_cast<String^>(frame->GetValue(FrameSessionStateKeyProperty));
if (frameSessionKey != nullptr)
{
// Registered frames reflect the corresponding session state
if (!_sessionState->HasKey(frameSessionKey))
{
_sessionState->Insert(frameSessionKey, ref new Map<String^, Object^>());
}
frameState = safe_cast<IMap<String^, Object^>^>(_sessionState->Lookup(frameSessionKey));
}
else
{
// Frames that aren't registered have transient state
frameState = ref new Map<String^, Object^>();
}
frame->SetValue(FrameSessionStateProperty, frameState);
}
return frameState;
}
void SuspensionManager::RestoreFrameNavigationState(Frame^ frame)
{
auto frameState = SessionStateForFrame(frame);
if (frameState->HasKey("Navigation"))
{
frame->SetNavigationState(safe_cast<String^>(frameState->Lookup("Navigation")));
}
}
void SuspensionManager::SaveFrameNavigationState(Frame^ frame)
{
auto frameState = SessionStateForFrame(frame);
frameState->Insert("Navigation", frame->GetNavigationState());
}
/// <summary>
/// Save the current <see cref="SessionState"/>. Any <see cref="Frame"/> instances
/// registered with <see cref="RegisterFrame"/> will also preserve their current
/// navigation stack, which in turn gives their active <see cref="Page"/> an opportunity
/// to save its state.
/// </summary>
/// <returns>An asynchronous task that reflects when session state has been saved.</returns>
task<void> SuspensionManager::SaveAsync(void)
{
// Save the navigation state for all registered frames
for (auto&& weakFrame : _registeredFrames)
{
auto frame = weakFrame->ResolvedFrame;
if (frame != nullptr) SaveFrameNavigationState(frame);
}
// Serialize the session state synchronously to avoid asynchronous access to shared
// state
auto sessionData = ref new InMemoryRandomAccessStream();
auto sessionDataWriter = ref new DataWriter(sessionData->GetOutputStreamAt(0));
WriteObject(sessionDataWriter, _sessionState);
// Once session state has been captured synchronously, begin the asynchronous process
// of writing the result to disk
return task<unsigned int>(sessionDataWriter->StoreAsync()).then([=](unsigned int)
{
return ApplicationData::Current->LocalFolder->CreateFileAsync(sessionStateFilename,
CreationCollisionOption::ReplaceExisting);
}).then([=](StorageFile^ createdFile)
{
return createdFile->OpenAsync(FileAccessMode::ReadWrite);
}).then([=](IRandomAccessStream^ newStream)
{
return RandomAccessStream::CopyAsync(
sessionData->GetInputStreamAt(0), newStream->GetOutputStreamAt(0));
}).then([=](UINT64 copiedBytes)
{
(void)copiedBytes; // Unused parameter
return;
});
}
/// <summary>
/// Restores previously saved <see cref="SessionState"/>. Any <see cref="Frame"/> instances
/// registered with <see cref="RegisterFrame"/> will also restore their prior navigation
/// state, which in turn gives their active <see cref="Page"/> an opportunity restore its
/// state.
/// </summary>
/// <param name="version">A version identifer compared to the session state to prevent
/// incompatible versions of session state from reaching app code. Saved state with a
/// different version will be ignored, resulting in an empty <see cref="SessionState"/>
/// dictionary.</param>
/// <returns>An asynchronous task that reflects when session state has been read. The
/// content of <see cref="SessionState"/> should not be relied upon until this task
/// completes.</returns>
task<void> SuspensionManager::RestoreAsync(void)
{
_sessionState->Clear();
task<StorageFile^> getFileTask(ApplicationData::Current->LocalFolder->GetFileAsync(sessionStateFilename));
return getFileTask.then([=](StorageFile^ stateFile)
{
task<BasicProperties^> getBasicPropertiesTask(stateFile->GetBasicPropertiesAsync());
return getBasicPropertiesTask.then([=](BasicProperties^ stateFileProperties)
{
auto size = unsigned int(stateFileProperties->Size);
if (size != stateFileProperties->Size) throw ref new FailureException("Session state larger than 4GB");
task<IRandomAccessStreamWithContentType^> openReadTask(stateFile->OpenReadAsync());
return openReadTask.then([=](IRandomAccessStreamWithContentType^ stateFileStream)
{
auto stateReader = ref new DataReader(stateFileStream);
return task<unsigned int>(stateReader->LoadAsync(size)).then([=](unsigned int bytesRead)
{
(void)bytesRead; // Unused parameter
// Deserialize the Session State
Object^ content = ReadObject(stateReader);
_sessionState = (Map<String^, Object^>^)content;
// Restore any registered frames to their saved state
for (auto&& weakFrame : _registeredFrames)
{
auto frame = weakFrame->ResolvedFrame;
if (frame != nullptr)
{
frame->ClearValue(FrameSessionStateProperty);
RestoreFrameNavigationState(frame);
}
}
}, task_continuation_context::use_current());
});
});
});
}
#pragma region Object serialization for a known set of types
namespace
{
// Codes used for identifying serialized types
enum StreamTypes {
NullPtrType = 0,
// Supported IPropertyValue types
UInt8Type, UInt16Type, UInt32Type, UInt64Type, Int16Type, Int32Type, Int64Type,
SingleType, DoubleType, BooleanType, Char16Type, GuidType, StringType,
// Array types
UInt8ArrayType,
// Additional supported types
StringToObjectMapType,
// Marker values used to ensure stream integrity
MapEndMarker
};
void WriteString(DataWriter^ writer, String^ string)
{
writer->WriteByte(StringType);
writer->WriteUInt32(writer->MeasureString(string));
writer->WriteString(string);
}
void WriteByteArray(DataWriter^ writer, Platform::Array<unsigned char>^ data)
{
writer->WriteByte(UInt8ArrayType);
writer->WriteUInt32(data->Length);
writer->WriteBytes(data);
}
void WriteProperty(DataWriter^ writer, IPropertyValue^ propertyValue)
{
switch (propertyValue->Type)
{
case PropertyType::UInt8:
writer->WriteByte(UInt8Type);
writer->WriteByte(propertyValue->GetUInt8());
return;
case PropertyType::UInt8Array:
{
Array<unsigned char>^ data;
propertyValue->GetUInt8Array(&data);
WriteByteArray(writer, data);
}
return;
case PropertyType::UInt16:
writer->WriteByte(UInt16Type);
writer->WriteUInt16(propertyValue->GetUInt16());
return;
case PropertyType::UInt32:
writer->WriteByte(UInt32Type);
writer->WriteUInt32(propertyValue->GetUInt32());
return;
case PropertyType::UInt64:
writer->WriteByte(UInt64Type);
writer->WriteUInt64(propertyValue->GetUInt64());
return;
case PropertyType::Int16:
writer->WriteByte(Int16Type);
writer->WriteUInt16(propertyValue->GetInt16());
return;
case PropertyType::Int32:
writer->WriteByte(Int32Type);
writer->WriteUInt32(propertyValue->GetInt32());
return;
case PropertyType::Int64:
writer->WriteByte(Int64Type);
writer->WriteUInt64(propertyValue->GetInt64());
return;
case PropertyType::Single:
writer->WriteByte(SingleType);
writer->WriteSingle(propertyValue->GetSingle());
return;
case PropertyType::Double:
writer->WriteByte(DoubleType);
writer->WriteDouble(propertyValue->GetDouble());
return;
case PropertyType::Boolean:
writer->WriteByte(BooleanType);
writer->WriteBoolean(propertyValue->GetBoolean());
return;
case PropertyType::Char16:
writer->WriteByte(Char16Type);
writer->WriteUInt16(propertyValue->GetChar16());
return;
case PropertyType::Guid:
writer->WriteByte(GuidType);
writer->WriteGuid(propertyValue->GetGuid());
return;
case PropertyType::String:
WriteString(writer, propertyValue->GetString());
return;
default:
throw ref new InvalidArgumentException("Unsupported property type");
}
}
void WriteStringToObjectMap(DataWriter^ writer, IMap<String^, Object^>^ map)
{
writer->WriteByte(StringToObjectMapType);
writer->WriteUInt32(map->Size);
for (auto&& pair : map)
{
WriteObject(writer, pair->Key);
WriteObject(writer, pair->Value);
}
writer->WriteByte(MapEndMarker);
}
void WriteObject(DataWriter^ writer, Object^ object)
{
if (object == nullptr)
{
writer->WriteByte(NullPtrType);
return;
}
auto propertyObject = dynamic_cast<IPropertyValue^>(object);
if (propertyObject != nullptr)
{
WriteProperty(writer, propertyObject);
return;
}
auto mapObject = dynamic_cast<IMap<String^, Object^>^>(object);
if (mapObject != nullptr)
{
WriteStringToObjectMap(writer, mapObject);
return;
}
throw ref new InvalidArgumentException("Unsupported data type");
}
String^ ReadString(DataReader^ reader)
{
int length = reader->ReadUInt32();
String^ string = reader->ReadString(length);
return string;
}
Object^ ReadByteArray(DataReader^ reader)
{
unsigned int length = reader->ReadUInt32();
Array<unsigned char>^ data = ref new Array<unsigned char>(length);
reader->ReadBytes(data);
return data;
}
IMap<String^, Object^>^ ReadStringToObjectMap(DataReader^ reader)
{
auto map = ref new Map<String^, Object^>();
auto size = reader->ReadUInt32();
for (unsigned int index = 0; index < size; index++)
{
auto key = safe_cast<String^>(ReadObject(reader));
auto value = ReadObject(reader);
map->Insert(key, value);
}
if (reader->ReadByte() != MapEndMarker)
{
throw ref new InvalidArgumentException("Invalid stream");
}
return map;
}
Object^ ReadObject(DataReader^ reader)
{
auto type = reader->ReadByte();
switch (type)
{
case NullPtrType:
return nullptr;
case UInt8Type:
return reader->ReadByte();
case UInt8ArrayType:
return ReadByteArray(reader);
case UInt16Type:
return reader->ReadUInt16();
case UInt32Type:
return reader->ReadUInt32();
case UInt64Type:
return reader->ReadUInt64();
case Int16Type:
return reader->ReadInt16();
case Int32Type:
return reader->ReadInt32();
case Int64Type:
return reader->ReadInt64();
case SingleType:
return reader->ReadSingle();
case DoubleType:
return reader->ReadDouble();
case BooleanType:
return reader->ReadBoolean();
case Char16Type:
return static_cast<wchar_t>(reader->ReadUInt16());
case GuidType:
return reader->ReadGuid();
case StringType:
return ReadString(reader);
case StringToObjectMapType:
return ReadStringToObjectMap(reader);
default:
throw ref new InvalidArgumentException("Unsupported property type");
}
}
}
#pragma endregion

View File

@ -1,43 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// SuspensionManager.h
// Declaration of the SuspensionManager class
//
#pragma once
#include <ppltasks.h>
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// SuspensionManager captures global session state to simplify process lifetime management
/// for an application. Note that session state will be automatically cleared under a variety
/// of conditions and should only be used to store information that would be convenient to
/// carry across sessions, but that should be disacarded when an application crashes or is
/// upgraded.
/// </summary>
ref class SuspensionManager sealed
{
internal:
static void RegisterFrame(Windows::UI::Xaml::Controls::Frame^ frame, Platform::String^ sessionStateKey);
static void UnregisterFrame(Windows::UI::Xaml::Controls::Frame^ frame);
static Concurrency::task<void> SaveAsync(void);
static Concurrency::task<void> RestoreAsync(void);
static property Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ SessionState
{
Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ get(void);
};
static Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ SessionStateForFrame(
Windows::UI::Xaml::Controls::Frame^ frame);
private:
static void RestoreFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame);
static void SaveFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame);
};
}
}

View File

@ -1,53 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="CaptionFontSize">12</x:Double>
<x:Double x:Key="BodyFontSize">15</x:Double>
<x:Double x:Key="BaseFontSize">15</x:Double>
<x:Double x:Key="SubtitleFontSize">20</x:Double>
<x:Double x:Key="TitleFontSize">24</x:Double>
<x:Double x:Key="SubheaderFontSize">34</x:Double>
<x:Double x:Key="HeaderFontSize">46</x:Double>
<Style x:Key="CaptionTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource CaptionFontSize}" />
<Setter Property="LineHeight" Value="14" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style x:Key="BodyTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource BodyFontSize}" />
<Setter Property="LineHeight" Value="20" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}">
<Setter Property="FontWeight" Value="SemiBold" />
</Style>
<Style x:Key="SubtitleTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SubtitleFontSize}" />
<Setter Property="LineHeight" Value="24" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style x:Key="TitleTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource TitleFontSize}" />
<Setter Property="LineHeight" Value="28" />
<Setter Property="FontWeight" Value="SemiLight" />
</Style>
<Style x:Key="SubheaderTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SubheaderFontSize}" />
<Setter Property="LineHeight" Value="40" />
<Setter Property="FontWeight" Value="Light" />
</Style>
<Style x:Key="HeaderTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource HeaderFontSize}" />
<Setter Property="LineHeight" Value="56" />
<Setter Property="FontWeight" Value="Light" />
</Style>
</ResourceDictionary>

View File

@ -1,4 +1,4 @@
<common:LayoutAwarePage x:Class="CalculatorApp.MainPage"
<Page x:Class="CalculatorApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:automation="using:CalculatorApp.Common.Automation"
@ -160,4 +160,4 @@
</Grid>
</muxc:NavigationView>
</Grid>
</common:LayoutAwarePage>
</Page>

View File

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@ -85,60 +85,17 @@ MainPage::MainPage() :
}
}
/// <summary>
/// Populates the page with content passed during navigation. Any saved state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame::Navigate(Type, Object)"/> when this page was initially requested.
/// </param>
/// <param name="pageState">A map of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited.</param>
void MainPage::LoadState(_In_ Object^ navigationParameter, _In_ IMap<String^, Object^>^ pageState)
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
if (pageState != nullptr)
{
if (pageState->HasKey("ConverterViewModelState"))
{
auto converterViewModelState = safe_cast<String^>(pageState->Lookup("ConverterViewModelState"));
m_model->ConverterViewModel->Deserialize(converterViewModelState);
}
//Moving these below the converter view model deserialize, since the converter modes are also displayed in the MainPage NavBar and thus need to be deserialized before setting the current mode
if (pageState->HasKey(ApplicationViewModelProperties::Mode))
{
m_model->Mode = NavCategory::Deserialize(pageState->Lookup(ApplicationViewModelProperties::Mode));
}
if (pageState->HasKey(ApplicationViewModelProperties::PreviousMode))
{
m_model->PreviousMode = NavCategory::Deserialize(pageState->Lookup(ApplicationViewModelProperties::PreviousMode));
}
// rehydrate
if (pageState->HasKey("CalculatorViewModelState"))
{
auto calculatorViewModelState = safe_cast<Array<unsigned char>^>(pageState->Lookup("CalculatorViewModelState"));
m_model->CalculatorViewModel->Deserialize(calculatorViewModelState);
}
m_model->CalculatorViewModel->HistoryVM->RestoreCompleteHistory();
m_model->CalculatorViewModel->HistoryVM->ReloadHistory(m_model->Mode);
}
else
{
// initialize
if (m_model->CalculatorViewModel)
{
m_model->CalculatorViewModel->HistoryVM->ClearHistory();
}
ViewMode initialMode = ViewMode::Standard;
if (navigationParameter != nullptr)
if (e->Parameter != nullptr)
{
String^ stringParameter = dynamic_cast<String^>(navigationParameter);
String^ stringParameter = dynamic_cast<String^>(e->Parameter);
if (stringParameter != nullptr)
{
initialMode = (ViewMode)stoi(stringParameter->Data());
@ -155,36 +112,6 @@ void MainPage::LoadState(_In_ Object^ navigationParameter, _In_ IMap<String^, Ob
m_model->Initialize(initialMode);
}
}
/// <summary>
/// Preserves state associated with this page in case the application is suspended or the
/// page is discarded from the navigation cache. Values must conform to the serialization
/// requirements of <see cref="SuspensionManager::SessionState"/>.
/// </summary>
/// <param name="pageState">An empty map to be populated with serializable state.</param>
void MainPage::SaveState(_In_ IMap<String^, Object^>^ pageState)
{
int serializedCurrentMode = NavCategory::Serialize(m_model->Mode);
pageState->Insert(ApplicationViewModelProperties::Mode, serializedCurrentMode);
pageState->Insert(ApplicationViewModelProperties::PreviousMode, NavCategory::Serialize(m_model->PreviousMode));
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
localSettings->Values->Insert(ApplicationViewModelProperties::Mode, serializedCurrentMode);
auto serializedCalculatorData = m_model->CalculatorViewModel->Serialize();
auto serializedConverterData = m_model->ConverterViewModel->Serialize();
if (serializedCalculatorData->Length > 0)
{
pageState->Insert("CalculatorViewModelState", serializedCalculatorData);
}
if (serializedConverterData != nullptr)
{
pageState->Insert("ConverterViewModelState", serializedConverterData);
}
}
void MainPage::WindowSizeChanged(_In_ Platform::Object^ /*sender*/, _In_ Windows::UI::Core::WindowSizeChangedEventArgs^ e)
{

View File

@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Common\LayoutAwarePage.h" // Required by generated header
#include "Views\Calculator.xaml.h"
#include "Views\MainPage.g.h"
#include "Views\DateCalculator.xaml.h"
@ -40,9 +39,7 @@ namespace CalculatorApp
Windows::Foundation::Collections::IObservableVector<Platform::Object^>^ CreateUIElementsForCategories(_In_ Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ categories);
protected:
virtual void LoadState(_In_ Platform::Object^ navigationParameter,
_In_ Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ pageState) override;
virtual void SaveState(_In_ Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ pageState) override;
void OnNavigatedTo(_In_ Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
private:
void WindowSizeChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Core::WindowSizeChangedEventArgs^ e);

View File

@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "WindowFrameService.h"
#include "Common\SuspensionManager.h"
#include "CalcViewModel\Common\KeyboardShortcutManager.h"
using namespace concurrency;

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -2,7 +2,7 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{d3baed2c-4b07-4e1d-8807-9d6499450349}</ProjectGuid>
<RootNamespace>CalculatorUnitTests_VS</RootNamespace>
<RootNamespace>CalculatorUnitTests</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
@ -129,7 +129,7 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<PackageCertificateKeyFile>CalculatorUnitTests_VS_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateKeyFile>CalculatorUnitTests_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>3F0C32266A4D995CC08C9AEC3960CFF3EF0D1853</PackageCertificateThumbprint>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
@ -259,7 +259,7 @@
<Xml Include="UnitTestApp.rd.xml" />
</ItemGroup>
<ItemGroup>
<None Include="CalculatorUnitTests_VS_TemporaryKey.pfx" />
<None Include="CalculatorUnitTests_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="..\Calculator\Resources\en-US\CEngineStrings.resw" />
@ -269,7 +269,7 @@
</PRIResource>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CalculatorUnitTests_VS.rc" />
<ResourceCompile Include="CalculatorUnitTests.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">

View File

@ -17,7 +17,6 @@
<ClCompile Include="CurrencyConverterUnitTests.cpp" />
<ClCompile Include="DateCalculatorUnitTests.cpp" />
<ClCompile Include="HistoryTests.cpp" />
<ClCompile Include="Mocks\CurrencyHttpClient.cpp" />
<ClCompile Include="Module.cpp" />
<ClCompile Include="MultiWindowUnitTests.cpp" />
<ClCompile Include="NavCategoryUnitTests.cpp" />
@ -27,36 +26,63 @@
<ClCompile Include="UnitTestApp.xaml.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="UtilsTests.cpp" />
<ClCompile Include="Mocks\CurrencyHttpClient.cpp">
<Filter>Mocks</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AsyncHelper.h" />
<ClInclude Include="DateUtils.h" />
<ClInclude Include="Helpers.h" />
<ClInclude Include="Mocks\CurrencyHttpClient.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="UnitConverterViewModelUnitTests.h" />
<ClInclude Include="UnitTestApp.xaml.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Mocks\CurrencyHttpClient.h">
<Filter>Mocks</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CalculatorUnitTests_VS.rc" />
<ResourceCompile Include="CalculatorUnitTests.rc" />
</ItemGroup>
<ItemGroup>
<Xml Include="UnitTestApp.rd.xml" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\Square44x44Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
<Image Include="Assets\StoreLogo.png" />
<Image Include="Assets\Wide310x150Logo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Wide310x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LockScreenLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<None Include="CalculatorUnitTests_VS_TemporaryKey.pfx" />
<None Include="CalculatorUnitTests_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Filter Include="Assets">
<UniqueIdentifier>{f2987b0a-9832-46fc-b818-d5347362b3d8}</UniqueIdentifier>
</Filter>
<Filter Include="Mocks">
<UniqueIdentifier>{d3ec8922-022d-4531-8744-f65a872f3841}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -3,7 +3,7 @@
<Identity Name="0f7457a6-1a6a-4607-b3b8-e3dd274567c8" Publisher="CN=CalculatorUnitTests" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="0f7457a6-1a6a-4607-b3b8-e3dd274567c8" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>CalculatorUnitTests_VS</DisplayName>
<DisplayName>CalculatorUnitTests</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
@ -14,8 +14,8 @@
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="vstest.executionengine.universal.App" Executable="$targetnametoken$.exe" EntryPoint="CalculatorUnitTests_VS.App">
<uap:VisualElements DisplayName="CalculatorUnitTests_VS" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="CalculatorUnitTests_VS" BackgroundColor="transparent">
<Application Id="vstest.executionengine.universal.App" Executable="$targetnametoken$.exe" EntryPoint="CalculatorUnitTests.App">
<uap:VisualElements DisplayName="CalculatorUnitTests" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="CalculatorUnitTests" BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />

Some files were not shown because too many files have changed in this diff Show More