diff --git a/.gitattributes b/.gitattributes
index 51617f5f..e0d31f91 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -12,29 +12,6 @@
###############################################################################
*.cs diff=csharp
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-*.sln merge=binary
-*.csproj merge=binary
-*.vbproj merge=binary
-*.vcxproj merge=binary
-*.vcproj merge=binary
-*.dbproj merge=binary
-*.fsproj merge=binary
-*.lsproj merge=binary
-*.wixproj merge=binary
-*.modelproj merge=binary
-*.sqlproj merge=binary
-*.wwaproj merge=binary
-
###############################################################################
# behavior for image files
#
diff --git a/.gitignore b/.gitignore
index 2100dfc1..1088272d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -289,6 +289,7 @@ __pycache__/
# Calculator specific
Generated Files/
+src/GraphControl/GraphingImplOverrides.props
!/build/config/TRexDefs/**
!src/Calculator/TemporaryKey.pfx
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx
\ No newline at end of file
diff --git a/README.md b/README.md
index d967b175..00243142 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,9 @@ Calculator ships regularly with new features and bug fixes. You can get the late
- Calculation history and memory capabilities.
- Conversion between many units of measurement.
- Currency conversion based on data retrieved from [Bing](https://www.bing.com).
+- [Infinite precision](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) for basic
+ arithmetic operations (addition, subtraction, multiplication, division) so that calculations
+ never lose precision.
## Getting started
Prerequisites:
diff --git a/build/config/SignConfig.xml b/build/config/SignConfig.xml
index 7209725e..eb298e87 100644
--- a/build/config/SignConfig.xml
+++ b/build/config/SignConfig.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/build/pipelines/azure-pipelines.ci.yaml b/build/pipelines/azure-pipelines.ci.yaml
index 31ce98fb..23eb46ca 100644
--- a/build/pipelines/azure-pipelines.ci.yaml
+++ b/build/pipelines/azure-pipelines.ci.yaml
@@ -33,6 +33,10 @@ jobs:
platform: ARM64
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
+- template: ./templates/run-ui-tests.yaml
+ parameters:
+ platform: x64
+
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x64
diff --git a/build/pipelines/templates/build-single-architecture.yaml b/build/pipelines/templates/build-single-architecture.yaml
index 92e06f7b..50859db3 100644
--- a/build/pipelines/templates/build-single-architecture.yaml
+++ b/build/pipelines/templates/build-single-architecture.yaml
@@ -30,7 +30,7 @@ steps:
inputs:
solution: src/Calculator.sln
vsVersion: 15.0
- msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) ${{ parameters.extraMsBuildArgs }}
+ msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: true
diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml
index 363ca049..178fd268 100644
--- a/build/pipelines/templates/prepare-release-internalonly.yaml
+++ b/build/pipelines/templates/prepare-release-internalonly.yaml
@@ -1,5 +1,5 @@
# This template contains a job which builds artifacts needed to release the app to the store and to
-# Windows using Microsoft-internal systems. It relies Microsoft-internal resources and will not
+# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
# work outside of Microsoft.
# Specifically, this job:
# - Signs the bundle using a secure system. If you want to build your own, use SignTool following
@@ -28,8 +28,8 @@ jobs:
- task: PkgESSetupBuild@10
displayName: Initialize Package ES
inputs:
- productName: Calculator
- disableWorkspace: true
+ productName: Calculator
+ disableWorkspace: true
env:
XES_DISABLEPROV: true
@@ -46,6 +46,8 @@ jobs:
- task: PkgESCodeSign@10
displayName: Send bundle to Package ES code signing service
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
signConfigXml: build\config\SignConfig.xml
inPathRoot: $(Build.ArtifactStagingDirectory)\appxBundle
@@ -60,25 +62,25 @@ jobs:
- task: CopyFiles@2
displayName: Copy signed AppxBundle to vpack staging folder
inputs:
- sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
- targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
+ sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
+ targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
- task: PkgESVPack@10
displayName: Create and push vpack for app
env:
- SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
- sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
- description: VPack for the Calculator Application
- pushPkgName: calculator.app
- version: $(versionMajor).$(versionMinor).$(versionBuild)
- owner: paxeeapps
+ sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
+ description: VPack for the Calculator Application
+ pushPkgName: calculator.app
+ version: $(versionMajor).$(versionMinor).$(versionBuild)
+ owner: paxeeapps
- task: PublishBuildArtifacts@1
displayName: Publish vpack\app artifact with vpack manifest
inputs:
- pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
- artifactName: vpack\app
+ pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
+ artifactName: vpack\app
# TODO (macool): create and push internal test packages and test config
diff --git a/build/pipelines/templates/run-ui-tests.yaml b/build/pipelines/templates/run-ui-tests.yaml
new file mode 100644
index 00000000..41d441ad
--- /dev/null
+++ b/build/pipelines/templates/run-ui-tests.yaml
@@ -0,0 +1,52 @@
+# This template contains jobs to run UI tests using WinAppDriver.
+
+parameters:
+ platform: ''
+
+jobs:
+- job: UITests${{ parameters.platform }}
+ displayName: UITests ${{ parameters.platform }}
+ dependsOn: Build${{ parameters.platform }}
+ condition: succeeded()
+ pool:
+ vmImage: windows-2019
+ variables:
+ skipComponentGovernanceDetection: true
+ steps:
+ - checkout: none
+
+ - powershell: Set-DisplayResolution -Width 1920 -Height 1080 -Force
+ displayName: Set resolution to 1920x1080
+ continueOnError: true
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download AppxBundle and CalculatorUITests
+ inputs:
+ artifactName: drop
+ itemPattern: |
+ drop/Release/${{ parameters.platform }}/Calculator/AppPackages/**
+ drop/Release/${{ parameters.platform }}/publish/**
+
+ - task: PowerShell@2
+ displayName: Install certificate
+ inputs:
+ filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
+ arguments: -CertificatePath $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Calculator_$(Build.BuildNumber)_${{ parameters.platform }}.cer -Force
+
+ - task: PowerShell@2
+ displayName: Install app
+ inputs:
+ filePath: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/Calculator/AppPackages/Calculator_$(Build.BuildNumber)_Test/Add-AppDevPackage.ps1
+ arguments: -Force
+
+ - powershell: Start-Process -FilePath "C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe" -Verb RunAs
+ displayName: Start WinAppDriver
+
+ - task: VSTest@2
+ displayName: Run CalculatorUITests
+ inputs:
+ testAssemblyVer2: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.dll
+ vsTestVersion: 16.0
+ runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.runsettings
+ platform: ${{ parameters.platform }}
+ configuration: Release
\ No newline at end of file
diff --git a/docs/ApplicationArchitecture.md b/docs/ApplicationArchitecture.md
index 0d7c2ff3..dff02965 100644
--- a/docs/ApplicationArchitecture.md
+++ b/docs/ApplicationArchitecture.md
@@ -153,7 +153,9 @@ The CalcEngine contains the logic for interpreting and performing operations acc
### RatPack
-The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for performing its mathematical operations. The interface to this layer is defined in [ratpak.h][ratpak.h].
+The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for
+performing its mathematical operations (using [infinite precision][Infinite Precision] arithmetic
+instead of regular floating point arithmetic). The interface to this layer is defined in [ratpak.h][ratpak.h].
[References]:####################################################################################################
diff --git a/src/CalcManager/CEngine/CalcInput.cpp b/src/CalcManager/CEngine/CalcInput.cpp
index 45e553b9..1c47a8da 100644
--- a/src/CalcManager/CEngine/CalcInput.cpp
+++ b/src/CalcManager/CEngine/CalcInput.cpp
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include
#include "Header Files/CalcEngine.h"
using namespace std;
diff --git a/src/CalcManager/CEngine/CalcUtils.cpp b/src/CalcManager/CEngine/CalcUtils.cpp
index 7980e4e0..15b11926 100644
--- a/src/CalcManager/CEngine/CalcUtils.cpp
+++ b/src/CalcManager/CEngine/CalcUtils.cpp
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp
index ca276a41..74edf3cc 100644
--- a/src/CalcManager/CEngine/History.cpp
+++ b/src/CalcManager/CEngine/History.cpp
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
#include "Header Files/CalcEngine.h"
#include "Command.h"
#include "CalculatorVector.h"
diff --git a/src/CalcManager/CEngine/Number.cpp b/src/CalcManager/CEngine/Number.cpp
index 4bf83a33..fdf29e09 100644
--- a/src/CalcManager/CEngine/Number.cpp
+++ b/src/CalcManager/CEngine/Number.cpp
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
-#include "pch.h"
+#include
#include "Header Files/Number.h"
using namespace std;
diff --git a/src/CalcManager/CEngine/Rational.cpp b/src/CalcManager/CEngine/Rational.cpp
index fd86b72a..e116c237 100644
--- a/src/CalcManager/CEngine/Rational.cpp
+++ b/src/CalcManager/CEngine/Rational.cpp
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
-#include "pch.h"
+#include
#include "Header Files/Rational.h"
using namespace std;
@@ -182,6 +182,13 @@ namespace CalcEngine
return *this;
}
+ ///
+ /// Calculate the remainder after division, the sign of a result will match the sign of the current object.
+ ///
+ ///
+ /// This function has the same behavior as the standard C/C++ operator '%'
+ /// to calculate the modulus after division instead, use instead.
+ ///
Rational& Rational::operator%=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
@@ -189,7 +196,7 @@ namespace CalcEngine
try
{
- modrat(&lhsRat, rhsRat);
+ remrat(&lhsRat, rhsRat);
destroyrat(rhsRat);
}
catch (uint32_t error)
@@ -342,6 +349,12 @@ namespace CalcEngine
return lhs;
}
+ ///
+ /// Calculate the remainder after division, the sign of a result will match the sign of lhs.
+ ///
+ ///
+ /// This function has the same behavior as the standard C/C++ operator '%', to calculate the modulus after division instead, use instead.
+ ///
Rational operator%(Rational lhs, Rational const& rhs)
{
lhs %= rhs;
diff --git a/src/CalcManager/CEngine/RationalMath.cpp b/src/CalcManager/CEngine/RationalMath.cpp
index 37dc7926..4b1a4b8a 100644
--- a/src/CalcManager/CEngine/RationalMath.cpp
+++ b/src/CalcManager/CEngine/RationalMath.cpp
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
#include "Header Files/RationalMath.h"
using namespace std;
@@ -387,3 +386,33 @@ Rational RationalMath::ATanh(Rational const& rat)
return result;
}
+
+///
+/// Calculate the modulus after division, the sign of the result will match the sign of b.
+///
+///
+/// When one of the operand is negative
+/// the result will differ from the C/C++ operator '%'
+/// use instead to calculate the remainder after division.
+///
+Rational RationalMath::Mod(Rational const& a, Rational const& b)
+{
+ PRAT prat = a.ToPRAT();
+ PRAT pn = b.ToPRAT();
+
+ try
+ {
+ modrat(&prat, pn);
+ destroyrat(pn);
+ }
+ catch (uint32_t error)
+ {
+ destroyrat(prat);
+ destroyrat(pn);
+ throw(error);
+ }
+
+ auto res = Rational{ prat };
+ destroyrat(prat);
+ return res;
+}
diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp
index 0e4979f2..65e6f0d0 100644
--- a/src/CalcManager/CEngine/calc.cpp
+++ b/src/CalcManager/CEngine/calc.cpp
@@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include
#include "Header Files/CalcEngine.h"
-
#include "CalculatorResource.h"
using namespace std;
diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp
index d450a70d..36130bb5 100644
--- a/src/CalcManager/CEngine/scicomm.cpp
+++ b/src/CalcManager/CEngine/scicomm.cpp
@@ -12,7 +12,8 @@
*
* Author:
\****************************************************************************/
-#include "pch.h"
+
+#include
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
@@ -390,7 +391,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
cleared for CENTR */
if (nullptr != m_pCalcDisplay)
{
- m_pCalcDisplay->SetParenDisplayText(L"");
+ m_pCalcDisplay->SetParenthesisNumber(0);
m_pCalcDisplay->SetExpressionDisplay(make_shared>>(), make_shared>>());
}
@@ -594,7 +595,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
// Set the "(=xx" indicator.
if (nullptr != m_pCalcDisplay)
{
- m_pCalcDisplay->SetParenDisplayText(m_openParenCount ? to_wstring(m_openParenCount) : L"");
+ m_pCalcDisplay->SetParenthesisNumber(m_openParenCount >= 0 ? static_cast(m_openParenCount) : 0);
}
if (!m_bError)
diff --git a/src/CalcManager/CEngine/scidisp.cpp b/src/CalcManager/CEngine/scidisp.cpp
index 849fe863..1ef88799 100644
--- a/src/CalcManager/CEngine/scidisp.cpp
+++ b/src/CalcManager/CEngine/scidisp.cpp
@@ -12,7 +12,9 @@
*
* Author:
\****************************************************************************/
-#include "pch.h"
+
+#include
+#include
#include "Header Files/CalcEngine.h"
using namespace std;
diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp
index a1007c1c..c2341752 100644
--- a/src/CalcManager/CEngine/scifunc.cpp
+++ b/src/CalcManager/CEngine/scifunc.cpp
@@ -16,7 +16,6 @@
/*** ***/
/*** ***/
/**************************************************************************/
-#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace std;
diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp
index b09083c4..f8d04855 100644
--- a/src/CalcManager/CEngine/scioper.cpp
+++ b/src/CalcManager/CEngine/scioper.cpp
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
@@ -78,7 +77,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
case IDC_DIV:
case IDC_MOD:
{
- int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1;
+ int iNumeratorSign = 1, iDenominatorSign = 1;
auto temp = result;
result = rhs;
@@ -107,20 +106,30 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
if (operation == IDC_DIV)
{
- iFinalSign = iNumeratorSign * iDenominatorSign;
result /= temp;
+ if (m_fIntegerMode && (iNumeratorSign * iDenominatorSign) == -1)
+ {
+ result = -(Integer(result));
+ }
}
else
{
- iFinalSign = iNumeratorSign;
- result %= temp;
- }
+ if (m_fIntegerMode)
+ {
+ // Programmer mode, use remrat (remainder after division)
+ result %= temp;
- if (m_fIntegerMode && iFinalSign == -1)
- {
- result = -(Integer(result));
+ if (iNumeratorSign == -1)
+ {
+ result = -(Integer(result));
+ }
+ }
+ else
+ {
+ //other modes, use modrat (modulus after division)
+ result = Mod(result, temp);
+ }
}
-
break;
}
diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp
index 5495748e..ca715be5 100644
--- a/src/CalcManager/CEngine/sciset.cpp
+++ b/src/CalcManager/CEngine/sciset.cpp
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj
index 4a098141..4d03a5c9 100644
--- a/src/CalcManager/CalcManager.vcxproj
+++ b/src/CalcManager/CalcManager.vcxproj
@@ -157,6 +157,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -173,6 +174,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -189,6 +191,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -205,6 +208,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -222,6 +226,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -238,6 +243,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -254,6 +260,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -270,6 +277,7 @@
$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)
Level4
true
+ pch.h
Console
@@ -278,7 +286,6 @@
-
diff --git a/src/CalcManager/CalculatorHistory.cpp b/src/CalcManager/CalculatorHistory.cpp
index 31a1dae2..935ea8da 100644
--- a/src/CalcManager/CalculatorHistory.cpp
+++ b/src/CalcManager/CalculatorHistory.cpp
@@ -1,7 +1,7 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include
#include "CalculatorHistory.h"
using namespace std;
diff --git a/src/CalcManager/CalculatorHistory.h b/src/CalcManager/CalculatorHistory.h
index 8116e9e4..ea87f857 100644
--- a/src/CalcManager/CalculatorHistory.h
+++ b/src/CalcManager/CalculatorHistory.h
@@ -38,7 +38,7 @@ namespace CalculationManager
void ClearHistory();
unsigned int AddItem(_In_ std::shared_ptr const &spHistoryItem);
bool RemoveItem(unsigned int uIdx);
- const size_t MaxHistorySize() const { return m_maxHistorySize; }
+ size_t MaxHistorySize() const { return m_maxHistorySize; }
~CalculatorHistory(void);
private:
diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp
index b4b4dfaf..e640bd94 100644
--- a/src/CalcManager/CalculatorManager.cpp
+++ b/src/CalcManager/CalculatorManager.cpp
@@ -1,7 +1,7 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include // for UCHAR_MAX
#include "Header Files/CalcEngine.h"
#include "CalculatorManager.h"
#include "CalculatorResource.h"
@@ -111,9 +111,9 @@ namespace CalculationManager
/// Callback from the engine
///
/// string containing the parenthesis count
- void CalculatorManager::SetParenDisplayText(const wstring& parenthesisCount)
+ void CalculatorManager::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
- m_displayCallback->SetParenDisplayText(parenthesisCount);
+ m_displayCallback->SetParenthesisNumber(parenthesisCount);
}
///
diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h
index 0b9986b0..e00dc243 100644
--- a/src/CalcManager/CalculatorManager.h
+++ b/src/CalcManager/CalculatorManager.h
@@ -94,7 +94,7 @@ namespace CalculationManager
void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) override;
void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override;
void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override;
- void SetParenDisplayText(const std::wstring& parenthesisCount) override;
+ void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override;
void OnNoRightParenAdded() override;
void DisplayPasteError();
void MaxDigitsReached() override;
diff --git a/src/CalcManager/CalculatorVector.h b/src/CalcManager/CalculatorVector.h
index a4de434d..e9f1b8dc 100644
--- a/src/CalcManager/CalculatorVector.h
+++ b/src/CalcManager/CalculatorVector.h
@@ -1,9 +1,14 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
+#include
+#include
+#include
#include "Ratpack/CalcErr.h"
+#include // for std::out_of_range
+#include // for SAL
template
class CalculatorVector
diff --git a/src/CalcManager/Command.h b/src/CalcManager/Command.h
index e6eeb8ac..4d98d012 100644
--- a/src/CalcManager/Command.h
+++ b/src/CalcManager/Command.h
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
diff --git a/src/CalcManager/ExpressionCommand.cpp b/src/CalcManager/ExpressionCommand.cpp
index 0b68a374..9fc87708 100644
--- a/src/CalcManager/ExpressionCommand.cpp
+++ b/src/CalcManager/ExpressionCommand.cpp
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include
#include "Header Files/CCommand.h"
#include "CalculatorVector.h"
#include "ExpressionCommand.h"
diff --git a/src/CalcManager/ExpressionCommandInterface.h b/src/CalcManager/ExpressionCommandInterface.h
index ce89dd81..94bae836 100644
--- a/src/CalcManager/ExpressionCommandInterface.h
+++ b/src/CalcManager/ExpressionCommandInterface.h
@@ -1,7 +1,9 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
+
+#include // for std::shared_ptr
#include "CalculatorVector.h"
#include "Command.h"
diff --git a/src/CalcManager/Header Files/CCommand.h b/src/CalcManager/Header Files/CCommand.h
index 2fc08b3c..9530b5c5 100644
--- a/src/CalcManager/Header Files/CCommand.h
+++ b/src/CalcManager/Header Files/CCommand.h
@@ -13,6 +13,8 @@
*
\****************************************************************************/
+#pragma once
+
// The following are the valid id's which can be passed to CCalcEngine::ProcessCommand
#define IDM_HEX 313
diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h
index db906e51..c84f2d55 100644
--- a/src/CalcManager/Header Files/CalcEngine.h
+++ b/src/CalcManager/Header Files/CalcEngine.h
@@ -45,7 +45,7 @@ namespace CalculationManager
class IResourceProvider;
}
-namespace CalculatorUnitTests
+namespace CalculatorEngineTests
{
class CalcEngineTests;
}
@@ -160,5 +160,5 @@ private:
static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision);
void BaseOrPrecisionChanged();
- friend class CalculatorUnitTests::CalcEngineTests;
+ friend class CalculatorEngineTests::CalcEngineTests;
};
diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/Header Files/EngineStrings.h
index 37f11483..89d624bf 100644
--- a/src/CalcManager/Header Files/EngineStrings.h
+++ b/src/CalcManager/Header Files/EngineStrings.h
@@ -13,6 +13,11 @@
* Created: 13-Feb-2008
*
\****************************************************************************/
+
+#pragma once
+
+#include
+
inline constexpr auto IDS_ERRORS_FIRST = 99;
// This is the list of error strings corresponding to SCERR_DIVIDEZERO..
diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/Header Files/History.h
index 4f82088f..7446616d 100644
--- a/src/CalcManager/Header Files/History.h
+++ b/src/CalcManager/Header Files/History.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include "ICalcDisplay.h"
#include "IHistoryDisplay.h"
#include "Rational.h"
diff --git a/src/CalcManager/Header Files/ICalcDisplay.h b/src/CalcManager/Header Files/ICalcDisplay.h
index 2ba57e65..73fce932 100644
--- a/src/CalcManager/Header Files/ICalcDisplay.h
+++ b/src/CalcManager/Header Files/ICalcDisplay.h
@@ -12,7 +12,7 @@ public:
virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) = 0;
virtual void SetIsInError(bool isInError) = 0;
virtual void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) = 0;
- virtual void SetParenDisplayText(const std::wstring& pszText) = 0;
+ virtual void SetParenthesisNumber(_In_ unsigned int count) = 0;
virtual void OnNoRightParenAdded() = 0;
virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer.
virtual void BinaryOperatorReceived() = 0;
diff --git a/src/CalcManager/Header Files/Number.h b/src/CalcManager/Header Files/Number.h
index c67aa108..769e3acf 100644
--- a/src/CalcManager/Header Files/Number.h
+++ b/src/CalcManager/Header Files/Number.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include "Ratpack/ratpak.h"
namespace CalcEngine
diff --git a/src/CalcManager/Header Files/RationalMath.h b/src/CalcManager/Header Files/RationalMath.h
index b52c1c5f..59500573 100644
--- a/src/CalcManager/Header Files/RationalMath.h
+++ b/src/CalcManager/Header Files/RationalMath.h
@@ -13,6 +13,7 @@ namespace CalcEngine::RationalMath
Rational Pow(Rational const& base, Rational const& pow);
Rational Root(Rational const& base, Rational const& root);
Rational Fact(Rational const& rat);
+ Rational Mod(Rational const& a, Rational const& b);
Rational Exp(Rational const& rat);
Rational Log(Rational const& rat);
diff --git a/src/CalcManager/Ratpack/basex.cpp b/src/CalcManager/Ratpack/basex.cpp
index 97a29dd4..2685af87 100644
--- a/src/CalcManager/Ratpack/basex.cpp
+++ b/src/CalcManager/Ratpack/basex.cpp
@@ -14,8 +14,8 @@
// internal base is a power of 2.
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
+#include // for memmove
void _mulnumx( PNUMBER *pa, PNUMBER b );
diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp
index c25d4481..3a1aaa14 100644
--- a/src/CalcManager/Ratpack/conv.cpp
+++ b/src/CalcManager/Ratpack/conv.cpp
@@ -17,7 +17,10 @@
//
//---------------------------------------------------------------------------
-#include "pch.h"
+#include
+#include
+#include
+#include // for memmove, memcpy
#include "ratpak.h"
using namespace std;
diff --git a/src/CalcManager/Ratpack/exp.cpp b/src/CalcManager/Ratpack/exp.cpp
index c8691cfa..e4939db4 100644
--- a/src/CalcManager/Ratpack/exp.cpp
+++ b/src/CalcManager/Ratpack/exp.cpp
@@ -14,7 +14,6 @@
//
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
@@ -408,7 +407,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
//---------------------------------------------------------------------------
void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
{
- int32_t sign = ((*px)->pp->sign * (*px)->pq->sign);
+ int32_t sign = SIGN(*px);
// Take the absolute value
(*px)->pp->sign = 1;
diff --git a/src/CalcManager/Ratpack/fact.cpp b/src/CalcManager/Ratpack/fact.cpp
index c974b005..bdcbccb0 100644
--- a/src/CalcManager/Ratpack/fact.cpp
+++ b/src/CalcManager/Ratpack/fact.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
@@ -13,7 +13,6 @@
// Contains fact(orial) and supporting _gamma functions.
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
@@ -216,7 +215,7 @@ void factrat( PRAT *px, uint32_t radix, int32_t precision)
// Check for negative integers and throw an error.
if ( ( zerrat(frac) || ( LOGRATRADIX(frac) <= -precision) ) &&
- ( (*px)->pp->sign * (*px)->pq->sign == -1 ) )
+ ( SIGN(*px) == -1 ) )
{
throw CALC_E_DOMAIN;
}
diff --git a/src/CalcManager/Ratpack/itrans.cpp b/src/CalcManager/Ratpack/itrans.cpp
index 1ecbf4a1..1521308d 100644
--- a/src/CalcManager/Ratpack/itrans.cpp
+++ b/src/CalcManager/Ratpack/itrans.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//-----------------------------------------------------------------------------
@@ -15,7 +15,6 @@
// Special Information
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
@@ -92,11 +91,9 @@ void asinanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32
void asinrat( PRAT *px, uint32_t radix, int32_t precision)
{
- int32_t sgn;
PRAT pret= nullptr;
PRAT phack= nullptr;
-
- sgn = (*px)->pp->sign* (*px)->pq->sign;
+ int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
@@ -204,9 +201,7 @@ void _acosrat( PRAT *px, int32_t precision)
void acosrat( PRAT *px, uint32_t radix, int32_t precision)
{
- int32_t sgn;
-
- sgn = (*px)->pp->sign*(*px)->pq->sign;
+ int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
@@ -291,10 +286,8 @@ void _atanrat( PRAT *px, int32_t precision)
void atanrat( PRAT *px, uint32_t radix, int32_t precision)
{
- int32_t sgn;
PRAT tmpx= nullptr;
-
- sgn = (*px)->pp->sign * (*px)->pq->sign;
+ int32_t sgn = SIGN(*px);
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
diff --git a/src/CalcManager/Ratpack/itransh.cpp b/src/CalcManager/Ratpack/itransh.cpp
index d6734a1f..50941287 100644
--- a/src/CalcManager/Ratpack/itransh.cpp
+++ b/src/CalcManager/Ratpack/itransh.cpp
@@ -16,7 +16,6 @@
//
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
diff --git a/src/CalcManager/Ratpack/logic.cpp b/src/CalcManager/Ratpack/logic.cpp
index c7f8a3a3..7939ce26 100644
--- a/src/CalcManager/Ratpack/logic.cpp
+++ b/src/CalcManager/Ratpack/logic.cpp
@@ -13,59 +13,58 @@
// Contains routines for and, or, xor, not and other support
//
//---------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
using namespace std;
-void lshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
+void lshrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
{
- PRAT pwr= nullptr;
+ PRAT pwr = nullptr;
int32_t intb;
intrat(pa, radix, precision);
- if ( !zernum( (*pa)->pp ) )
- {
+ if (!zernum((*pa)->pp))
+ {
// If input is zero we're done.
- if ( rat_gt( b, rat_max_exp, precision) )
- {
+ if (rat_gt(b, rat_max_exp, precision))
+ {
// Don't attempt lsh of anything big
- throw( CALC_E_DOMAIN );
- }
+ throw(CALC_E_DOMAIN);
+ }
intb = rattoi32(b, radix, precision);
- DUPRAT(pwr,rat_two);
+ DUPRAT(pwr, rat_two);
ratpowi32(&pwr, intb, precision);
mulrat(pa, pwr, precision);
destroyrat(pwr);
- }
+ }
}
-void rshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
+void rshrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
{
- PRAT pwr= nullptr;
+ PRAT pwr = nullptr;
int32_t intb;
intrat(pa, radix, precision);
- if ( !zernum( (*pa)->pp ) )
- {
+ if (!zernum((*pa)->pp))
+ {
// If input is zero we're done.
- if ( rat_lt( b, rat_min_exp, precision) )
- {
+ if (rat_lt(b, rat_min_exp, precision))
+ {
// Don't attempt rsh of anything big and negative.
- throw( CALC_E_DOMAIN );
- }
+ throw(CALC_E_DOMAIN);
+ }
intb = rattoi32(b, radix, precision);
- DUPRAT(pwr,rat_two);
+ DUPRAT(pwr, rat_two);
ratpowi32(&pwr, intb, precision);
divrat(pa, pwr, precision);
destroyrat(pwr);
- }
+ }
}
-void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision);
-void boolnum( PNUMBER *pa, PNUMBER b, int func );
+void boolrat(PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision);
+void boolnum(PNUMBER *pa, PNUMBER b, int func);
enum {
@@ -74,22 +73,22 @@ enum {
FUNC_XOR
} BOOL_FUNCS;
-void andrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
+void andrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
{
- boolrat( pa, b, FUNC_AND, radix, precision);
+ boolrat(pa, b, FUNC_AND, radix, precision);
}
-void orrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
+void orrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
{
- boolrat( pa, b, FUNC_OR, radix, precision);
+ boolrat(pa, b, FUNC_OR, radix, precision);
}
-void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
+void xorrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
{
- boolrat( pa, b, FUNC_XOR, radix, precision);
+ boolrat(pa, b, FUNC_XOR, radix, precision);
}
//---------------------------------------------------------------------------
@@ -104,15 +103,15 @@ void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
-void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision)
+void boolrat(PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision)
{
- PRAT tmp= nullptr;
- intrat( pa, radix, precision);
- DUPRAT(tmp,b);
- intrat( &tmp, radix, precision);
+ PRAT tmp = nullptr;
+ intrat(pa, radix, precision);
+ DUPRAT(tmp, b);
+ intrat(&tmp, radix, precision);
- boolnum( &((*pa)->pp), tmp->pp, func );
+ boolnum(&((*pa)->pp), tmp->pp, func);
destroyrat(tmp);
}
@@ -130,11 +129,11 @@ void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision)
//
//---------------------------------------------------------------------------
-void boolnum( PNUMBER *pa, PNUMBER b, int func )
+void boolnum(PNUMBER *pa, PNUMBER b, int func)
{
- PNUMBER c= nullptr;
- PNUMBER a= nullptr;
+ PNUMBER c = nullptr;
+ PNUMBER a = nullptr;
MANTTYPE *pcha;
MANTTYPE *pchb;
MANTTYPE *pchc;
@@ -143,26 +142,26 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
MANTTYPE da;
MANTTYPE db;
- a=*pa;
- cdigits = max( a->cdigit+a->exp, b->cdigit+b->exp ) -
- min( a->exp, b->exp );
- createnum( c, cdigits );
- c->exp = min( a->exp, b->exp );
+ a = *pa;
+ cdigits = max(a->cdigit + a->exp, b->cdigit + b->exp) -
+ min(a->exp, b->exp);
+ createnum(c, cdigits);
+ c->exp = min(a->exp, b->exp);
mexp = c->exp;
c->cdigit = cdigits;
pcha = a->mant;
pchb = b->mant;
pchc = c->mant;
- for ( ;cdigits > 0; cdigits--, mexp++ )
+ for (; cdigits > 0; cdigits--, mexp++)
+ {
+ da = (((mexp >= a->exp) && (cdigits + a->exp - c->exp >
+ (c->cdigit - a->cdigit))) ?
+ *pcha++ : 0);
+ db = (((mexp >= b->exp) && (cdigits + b->exp - c->exp >
+ (c->cdigit - b->cdigit))) ?
+ *pchb++ : 0);
+ switch (func)
{
- da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp >
- (c->cdigit - a->cdigit) ) ) ?
- *pcha++ : 0 );
- db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp >
- (c->cdigit - b->cdigit) ) ) ?
- *pchb++ : 0 );
- switch ( func )
- {
case FUNC_AND:
*pchc++ = da & db;
break;
@@ -172,15 +171,51 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
case FUNC_XOR:
*pchc++ = da ^ db;
break;
- }
}
+ }
c->sign = a->sign;
- while ( c->cdigit > 1 && *(--pchc) == 0 )
- {
+ while (c->cdigit > 1 && *(--pchc) == 0)
+ {
c->cdigit--;
- }
- destroynum( *pa );
- *pa=c;
+ }
+ destroynum(*pa);
+ *pa = c;
+}
+
+//-----------------------------------------------------------------------------
+//
+// FUNCTION: remrat
+//
+// ARGUMENTS: pointer to a rational a second rational.
+//
+// RETURN: None, changes pointer.
+//
+// DESCRIPTION: Calculate the remainder of *pa / b,
+// equivalent of 'pa % b' in C/C++ and produces a result
+// that is either zero or has the same sign as the dividend.
+//
+//-----------------------------------------------------------------------------
+
+void remrat(PRAT *pa, PRAT b)
+
+{
+ if (zerrat(b))
+ {
+ throw CALC_E_INDEFINITE;
+ }
+
+ PRAT tmp = nullptr;
+ DUPRAT(tmp, b);
+
+ mulnumx(&((*pa)->pp), tmp->pq);
+ mulnumx(&(tmp->pp), (*pa)->pq);
+ remnum(&((*pa)->pp), tmp->pp, BASEX);
+ mulnumx(&((*pa)->pq), tmp->pq);
+
+ // Get *pa back in the integer over integer form.
+ RENORMALIZE(*pa);
+
+ destroyrat(tmp);
}
//-----------------------------------------------------------------------------
@@ -191,28 +226,38 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
//
// RETURN: None, changes pointer.
//
-// DESCRIPTION: Does the rational equivalent of frac(*pa);
+// DESCRIPTION: Calculate the remainder of *pa / b, with the sign of the result
+// either zero or has the same sign as the divisor.
+// NOTE: When *pa or b are negative, the result won't be the same as
+// the C/C++ operator %, use remrat if it's the behavior you expect.
//
//-----------------------------------------------------------------------------
-void modrat( PRAT *pa, PRAT b )
-
+void modrat(PRAT *pa, PRAT b)
{
+ //contrary to remrat(X, 0) returning 0, modrat(X, 0) must return X
+ if (zerrat(b))
+ {
+ return;
+ }
+
PRAT tmp = nullptr;
+ DUPRAT(tmp, b);
- if ( zerrat( b ) )
- {
- throw CALC_E_INDEFINITE;
- }
- DUPRAT(tmp,b);
+ auto needAdjust = (SIGN(*pa) == -1 ? (SIGN(b) == 1) : (SIGN(b) == -1));
- mulnumx( &((*pa)->pp), tmp->pq );
- mulnumx( &(tmp->pp), (*pa)->pq );
- remnum( &((*pa)->pp), tmp->pp, BASEX );
- mulnumx( &((*pa)->pq), tmp->pq );
+ mulnumx(&((*pa)->pp), tmp->pq);
+ mulnumx(&(tmp->pp), (*pa)->pq);
+ remnum(&((*pa)->pp), tmp->pp, BASEX);
+ mulnumx(&((*pa)->pq), tmp->pq);
+
+ if (needAdjust && !zerrat(*pa))
+ {
+ addrat(pa, b, BASEX);
+ }
// Get *pa back in the integer over integer form.
RENORMALIZE(*pa);
- destroyrat( tmp );
+ destroyrat(tmp);
}
diff --git a/src/CalcManager/Ratpack/num.cpp b/src/CalcManager/Ratpack/num.cpp
index 2bfa6b89..7b45fea0 100644
--- a/src/CalcManager/Ratpack/num.cpp
+++ b/src/CalcManager/Ratpack/num.cpp
@@ -17,7 +17,8 @@
//
//
//-----------------------------------------------------------------------------
-#include "pch.h"
+#include
+#include // for memmove
#include "ratpak.h"
using namespace std;
diff --git a/src/CalcManager/Ratpack/rat.cpp b/src/CalcManager/Ratpack/rat.cpp
index e101458a..e5a6d254 100644
--- a/src/CalcManager/Ratpack/rat.cpp
+++ b/src/CalcManager/Ratpack/rat.cpp
@@ -16,7 +16,6 @@
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
using namespace std;
diff --git a/src/CalcManager/Ratpack/ratpak.h b/src/CalcManager/Ratpack/ratpak.h
index 75ac28de..349569a6 100644
--- a/src/CalcManager/Ratpack/ratpak.h
+++ b/src/CalcManager/Ratpack/ratpak.h
@@ -17,7 +17,11 @@
//
//-----------------------------------------------------------------------------
+#include
+#include
#include "CalcErr.h"
+#include // for memmove
+#include // for SAL
static constexpr uint32_t BASEXPWR = 31L;// Internal log2(BASEX)
static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise
@@ -148,6 +152,9 @@ extern PRAT rat_min_i32;
#define LOGNUM2(pnum) ((pnum)->cdigit+(pnum)->exp)
#define LOGRAT2(prat) (LOGNUM2((prat)->pp)-LOGNUM2((prat)->pq))
+// SIGN returns the sign of the rational
+#define SIGN(prat) ((prat)->pp->sign*(prat)->pq->sign)
+
#if defined( DEBUG_RATPAK )
//-----------------------------------------------------------------------------
//
@@ -423,7 +430,8 @@ extern void divnumx( _Inout_ PNUMBER *pa, _In_ PNUMBER b, int32_t precision);
extern void divrat( _Inout_ PRAT *pa, _In_ PRAT b, int32_t precision);
extern void fracrat( _Inout_ PRAT *pa , uint32_t radix, int32_t precision);
extern void factrat( _Inout_ PRAT *pa, uint32_t radix, int32_t precision);
-extern void modrat( _Inout_ PRAT *pa, _In_ PRAT b );
+extern void remrat(_Inout_ PRAT *pa, _In_ PRAT b);
+extern void modrat(_Inout_ PRAT *pa, _In_ PRAT b);
extern void gcdrat( _Inout_ PRAT *pa, int32_t precision);
extern void intrat( _Inout_ PRAT *px, uint32_t radix, int32_t precision);
extern void mulnum( _Inout_ PNUMBER *pa, _In_ PNUMBER b, uint32_t radix);
diff --git a/src/CalcManager/Ratpack/support.cpp b/src/CalcManager/Ratpack/support.cpp
index ebee00c6..1e6a9204 100644
--- a/src/CalcManager/Ratpack/support.cpp
+++ b/src/CalcManager/Ratpack/support.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//----------------------------------------------------------------------------
@@ -18,7 +18,9 @@
//
//----------------------------------------------------------------------------
-#include "pch.h"
+#include
+#include // for memmove
+#include // for wostream
#include "ratpak.h"
using namespace std;
@@ -296,7 +298,7 @@ void intrat( PRAT *px, uint32_t radix, int32_t precision)
// Subtract the fractional part of the rational
PRAT pret = nullptr;
DUPRAT(pret,*px);
- modrat( &pret, rat_one );
+ remrat( &pret, rat_one );
subrat( px, pret, precision);
destroyrat( pret );
@@ -348,8 +350,7 @@ bool rat_ge( PRAT a, PRAT b, int32_t precision)
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
b->pp->sign *= -1;
- bool bret = ( zernum( rattmp->pp ) ||
- rattmp->pp->sign * rattmp->pq->sign == 1 );
+ bool bret = ( zernum( rattmp->pp ) || SIGN(rattmp) == 1 );
destroyrat( rattmp );
return( bret );
}
@@ -374,8 +375,7 @@ bool rat_gt( PRAT a, PRAT b, int32_t precision)
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
b->pp->sign *= -1;
- bool bret = ( !zernum( rattmp->pp ) &&
- rattmp->pp->sign * rattmp->pq->sign == 1 );
+ bool bret = ( !zernum( rattmp->pp ) && SIGN(rattmp) == 1 );
destroyrat( rattmp );
return( bret );
}
@@ -400,8 +400,7 @@ bool rat_le( PRAT a, PRAT b, int32_t precision)
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
b->pp->sign *= -1;
- bool bret = ( zernum( rattmp->pp ) ||
- rattmp->pp->sign * rattmp->pq->sign == -1 );
+ bool bret = ( zernum( rattmp->pp ) || SIGN(rattmp) == -1 );
destroyrat( rattmp );
return( bret );
}
@@ -426,8 +425,7 @@ bool rat_lt( PRAT a, PRAT b, int32_t precision)
b->pp->sign *= -1;
addrat( &rattmp, b, precision);
b->pp->sign *= -1;
- bool bret = ( !zernum( rattmp->pp ) &&
- rattmp->pp->sign * rattmp->pq->sign == -1 );
+ bool bret = ( !zernum( rattmp->pp ) && SIGN(rattmp) == -1 );
destroyrat( rattmp );
return( bret );
}
diff --git a/src/CalcManager/Ratpack/trans.cpp b/src/CalcManager/Ratpack/trans.cpp
index 82897564..3706d44d 100644
--- a/src/CalcManager/Ratpack/trans.cpp
+++ b/src/CalcManager/Ratpack/trans.cpp
@@ -14,7 +14,6 @@
//
//----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
diff --git a/src/CalcManager/Ratpack/transh.cpp b/src/CalcManager/Ratpack/transh.cpp
index 92a12583..85c27f8b 100644
--- a/src/CalcManager/Ratpack/transh.cpp
+++ b/src/CalcManager/Ratpack/transh.cpp
@@ -14,7 +14,6 @@
//
//
//-----------------------------------------------------------------------------
-#include "pch.h"
#include "ratpak.h"
diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp
index 0548719a..7bfc4817 100644
--- a/src/CalcManager/UnitConverter.cpp
+++ b/src/CalcManager/UnitConverter.cpp
@@ -1,7 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+#include
+#include
+#include // for std::sort
#include "Command.h"
#include "UnitConverter.h"
@@ -63,7 +65,8 @@ UnitConverter::UnitConverter(_In_ const shared_ptr& dataLo
unquoteConversions[L"{sc}"] = L';';
unquoteConversions[L"{lb}"] = LEFTESCAPECHAR;
unquoteConversions[L"{rb}"] = RIGHTESCAPECHAR;
- Reset();
+ ClearValues();
+ ResetCategoriesAndRatios();
}
void UnitConverter::Initialize()
@@ -75,7 +78,7 @@ bool UnitConverter::CheckLoad()
{
if (m_categories.empty())
{
- Reset();
+ ResetCategoriesAndRatios();
}
return !m_categories.empty();
}
@@ -152,7 +155,6 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType
Calculate();
UpdateCurrencySymbols();
- UpdateViewModel();
}
///
@@ -336,7 +338,8 @@ wstring UnitConverter::Serialize()
/// wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it
void UnitConverter::DeSerialize(const wstring& serializedData)
{
- Reset();
+ ClearValues();
+ ResetCategoriesAndRatios();
if (serializedData.empty())
{
@@ -403,12 +406,30 @@ void UnitConverter::RestoreUserPreferences(const wstring& userPreferences)
}
vector outerTokens = StringToVector(userPreferences, L"|");
- if (outerTokens.size() == 3)
+ if (outerTokens.size() != 3)
{
- m_fromType = StringToUnit(outerTokens[0]);
- m_toType = StringToUnit(outerTokens[1]);
- m_currentCategory = StringToCategory(outerTokens[2]);
+ return;
}
+
+ auto fromType = StringToUnit(outerTokens[0]);
+ auto toType = StringToUnit(outerTokens[1]);
+ m_currentCategory = StringToCategory(outerTokens[2]);
+
+ // Only restore from the saved units if they are valid in the current available units.
+ auto itr = m_categoryToUnits.find(m_currentCategory);
+ if (itr != m_categoryToUnits.end())
+ {
+ const auto& curUnits = itr->second;
+ if (find(curUnits.begin(), curUnits.end(), fromType) != curUnits.end())
+ {
+ m_fromType = fromType;
+ }
+ if (find(curUnits.begin(), curUnits.end(), toType) != curUnits.end())
+ {
+ m_toType = toType;
+ }
+ }
+
}
///
@@ -615,7 +636,7 @@ void UnitConverter::SendCommand(Command command)
clearFront = false;
clearBack = false;
ClearValues();
- Reset();
+ ResetCategoriesAndRatios();
break;
default:
@@ -634,8 +655,6 @@ void UnitConverter::SendCommand(Command command)
}
Calculate();
-
- UpdateViewModel();
}
///
@@ -824,19 +843,16 @@ vector> UnitConverter::CalculateSuggested()
returnVector.push_back(whimsicalReturnVector.at(0));
}
- //
-
return returnVector;
}
///
-/// Resets the converter to its initial state
+/// Resets categories and ratios
///
-void UnitConverter::Reset()
+void UnitConverter::ResetCategoriesAndRatios()
{
m_categories = m_dataLoader->LoadOrderedCategories();
- ClearValues();
m_switchedActive = false;
if (m_categories.empty())
@@ -881,7 +897,6 @@ void UnitConverter::Reset()
}
InitializeSelectedUnits();
- Calculate();
}
///
@@ -972,11 +987,21 @@ bool UnitConverter::AnyUnitIsEmpty()
///
void UnitConverter::Calculate()
{
- unordered_map conversionTable = m_ratioMap[m_fromType];
- double returnValue = stod(m_currentDisplay);
- if (AnyUnitIsEmpty() || (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0))
+ if (AnyUnitIsEmpty())
{
m_returnDisplay = m_currentDisplay;
+ m_returnHasDecimal = m_currentHasDecimal;
+ TrimString(m_returnDisplay);
+ UpdateViewModel();
+ return;
+ }
+
+ unordered_map conversionTable = m_ratioMap[m_fromType];
+ double returnValue = stod(m_currentDisplay);
+ if (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0)
+ {
+ m_returnDisplay = m_currentDisplay;
+ m_returnHasDecimal = m_currentHasDecimal;
TrimString(m_returnDisplay);
}
else
@@ -1015,9 +1040,9 @@ void UnitConverter::Calculate()
m_returnDisplay = returnString;
TrimString(m_returnDisplay);
}
+ m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos);
}
-
- m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos);
+ UpdateViewModel();
}
///
diff --git a/src/CalcManager/UnitConverter.h b/src/CalcManager/UnitConverter.h
index 4e130d12..4c77f8aa 100644
--- a/src/CalcManager/UnitConverter.h
+++ b/src/CalcManager/UnitConverter.h
@@ -1,8 +1,14 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
+#include
+#include
+#include
+#include // for SAL
+#include // for std::shared_ptr
+
namespace UnitConversionManager
{
enum class Command;
@@ -195,6 +201,8 @@ namespace UnitConversionManager
virtual void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) = 0;
virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) = 0;
virtual concurrency::task> RefreshCurrencyRatios() = 0;
+ virtual void Calculate() = 0;
+ virtual void ResetCategoriesAndRatios() = 0;
};
class UnitConverter : public IUnitConverter, public std::enable_shared_from_this
@@ -218,6 +226,8 @@ namespace UnitConversionManager
void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) override;
concurrency::task> RefreshCurrencyRatios() override;
+ void Calculate() override;
+ void ResetCategoriesAndRatios() override;
// IUnitConverter
static std::vector StringToVector(const std::wstring& w, const wchar_t * delimiter, bool addRemainder = false);
@@ -228,9 +238,7 @@ namespace UnitConversionManager
bool CheckLoad();
double Convert(double value, ConversionData conversionData);
std::vector> CalculateSuggested();
- void Reset();
void ClearValues();
- void Calculate();
void TrimString(std::wstring& input);
void InitializeSelectedUnits();
std::wstring RoundSignificant(double num, int numSignificant);
diff --git a/src/CalcManager/pch.cpp b/src/CalcManager/pch.cpp
index 1da170eb..8ca9987d 100644
--- a/src/CalcManager/pch.cpp
+++ b/src/CalcManager/pch.cpp
@@ -1,4 +1,6 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-#include "pch.h"
+// Intentionally do not include the pch.h here. For projects that don't
+// use precompiled headers, including the header here would force unnecessary compilation.
+// The pch will be included through forced include.
diff --git a/src/CalcManager/pch.h b/src/CalcManager/pch.h
index c5f39b6d..e66e1a38 100644
--- a/src/CalcManager/pch.h
+++ b/src/CalcManager/pch.h
@@ -3,27 +3,20 @@
#pragma once
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
+// The CalcManager project should be able to be compiled with or without a precompiled header
+// in - order to support other toolchains besides MSVC. When adding new system headers, make sure
+// that the relevant source file includes all headers it needs, but then also add the system headers
+// here so that MSVC users see the performance benefit.
-// Windows headers define min/max macros.
-// Disable it for project code.
-#define NOMINMAX
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
diff --git a/src/CalcManager/targetver.h b/src/CalcManager/targetver.h
deleted file mode 100644
index 221efabb..00000000
--- a/src/CalcManager/targetver.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-#pragma once
-
-// Including SDKDDKVer.h defines the highest available Windows platform.
-
-// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
-// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
-
-#include
diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp
index f99ce036..5033080b 100644
--- a/src/CalcViewModel/ApplicationViewModel.cpp
+++ b/src/CalcViewModel/ApplicationViewModel.cpp
@@ -36,7 +36,6 @@ namespace
{
StringReference CategoriesPropertyName(L"Categories");
StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility");
- StringReference AppBarVisibilityPropertyName(L"AppBarVisibility");
}
ApplicationViewModel::ApplicationViewModel() :
@@ -164,7 +163,6 @@ void ApplicationViewModel::OnModeChanged()
TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
RaisePropertyChanged(ClearMemoryVisibilityPropertyName);
- RaisePropertyChanged(AppBarVisibilityPropertyName);
}
void ApplicationViewModel::OnCopyCommand(Object^ parameter)
@@ -189,7 +187,7 @@ void ApplicationViewModel::OnPasteCommand(Object^ parameter)
{
ConverterViewModel->OnPasteCommand(parameter);
}
- else
+ else if (NavCategory::IsCalculatorViewMode(m_mode))
{
CalculatorViewModel->OnPasteCommand(parameter);
}
diff --git a/src/CalcViewModel/ApplicationViewModel.h b/src/CalcViewModel/ApplicationViewModel.h
index f13e00ad..74567ca1 100644
--- a/src/CalcViewModel/ApplicationViewModel.h
+++ b/src/CalcViewModel/ApplicationViewModel.h
@@ -66,16 +66,6 @@ namespace CalculatorApp
}
}
- property Windows::UI::Xaml::Visibility AppBarVisibility
- {
- Windows::UI::Xaml::Visibility get()
- {
- return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode)
- ? Windows::UI::Xaml::Visibility::Visible
- : Windows::UI::Xaml::Visibility::Collapsed;
- }
- }
-
private:
bool TryRecoverFromNavigationModeFailure();
diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp
index 4dc48074..b17aaba4 100644
--- a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp
+++ b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Implementation of the NarratorNotifier class.
diff --git a/src/CalcViewModel/Common/CalculatorDisplay.cpp b/src/CalcViewModel/Common/CalculatorDisplay.cpp
index cd531e01..4da98129 100644
--- a/src/CalcViewModel/Common/CalculatorDisplay.cpp
+++ b/src/CalcViewModel/Common/CalculatorDisplay.cpp
@@ -36,7 +36,7 @@ void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue
}
}
-void CalculatorDisplay::SetParenDisplayText(_In_ const std::wstring& parenthesisCount)
+void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
if (m_callbackReference != nullptr)
{
diff --git a/src/CalcViewModel/Common/CalculatorDisplay.h b/src/CalcViewModel/Common/CalculatorDisplay.h
index 9ff06a6e..877bdf06 100644
--- a/src/CalcViewModel/Common/CalculatorDisplay.h
+++ b/src/CalcViewModel/Common/CalculatorDisplay.h
@@ -21,7 +21,7 @@ namespace CalculatorApp
void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) override;
void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override;
void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override;
- void SetParenDisplayText(_In_ const std::wstring& parenthesisCount) override;
+ void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override;
void OnNoRightParenAdded() override;
void MaxDigitsReached() override;
void BinaryOperatorReceived() override;
diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp
index d10c4c57..6d6807ba 100644
--- a/src/CalcViewModel/Common/CopyPasteManager.cpp
+++ b/src/CalcViewModel/Common/CopyPasteManager.cpp
@@ -15,14 +15,15 @@ using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::ApplicationModel::DataTransfer;
-unsigned long long maxOperandNumber;
-
String^ CopyPasteManager::supportedFormats[] =
{
StandardDataFormats::Text
};
-constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" };
+static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" };
+
+// The below values can not be "constexpr"-ed,
+// as both wstring_view and wchar[] can not be concatenated
// [\s\x85] means white-space characters
static const wstring c_wspc = L"[\\s\\x85]*";
static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc;
@@ -103,19 +104,16 @@ task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupTyp
int CopyPasteManager::ClipboardTextFormat()
{
- int result = -1;
-
- auto dataPackageView = Clipboard::GetContent();
+ const auto dataPackageView = Clipboard::GetContent();
for (int i = 0; i < RTL_NUMBER_OF(supportedFormats); i++)
{
if (dataPackageView->Contains(supportedFormats[i]))
{
- result = i;
- break;
+ return i;
}
}
- return result;
+ return -1;
}
String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType)
@@ -268,13 +266,8 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
return false;
}
- bool expMatched = true;
vector patterns{};
-
- pair operandLimits = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType);
- size_t maxOperandLength = operandLimits.first;
- uint64_t maxOperandValue = operandLimits.second;
-
+
if (mode == ViewMode::Standard)
{
patterns.assign(standardModePatterns.begin(), standardModePatterns.end());
@@ -292,11 +285,14 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
patterns.assign(unitConverterPatterns.begin(), unitConverterPatterns.end());
}
- for (const wstring& operand : operands)
+ const auto [maxOperandLength, maxOperandValue] = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType);
+ bool expMatched = true;
+
+ for (const auto& operand : operands)
{
// Each operand only needs to match one of the available patterns.
bool operandMatched = false;
- for (const wregex& pattern : patterns)
+ for (const auto& pattern : patterns)
{
operandMatched = operandMatched || regex_match(operand, pattern);
}
@@ -305,7 +301,7 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
{
// Remove characters that are valid in the expression but we do not want to include in length calculations
// or which will break conversion from string-to-ULL.
- wstring operandValue = SanitizeOperand(operand);
+ const wstring operandValue = SanitizeOperand(operand);
// If an operand exceeds the maximum length allowed, break and return.
if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLength)
@@ -341,16 +337,16 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m
pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
{
- size_t maxLength = 0;
- uint64_t maxValue = 0;
-
+ constexpr size_t defaultMaxOperandLength = 0;
+ constexpr uint64_t defaultMaxValue = 0;
+
if (mode == ViewMode::Standard)
{
- maxLength = MaxStandardOperandLength;
+ return make_pair(MaxStandardOperandLength, defaultMaxValue);
}
else if (mode == ViewMode::Scientific)
{
- maxLength = MaxScientificOperandLength;
+ return make_pair(MaxScientificOperandLength, defaultMaxValue);
}
else if (mode == ViewMode::Programmer)
{
@@ -390,15 +386,17 @@ pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mo
unsigned int signBit = (programmerNumberBase == DecBase) ? 1 : 0;
- maxLength = (size_t)ceil((bitLength - signBit) / bitsPerDigit);
- maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit));
+ const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit));
+ const uint64_t maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit));
+
+ return make_pair(maxLength, maxValue);
}
else if (modeType == CategoryGroupType::Converter)
{
- maxLength = MaxConverterInputLength;
+ return make_pair(MaxConverterInputLength, defaultMaxValue);
}
- return make_pair(maxLength, maxValue);
+ return make_pair(defaultMaxOperandLength, defaultMaxValue);
}
wstring CopyPasteManager::SanitizeOperand(const wstring& operand)
@@ -417,8 +415,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
return false;
}
- // Default to base10
- int intBase = 10;
+ int intBase;
switch (numberBase)
{
case HexBase:
@@ -430,6 +427,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
case BinBase:
intBase = 2;
break;
+ default:
case DecBase:
intBase = 10;
break;
@@ -441,11 +439,11 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
result = stoull(operand, &size, intBase);
return true;
}
- catch (invalid_argument)
+ catch (const invalid_argument&)
{
// Do nothing
}
- catch (out_of_range)
+ catch (const out_of_range&)
{
// Do nothing
}
@@ -453,35 +451,28 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u
return false;
}
-size_t CopyPasteManager::OperandLength(wstring operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase)
-{
- size_t len = 0;
- if (mode == ViewMode::Standard || mode == ViewMode::Scientific)
- {
- len = StandardScientificOperandLength(operand);
- }
- else if (mode == ViewMode::Programmer)
- {
- len = ProgrammerOperandLength(operand, programmerNumberBase);
- }
- else if (modeType == CategoryGroupType::Converter)
- {
- len = operand.length();
+size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase)
+{
+ if (modeType == CategoryGroupType::Converter) {
+ return operand.length();
}
- return len;
+ switch(mode) {
+ case ViewMode::Standard:
+ case ViewMode::Scientific:
+ return StandardScientificOperandLength(operand);
+
+ case ViewMode::Programmer:
+ return ProgrammerOperandLength(operand, programmerNumberBase);
+
+ default:
+ return 0;
+ }
}
-size_t CopyPasteManager::StandardScientificOperandLength(wstring operand)
-{
- bool hasDecimal = false;
- for (size_t i = 0; i < operand.length(); i++)
- {
- if (operand[i] == L'.')
- {
- hasDecimal = true;
- }
- }
+size_t CopyPasteManager::StandardScientificOperandLength(const wstring& operand)
+{
+ const bool hasDecimal = operand.find('.') != wstring::npos;
if (hasDecimal)
{
@@ -503,8 +494,7 @@ size_t CopyPasteManager::StandardScientificOperandLength(wstring operand)
size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int numberBase)
{
- size_t len = operand.length();
-
+
vector prefixes{};
vector suffixes{};
switch (numberBase)
@@ -525,7 +515,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
break;
default:
// No defined prefixes/suffixes
- break;
+ return 0;
}
// UInt suffixes are common across all modes
@@ -535,9 +525,11 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
wstring operandUpper = operand;
transform(operandUpper.begin(), operandUpper.end(), operandUpper.begin(), towupper);
+ size_t len = operand.length();
+
// Detect if there is a suffix and subtract its length
// Check suffixes first to allow e.g. "0b" to result in length 1 (value 0), rather than length 0 (no value).
- for (const wstring& suffix : suffixes)
+ for (const auto& suffix : suffixes)
{
if (len < suffix.length())
{
@@ -552,7 +544,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
}
// Detect if there is a prefix and subtract its length
- for (const wstring& prefix : prefixes)
+ for (const auto& prefix : prefixes)
{
if (len < prefix.length())
{
diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h
index 9a886154..9d6fd669 100644
--- a/src/CalcViewModel/Common/CopyPasteManager.h
+++ b/src/CalcViewModel/Common/CopyPasteManager.h
@@ -13,15 +13,14 @@ namespace CalculatorUnitTests
namespace CalculatorApp
{
-
-#define QwordType 1
-#define DwordType 2
-#define WordType 3
-#define ByteType 4
-#define HexBase 5
-#define DecBase 6
-#define OctBase 7
-#define BinBase 8
+ inline constexpr auto QwordType = 1;
+ inline constexpr auto DwordType = 2;
+ inline constexpr auto WordType = 3;
+ inline constexpr auto ByteType = 4;
+ inline constexpr auto HexBase = 5;
+ inline constexpr auto DecBase = 6;
+ inline constexpr auto OctBase = 7;
+ inline constexpr auto BinBase = 8;
class CopyPasteManager
{
@@ -55,8 +54,8 @@ namespace CalculatorApp
static std::pair GetMaxOperandLengthAndValue(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1);
static std::wstring SanitizeOperand(const std::wstring& operand);
static bool TryOperandToULL(const std::wstring& operand, int numberBase, unsigned long long int& result);
- static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1);
- static size_t StandardScientificOperandLength(std::wstring operand);
+ static size_t OperandLength(const std::wstring& operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1);
+ static size_t StandardScientificOperandLength(const std::wstring& operand);
static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase);
static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input);
diff --git a/src/CalcViewModel/Common/DateCalculator.cpp b/src/CalcViewModel/Common/DateCalculator.cpp
index 63efcdd0..4ccba38c 100644
--- a/src/CalcViewModel/Common/DateCalculator.cpp
+++ b/src/CalcViewModel/Common/DateCalculator.cpp
@@ -20,13 +20,27 @@ DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier)
// Returns: True if function succeeds to calculate the date else returns False
bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime *endDate)
{
+ auto currentCalendarSystem = m_calendar->GetCalendarSystem();
+
try
{
m_calendar->SetDateTime(startDate);
if (duration.year != 0)
{
+ // The Japanese Era system can have multiple year partitions within the same year.
+ // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
+ // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in a date in Heisei 31.
+ // To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math, and then convert back to the Japanese era system.
+ // This works because the Japanese era system maintains the same year/month boundaries and durations as the Gregorian system and is only different in display value.
+ if (currentCalendarSystem == CalendarIdentifiers::Japanese)
+ {
+ m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian);
+ }
+
m_calendar->AddYears(duration.year);
+
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
}
if (duration.month != 0)
{
@@ -41,6 +55,9 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date
}
catch (Platform::InvalidArgumentException^ ex)
{
+ // ensure that we revert to the correct calendar system
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
+
// Do nothing
return false;
}
@@ -52,6 +69,8 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date
// Returns: True if function succeeds to calculate the date else returns False
bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime *endDate)
{
+ auto currentCalendarSystem = m_calendar->GetCalendarSystem();
+
// For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first
// and then the larger units.
try
@@ -68,13 +87,28 @@ bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const
}
if (duration.year != 0)
{
+ // The Japanese Era system can have multiple year partitions within the same year.
+ // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
+ // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in a date in Heisei 31.
+ // To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math, and then convert back to the Japanese era system.
+ // This works because the Japanese era system maintains the same year/month boundaries and durations as the Gregorian system and is only different in display value.
+ if (currentCalendarSystem == CalendarIdentifiers::Japanese)
+ {
+ m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian);
+ }
+
m_calendar->AddYears(-duration.year);
+
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
}
*endDate = m_calendar->GetDateTime();
}
catch (Platform::InvalidArgumentException^ ex)
{
+ // ensure that we revert to the correct calendar system
+ m_calendar->ChangeCalendarSystem(currentCalendarSystem);
+
// Do nothing
return false;
}
diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h b/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h
index bd8cb169..7032b250 100644
--- a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h
+++ b/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace CalculatorApp
@@ -162,7 +162,8 @@ namespace CalculatorApp
Data_Zebibytes = UnitStart + 162,
Data_Zetabits = UnitStart + 163,
Data_Zetabytes = UnitStart + 164,
- UnitEnd = Data_Zetabytes
+ Area_Pyeong = UnitStart + 165,
+ UnitEnd = Area_Pyeong
};
}
}
diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp
index 45411c1d..c95fda5a 100644
--- a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp
+++ b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp
@@ -118,12 +118,19 @@ void UnitConverterDataLoader::LoadData()
unordered_map unitConversions = categoryToUnitConversionDataMap.at(categoryViewMode);
double unitFactor = unitConversions[unit.id];
- for (auto itr = unitConversions.begin(); itr != unitConversions.end(); ++itr)
+ for (const auto&[id, conversionFactor] : unitConversions)
{
+ if (idToUnit.find(id) == idToUnit.end())
+ {
+ // Optional units will not be in idToUnit but can be in unitConversions.
+ // For optional units that did not make it to the current set of units, just continue.
+ continue;
+ }
+
UCM::ConversionData parsedData = { 1.0, 0.0, false };
- assert(itr->second > 0); // divide by zero assert
- parsedData.ratio = unitFactor / itr->second;
- conversions.insert(pair(idToUnit.at(itr->first), parsedData));
+ assert(conversionFactor > 0); // divide by zero assert
+ parsedData.ratio = unitFactor / conversionFactor;
+ conversions.insert(pair(idToUnit.at(id), parsedData));
}
}
else
@@ -175,6 +182,10 @@ void UnitConverterDataLoader::GetUnits(_In_ unordered_map areaUnits;
areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Acre, GetLocalizedStringName(L"UnitName_Acre"), GetLocalizedStringName(L"UnitAbbreviation_Acre"), 9 });
areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Hectare, GetLocalizedStringName(L"UnitName_Hectare"), GetLocalizedStringName(L"UnitAbbreviation_Hectare"), 4 });
@@ -190,6 +201,10 @@ void UnitConverterDataLoader::GetUnits(_In_ unordered_map dataUnits;
@@ -384,6 +399,7 @@ void UnitConverterDataLoader::GetConversionData(_In_ unordered_map()),
m_MemorizedNumbers(ref new Vector()),
m_IsMemoryEmpty(true),
m_IsFToEChecked(false),
@@ -80,8 +80,8 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() :
m_isBinaryBitFlippingEnabled(false),
m_CurrentRadixType(RADIX_TYPE::DEC_RADIX),
m_CurrentAngleType(NumbersAndOperatorsEnum::Degree),
- m_OpenParenthesisCount(L""),
m_Announcement(nullptr),
+ m_OpenParenthesisCount(0),
m_feedbackForButtonPress(nullptr),
m_isRtlLanguage(false),
m_localizedMaxDigitsReachedAutomationFormat(nullptr),
@@ -102,7 +102,6 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() :
m_localizedDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DecButton);
m_localizedOctalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::OctButton);
m_localizedBinaryAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::BinButton);
- m_leftParenthesisAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::LeftParenthesisAutomationFormat);
// Initialize the Automation Name
CalculationResultAutomationName = GetLocalizedStringFormat(m_localizedCalculationResultAutomationFormat, m_DisplayValue);
@@ -216,19 +215,23 @@ void StandardCalculatorViewModel::DisplayPasteError()
m_standardCalculatorManager.DisplayPasteError();
}
-void StandardCalculatorViewModel::SetParenthesisCount(_In_ const wstring& parenthesisCount)
+void StandardCalculatorViewModel::SetParenthesisCount(_In_ unsigned int parenthesisCount)
{
+ if (m_OpenParenthesisCount == parenthesisCount)
+ {
+ return;
+ }
+
+ OpenParenthesisCount = parenthesisCount;
if (IsProgrammer || IsScientific)
{
- OpenParenthesisCount = ref new String(parenthesisCount.c_str());
- RaisePropertyChanged("LeftParenthesisAutomationName");
+ SetOpenParenthesisCountNarratorAnnouncement();
}
}
void StandardCalculatorViewModel::SetOpenParenthesisCountNarratorAnnouncement()
{
- String^ parenthesisCount = ((m_OpenParenthesisCount == nullptr) ? "0" : m_OpenParenthesisCount);
- wstring localizedParenthesisCount = parenthesisCount->Data();
+ wstring localizedParenthesisCount = to_wstring(m_OpenParenthesisCount).c_str();
LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount);
String^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(
@@ -281,15 +284,6 @@ void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionC
}
}
-String ^ StandardCalculatorViewModel::GetLeftParenthesisAutomationName()
-{
- String^ parenthesisCount = ((m_OpenParenthesisCount == nullptr) ? "0" : m_OpenParenthesisCount);
- wstring localizedParenthesisCount = std::wstring(parenthesisCount->Data());
- LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount);
-
- return GetLocalizedStringFormat(m_leftParenthesisAutomationFormat, ref new String(localizedParenthesisCount.c_str()));
-}
-
void StandardCalculatorViewModel::SetExpressionDisplay(_Inout_ shared_ptr>> const &tokens, _Inout_ shared_ptr>> const &commands)
{
m_tokens = tokens;
@@ -321,59 +315,67 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr();
- }
- else
- {
- m_ExpressionTokens->Clear();
- }
-
unsigned int nTokens = 0;
tokens->GetSize(&nTokens);
+
+ if (nTokens == 0)
+ {
+ m_ExpressionTokens->Clear();
+ return;
+ }
+
pair currentToken;
const auto& localizer = LocalizationSettings::GetInstance();
+ const wstring separator = L" ";
for (unsigned int i = 0; i < nTokens; ++i)
{
if (SUCCEEDED(tokens->GetAt(i, ¤tToken)))
{
Common::TokenType type;
- const wstring separator = L" ";
bool isEditable = (currentToken.second == -1) ? false : true;
localizer.LocalizeDisplayValue(&(currentToken.first));
if (!isEditable)
{
- if (currentToken.first == separator)
- {
- type = TokenType::Separator;
- }
- else
- {
- type = TokenType::Operator;
- }
+ type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator;
}
-
else
{
shared_ptr command;
IFTPlatformException(m_commands->GetAt(static_cast(currentToken.second), &command));
+ type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator;
+ }
- if (command->GetCommandType() == CommandType::OperandCommand)
+ auto currentTokenString = ref new String(currentToken.first.c_str());
+ if (i < m_ExpressionTokens->Size)
+ {
+ auto existingItem = m_ExpressionTokens->GetAt(i);
+ if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString))
{
- type = TokenType::Operand;
+ existingItem->TokenPosition = i;
+ existingItem->IsTokenEditable = isEditable;
+ existingItem->CommandIndex = 0;
}
else
{
- type = TokenType::Operator;
+ auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type);
+ m_ExpressionTokens->InsertAt(i, expressionToken);
}
+
+ }
+ else
+ {
+ auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type);
+ m_ExpressionTokens->Append(expressionToken);
}
- DisplayExpressionToken^ expressionToken = ref new DisplayExpressionToken(ref new String(currentToken.first.c_str()), i, isEditable, type);
- m_ExpressionTokens->Append(expressionToken);
}
}
+
+ while (m_ExpressionTokens->Size != nTokens)
+ {
+ m_ExpressionTokens->RemoveAtEnd();
+ }
}
String^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName()
@@ -531,7 +533,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
{
if (commandIndex == 0)
{
- delete [] temp;
+ delete[] temp;
return;
}
@@ -552,7 +554,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
length = m_selectedExpressionLastData->Length() + 1;
if (length > 50)
{
- delete [] temp;
+ delete[] temp;
return;
}
for (; i < length; ++i)
@@ -1422,29 +1424,29 @@ void StandardCalculatorViewModel::SaveEditedCommand(_In_ unsigned int tokenPosit
switch (nOpCode)
{
- case static_cast(Command::CommandASIN) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSIN), true, angleType);
- break;
- case static_cast(Command::CommandACOS) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOS), true, angleType);
- break;
- case static_cast(Command::CommandATAN) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTAN), true, angleType);
- break;
- case static_cast(Command::CommandASINH) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSINH), true, angleType);
- break;
- case static_cast(Command::CommandACOSH) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOSH), true, angleType);
- break;
- case static_cast(Command::CommandATANH) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTANH), true, angleType);
- break;
- case static_cast(Command::CommandPOWE) :
- updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandLN), true, angleType);
- break;
- default:
- updatedToken = CCalcEngine::OpCodeToUnaryString(nOpCode, false, angleType);
+ case static_cast(Command::CommandASIN) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSIN), true, angleType);
+ break;
+ case static_cast(Command::CommandACOS) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOS), true, angleType);
+ break;
+ case static_cast(Command::CommandATAN) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTAN), true, angleType);
+ break;
+ case static_cast(Command::CommandASINH) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSINH), true, angleType);
+ break;
+ case static_cast(Command::CommandACOSH) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOSH), true, angleType);
+ break;
+ case static_cast(Command::CommandATANH) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTANH), true, angleType);
+ break;
+ case static_cast(Command::CommandPOWE) :
+ updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandLN), true, angleType);
+ break;
+ default:
+ updatedToken = CCalcEngine::OpCodeToUnaryString(nOpCode, false, angleType);
}
if ((token.first.length() > 0) && (token.first[token.first.length() - 1] == L'('))
{
diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h
index ba6dc82b..f8140a75 100644
--- a/src/CalcViewModel/StandardCalculatorViewModel.h
+++ b/src/CalcViewModel/StandardCalculatorViewModel.h
@@ -48,7 +48,7 @@ namespace CalculatorApp
OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError);
OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand);
OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression);
- OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector^, ExpressionTokens);
+ OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector^, ExpressionTokens);
OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue);
@@ -75,18 +75,17 @@ namespace CalculatorApp
OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled);
- OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, OpenParenthesisCount);
OBSERVABLE_PROPERTY_RW(int, CurrentRadixType);
OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated);
OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled);
OBSERVABLE_PROPERTY_RW(bool, AreProgrammerRadixOperatorsEnabled);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement^, Announcement);
+ OBSERVABLE_PROPERTY_R(unsigned int, OpenParenthesisCount);
COMMAND_FOR_METHOD(CopyCommand, StandardCalculatorViewModel::OnCopyCommand);
COMMAND_FOR_METHOD(PasteCommand, StandardCalculatorViewModel::OnPasteCommand);
COMMAND_FOR_METHOD(ButtonPressed, StandardCalculatorViewModel::OnButtonPressed);
COMMAND_FOR_METHOD(ClearMemoryCommand, StandardCalculatorViewModel::OnClearMemoryCommand);
- COMMAND_FOR_METHOD(PinUnpinAppBarButtonOnClicked, StandardCalculatorViewModel::OnPinUnpinCommand);
COMMAND_FOR_METHOD(MemoryItemPressed, StandardCalculatorViewModel::OnMemoryItemPressed);
COMMAND_FOR_METHOD(MemoryAdd, StandardCalculatorViewModel::OnMemoryAdd);
COMMAND_FOR_METHOD(MemorySubtract, StandardCalculatorViewModel::OnMemorySubtract);
@@ -255,14 +254,6 @@ namespace CalculatorApp
void set(bool value) { m_completeTextSelection = value; }
}
- property Platform::String^ LeftParenthesisAutomationName
- {
- Platform::String^ get()
- {
- return GetLeftParenthesisAutomationName();
- }
- }
-
internal:
void OnPaste(Platform::String^ pastedString, CalculatorApp::Common::ViewMode mode);
void OnCopyCommand(Platform::Object^ parameter);
@@ -283,7 +274,7 @@ namespace CalculatorApp
void SetTokens(_Inout_ std::shared_ptr>> const &tokens);
void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands);
void SetHistoryExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands);
- void SetParenthesisCount(_In_ const std::wstring& parenthesisCount);
+ void SetParenthesisCount(_In_ unsigned int parenthesisCount);
void SetOpenParenthesisCountNarratorAnnouncement();
void OnNoRightParenAdded();
void SetNoParenAddedNarratorAnnouncement();
@@ -354,7 +345,6 @@ namespace CalculatorApp
bool m_isLastOperationHistoryLoad;
Platform::String^ m_selectedExpressionLastData;
Common::DisplayExpressionToken^ m_selectedExpressionToken;
- Platform::String^ m_leftParenthesisAutomationFormat;
Platform::String^ LocalizeDisplayValue(_In_ std::wstring const &displayValue, _In_ bool isError);
Platform::String^ CalculateNarratorDisplayValue(_In_ std::wstring const &displayValue, _In_ Platform::String^ localizedDisplayValue, _In_ bool isError);
@@ -364,7 +354,6 @@ namespace CalculatorApp
CalculationManager::Command ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation);
void DisableButtons(CalculationManager::CommandType selectedExpressionCommandType);
- Platform::String^ GetLeftParenthesisAutomationName();
Platform::String^ m_feedbackForButtonPress;
void OnButtonPressed(Platform::Object^ parameter);
diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp
index 76d9aa3a..446ae582 100644
--- a/src/CalcViewModel/UnitConverterViewModel.cpp
+++ b/src/CalcViewModel/UnitConverterViewModel.cpp
@@ -165,12 +165,16 @@ void UnitConverterViewModel::PopulateData()
}
void UnitConverterViewModel::OnCategoryChanged(Object^ parameter)
+{
+ m_model->SendCommand(UCM::Command::Clear);
+ ResetCategory();
+}
+
+void UnitConverterViewModel::ResetCategory()
{
UCM::Category currentCategory = CurrentCategory->GetModelCategory();
IsCurrencyCurrentCategory = currentCategory.id == NavCategory::Serialize(ViewMode::Currency);
- m_model->SendCommand(UCM::Command::Clear);
-
m_isInputBlocked = false;
SetSelectedUnits();
@@ -706,7 +710,9 @@ void UnitConverterViewModel::OnCurrencyDataLoadFinished(bool didLoad)
{
m_isCurrencyDataLoaded = true;
CurrencyDataLoadFailed = !didLoad;
- ResetView();
+ m_model->ResetCategoriesAndRatios();
+ m_model->Calculate();
+ ResetCategory();
StringReference key = didLoad ? UnitConverterResourceKeys::CurrencyRatesUpdated : UnitConverterResourceKeys::CurrencyRatesUpdateFailed;
String^ announcement = AppResourceProvider::GetInstance().GetResourceString(key);
diff --git a/src/CalcViewModel/UnitConverterViewModel.h b/src/CalcViewModel/UnitConverterViewModel.h
index 5a982384..2c6c8af3 100644
--- a/src/CalcViewModel/UnitConverterViewModel.h
+++ b/src/CalcViewModel/UnitConverterViewModel.h
@@ -223,6 +223,7 @@ namespace CalculatorApp
void UpdateValue2AutomationName();
Platform::String^ Serialize();
void Deserialize(Platform::String^ state);
+ void ResetCategoriesAndRatio();
// Saving And Restoring User Preferences of Category and Associated-Units across Sessions.
void SaveUserPreferences();
@@ -263,6 +264,7 @@ namespace CalculatorApp
void RefreshSupplementaryResults();
void UpdateInputBlocked(_In_ const std::wstring& currencyInput);
bool UnitsAreValid();
+ void ResetCategory();
void OnButtonPressed(Platform::Object^ parameter);
Platform::String^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings);
diff --git a/src/Calculator.sln b/src/Calculator.sln
index 2d36a93f..232fcd1e 100644
--- a/src/Calculator.sln
+++ b/src/Calculator.sln
@@ -16,6 +16,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "CalcViewMo
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{D3BAED2C-4B07-4E1D-8807-9D6499450349}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorUITests", "CalculatorUITests\CalculatorUITests.csproj", "{B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@@ -28,22 +30,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {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
{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
@@ -68,6 +54,22 @@ Global
{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
+ {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
{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
@@ -100,6 +102,22 @@ Global
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.ActiveCfg = Release|Win32
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Build.0 = Release|Win32
{D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Deploy.0 = Release|Win32
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x64.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|x86.Build.0 = Debug|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|ARM64.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x64.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x64.Build.0 = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x86.ActiveCfg = Release|Any CPU
+ {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Calculator/App.xaml b/src/Calculator/App.xaml
index cec835fb..918034c0 100644
--- a/src/Calculator/App.xaml
+++ b/src/Calculator/App.xaml
@@ -19,7 +19,6 @@
#FF2B2B2B
-
@@ -55,7 +54,6 @@
#FFE0E0E0
-
@@ -89,7 +87,6 @@
2
-
@@ -356,7 +353,8 @@
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
@@ -412,12 +247,6 @@
OperatorTemplate="{StaticResource Operator}"
SeparatorTemplate="{StaticResource Separator}"/>
-
-
@@ -455,7 +284,7 @@
-
+
@@ -482,7 +311,7 @@
-
+
@@ -542,7 +371,7 @@
-
+
@@ -620,14 +449,14 @@
IsInError="{x:Bind Model.IsInError, Mode=OneWay}"
IsOperatorCommand="{x:Bind Model.IsOperatorCommand, Mode=OneWay}"
TabIndex="1"/>
-
+ TokensUpdated="{x:Bind Model.AreTokensUpdated, Mode=OneWay}"/>
- IsEnabled = enable;
+ MemButton->IsEnabled = enable;
MemMinus->IsEnabled = enable;
MemPlus->IsEnabled = enable;
if (!Model->IsMemoryEmpty)
@@ -659,11 +659,6 @@ void Calculator::OnHistoryFlyOutTapped(_In_ Object^ sender, _In_ TappedRoutedEve
}
}
-void Calculator::expressionContainer_LayoutUpdated(_In_ Object^ sender, _In_ Object^ e)
-{
- expressionText->UpdateScrollButtons();
-}
-
bool Calculator::IsValidRegularExpression(std::wstring str)
{
bool result = false;
@@ -700,7 +695,7 @@ void Calculator::DockPanelTapped(_In_ TappedRoutedEventArgs^ e)
void Calculator::UnregisterEventHandlers()
{
- expressionText->UnregisterEventHandlers();
+ ExpressionText->UnregisterEventHandlers();
}
void Calculator::OnErrorLayoutCompleted(_In_ Object^ sender, _In_ Object^ e)
diff --git a/src/Calculator/Views/Calculator.xaml.h b/src/Calculator/Views/Calculator.xaml.h
index 5ec5324b..50ecb760 100644
--- a/src/Calculator/Views/Calculator.xaml.h
+++ b/src/Calculator/Views/Calculator.xaml.h
@@ -5,7 +5,6 @@
#include "Views/Calculator.g.h"
#include "Converters/BooleanNegationConverter.h"
-#include "Converters/ExpressionItemContainerStyle.h"
#include "Converters/ExpressionItemTemplateSelector.h"
#include "Converters/VisibilityNegationConverter.h"
#include "CalcViewModel/Common/Automation/NarratorNotifier.h"
@@ -130,7 +129,6 @@ namespace CalculatorApp
void EnableMemoryControls(bool enable);
void OnMemoryFlyOutTapped(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
void OnHistoryFlyOutTapped(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
- void expressionContainer_LayoutUpdated(_In_ Platform::Object^ sender, _In_ Platform::Object^ e);
bool IsValidRegularExpression(std::wstring str);
void DockPanelTapped(_In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
void OnErrorLayoutCompleted(_In_ Platform::Object^ sender, _In_ Platform::Object^ e);
diff --git a/src/Calculator/Views/CalculatorProgrammerDisplayPanel.xaml b/src/Calculator/Views/CalculatorProgrammerDisplayPanel.xaml
index f9ff9086..1f1e443a 100644
--- a/src/Calculator/Views/CalculatorProgrammerDisplayPanel.xaml
+++ b/src/Calculator/Views/CalculatorProgrammerDisplayPanel.xaml
@@ -43,10 +43,10 @@
-
-
-
-
+
+
+
+
@@ -59,13 +59,13 @@
-
-
-
-
-
-
diff --git a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
index 9bb98fab..0318f152 100644
--- a/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
+++ b/src/CalculatorUnitTests/DateCalculatorUnitTests.cpp
@@ -664,5 +664,57 @@ namespace DateCalculationUnitTests
VERIFY_IS_TRUE(actualValue.find(expectedValue) != wstring::npos, message.c_str());
}
}
+
+ TEST_METHOD(JaEraTransitionAddition)
+ {
+ auto viewModel = make_unique(CalendarIdentifiers::Japanese);
+ auto cal = ref new Calendar();
+
+ // Showa period ended in Jan 1989.
+ cal->Year = 1989;
+ cal->Month = 1;
+ cal->Day = 1;
+ auto startTime = cal->GetDateTime();
+
+ cal->Year = 1990;
+ cal->Month = 1;
+ cal->Day = 1;
+
+ // Expect that adding a year across boundaries adds the equivalent in the Gregorian calendar.
+ auto expectedResult = cal->GetDateTime();
+ DateDifference duration;
+ duration.year = 1;
+
+ DateTime actualResult;
+ viewModel->AddDuration(startTime, duration, &actualResult);
+
+ VERIFY_ARE_EQUAL(expectedResult.UniversalTime, actualResult.UniversalTime);
+ }
+
+ TEST_METHOD(JaEraTransitionSubtraction)
+ {
+ auto viewModel = make_unique(CalendarIdentifiers::Japanese);
+ auto cal = ref new Calendar();
+
+ // Showa period ended in Jan 1989.
+ cal->Year = 1990;
+ cal->Month = 1;
+ cal->Day = 1;
+ auto startTime = cal->GetDateTime();
+
+ cal->Year = 1989;
+ cal->Month = 1;
+ cal->Day = 1;
+
+ // Expect that adding a year across boundaries adds the equivalent in the Gregorian calendar.
+ auto expectedResult = cal->GetDateTime();
+ DateDifference duration;
+ duration.year = 1;
+
+ DateTime actualResult;
+ viewModel->SubtractDuration(startTime, duration, &actualResult);
+
+ VERIFY_ARE_EQUAL(expectedResult.UniversalTime, actualResult.UniversalTime);
+ }
};
}
diff --git a/src/CalculatorUnitTests/RationalTest.cpp b/src/CalculatorUnitTests/RationalTest.cpp
new file mode 100644
index 00000000..c19692fd
--- /dev/null
+++ b/src/CalculatorUnitTests/RationalTest.cpp
@@ -0,0 +1,225 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include
+#include "Header Files/Rational.h"
+#include "Header Files/RationalMath.h"
+
+using namespace CalcEngine;
+using namespace CalcEngine::RationalMath;
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace CalculatorEngineTests
+{
+ TEST_CLASS(RationalTest)
+ {
+ public:
+ TEST_CLASS_INITIALIZE(CommonSetup)
+ {
+ ChangeConstants(10, 128);
+ }
+
+ TEST_METHOD(TestModuloOperandsNotModified)
+ {
+ // Verify results but also check that operands are not modified
+ Rational rat25(25);
+ Rational ratminus25(-25);
+ Rational rat4(4);
+ Rational ratminus4(-4);
+ Rational res = Mod(rat25, rat4);
+ VERIFY_ARE_EQUAL(res, 1);
+ VERIFY_ARE_EQUAL(rat25, 25);
+ VERIFY_ARE_EQUAL(rat4, 4);
+ res = Mod(rat25, ratminus4);
+ VERIFY_ARE_EQUAL(res, -3);
+ VERIFY_ARE_EQUAL(rat25, 25);
+ VERIFY_ARE_EQUAL(ratminus4, -4);
+ res = Mod(ratminus25, ratminus4);
+ VERIFY_ARE_EQUAL(res, -1);
+ VERIFY_ARE_EQUAL(ratminus25, -25);
+ VERIFY_ARE_EQUAL(ratminus4, -4);
+ res = Mod(ratminus25, rat4);
+ VERIFY_ARE_EQUAL(res, 3);
+ VERIFY_ARE_EQUAL(ratminus25, -25);
+ VERIFY_ARE_EQUAL(rat4, 4);
+ }
+
+ TEST_METHOD(TestModuloInteger)
+ {
+ // Check with integers
+ auto res = Mod(Rational(426), Rational(56478));
+ VERIFY_ARE_EQUAL(res, 426);
+ res = Mod(Rational(56478), Rational(426));
+ VERIFY_ARE_EQUAL(res, 246);
+ res = Mod(Rational(-643), Rational(8756));
+ VERIFY_ARE_EQUAL(res, 8113);
+ res = Mod(Rational(643), Rational(-8756));
+ VERIFY_ARE_EQUAL(res, -8113);
+ res = Mod(Rational(-643), Rational(-8756));
+ VERIFY_ARE_EQUAL(res, -643);
+ res = Mod(Rational(1000), Rational(250));
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Mod(Rational(1000), Rational(-250));
+ VERIFY_ARE_EQUAL(res, 0);
+ }
+
+ TEST_METHOD(TestModuloZero)
+ {
+ // Test with Zero
+ auto res = Mod(Rational(343654332), Rational(0));
+ VERIFY_ARE_EQUAL(res, 343654332);
+ res = Mod(Rational(0), Rational(8756));
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Mod(Rational(0), Rational(-242));
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Mod(Rational(0), Rational(0));
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Mod(Rational(Number(1, 0, { 23242 }), Number(1, 0, { 2 })), Rational(Number(1, 0, { 0 }), Number(1, 0, { 23 })));
+ VERIFY_ARE_EQUAL(res, 11621);
+ }
+
+ TEST_METHOD(TestModuloRational)
+ {
+ // Test with rational numbers
+ auto res = Mod(Rational(Number(1, 0, { 250 }), Number(1, 0, { 100 })), Rational(89));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"2.5");
+ res = Mod(Rational(Number(1, 0, { 3330 }), Number(1, 0, { 1332 })), Rational(1));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.5");
+ res = Mod(Rational(Number(1, 0, { 12250 }), Number(1, 0, { 100 })), Rational(10));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"2.5");
+ res = Mod(Rational(Number(-1, 0, { 12250 }), Number(1, 0, { 100 })), Rational(10));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"7.5");
+ res = Mod(Rational(Number(-1, 0, { 12250 }), Number(1, 0, { 100 })), Rational(-10));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-2.5");
+ res = Mod(Rational(Number(1, 0, { 12250 }), Number(1, 0, { 100 })), Rational(-10));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-7.5");
+ res = Mod(Rational(Number(1, 0, { 1000 }), Number(1, 0, { 3 })), Rational(1));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.33333333");
+ res = Mod(Rational(Number(1, 0, { 1000 }), Number(1, 0, { 3 })), Rational(-10));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-6.6666667");
+ res = Mod(Rational(834345), Rational(Number(1, 0, { 103 }), Number(1, 0, { 100 })));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.71");
+ res = Mod(Rational(834345), Rational(Number(-1, 0, { 103 }), Number(1, 0, { 100 })));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-0.32");
+ }
+
+ TEST_METHOD(TestRemainderOperandsNotModified)
+ {
+ //Verify results but also check that operands are not modified
+ Rational rat25(25);
+ Rational ratminus25(-25);
+ Rational rat4(4);
+ Rational ratminus4(-4);
+ Rational res = rat25 % rat4;
+ VERIFY_ARE_EQUAL(res, 1);
+ VERIFY_ARE_EQUAL(rat25, 25);
+ VERIFY_ARE_EQUAL(rat4, 4);
+ res = rat25 % ratminus4;
+ VERIFY_ARE_EQUAL(res, 1);
+ VERIFY_ARE_EQUAL(rat25, 25);
+ VERIFY_ARE_EQUAL(ratminus4, -4);
+ res = ratminus25 % ratminus4;
+ VERIFY_ARE_EQUAL(res, -1);
+ VERIFY_ARE_EQUAL(ratminus25, -25);
+ VERIFY_ARE_EQUAL(ratminus4, -4);
+ res = ratminus25 % rat4;
+ VERIFY_ARE_EQUAL(res, -1);
+ VERIFY_ARE_EQUAL(ratminus25, -25);
+ VERIFY_ARE_EQUAL(rat4, 4);
+ }
+
+ TEST_METHOD(TestRemainderInteger)
+ {
+ // Check with integers
+ auto res = Rational(426) % Rational(56478);
+ VERIFY_ARE_EQUAL(res, 426);
+ res = Rational(56478) % Rational(426);
+ VERIFY_ARE_EQUAL(res, 246);
+ res = Rational(-643) % Rational(8756);
+ VERIFY_ARE_EQUAL(res, -643);
+ res = Rational(643) % Rational(-8756);
+ VERIFY_ARE_EQUAL(res, 643);
+ res = Rational(-643) % Rational(-8756);
+ VERIFY_ARE_EQUAL(res, -643);
+ res = Rational(-124) % Rational(-124);
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Rational(24) % Rational(24);
+ VERIFY_ARE_EQUAL(res, 0);
+ }
+
+ TEST_METHOD(TestRemainderZero)
+ {
+ // Test with Zero
+ auto res = Rational(0) % Rational(3654);
+ VERIFY_ARE_EQUAL(res, 0);
+ res = Rational(0) % Rational(-242);
+ VERIFY_ARE_EQUAL(res, 0);
+ for (auto number : { 343654332, 0, -23423 })
+ {
+ try
+ {
+ res = Rational(number) % Rational(0);
+ Assert::Fail();
+ }
+ catch (uint32_t t)
+ {
+ if (t != CALC_E_INDEFINITE)
+ {
+ Assert::Fail();
+ }
+ }
+ catch (...)
+ {
+ Assert::Fail();
+ }
+
+ try
+ {
+ res = Rational(Number(1, number, { 0 }), Number(1, 0, { 2 })) % Rational(Number(1, 0, { 0 }), Number(1, 0, { 23 }));
+ Assert::Fail();
+ }
+ catch (uint32_t t)
+ {
+ if (t != CALC_E_INDEFINITE)
+ {
+ Assert::Fail();
+ }
+ }
+ catch (...)
+ {
+ Assert::Fail();
+ }
+ }
+ }
+
+ TEST_METHOD(TestRemainderRational)
+ {
+ //Test with rational numbers
+ auto res = Rational(Number(1, 0, { 250 }), Number(1, 0, { 100 })) % Rational(89);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"2.5");
+ res = Rational(Number(1, 0, { 3330 }), Number(1, 0, { 1332 })) % Rational(1);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.5");
+ res = Rational(Number(1, 0, { 12250 }), Number(1, 0, { 100 })) % Rational(10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"2.5");
+ res = Rational(Number(-1, 0, { 12250 }), Number(1, 0, { 100 })) % Rational(10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-2.5");
+ res = Rational(Number(-1, 0, { 12250 }), Number(1, 0, { 100 })) % Rational(-10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-2.5");
+ res = Rational(Number(1, 0, { 12250 }), Number(1, 0, { 100 })) % Rational(-10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"2.5");
+ res = Rational(Number(1, 0, { 1000 }), Number(1, 0, { 3 })) % Rational(1);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.33333333");
+ res = Rational(Number(1, 0, { 1000 }), Number(1, 0, { 3 })) % Rational(-10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"3.3333333");
+ res = Rational(Number(-1, 0, { 1000 }), Number(1, 0, { 3 })) % Rational(-10);
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-3.3333333");
+ res = Rational(834345) % Rational(Number(1, 0, { 103 }), Number(1, 0, { 100 }));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.71");
+ res = Rational(834345) % Rational(Number(-1, 0, { 103 }), Number(1, 0, { 100 }));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"0.71");
+ res = Rational(-834345) % Rational(Number(1, 0, { 103 }), Number(1, 0, { 100 }));
+ VERIFY_ARE_EQUAL(res.ToString(10, FMT_FLOAT, 8), L"-0.71");
+ }
+ };
+}
diff --git a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.cpp b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.cpp
index 1df945c7..42a9526e 100644
--- a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.cpp
+++ b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.cpp
@@ -454,61 +454,48 @@ namespace CalculatorUnitTests
// Call count is being set to 1 because we send 'CE' command as the first call
UINT callCount = 1;
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Zero);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Zero);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Zero == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::One);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::One);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::One == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Two);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Two);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Two == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Three);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Three);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Three == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Four);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Four);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Four == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Five);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Five);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Five == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Six);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Six);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Six == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Seven);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Seven);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Seven == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Eight);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Eight);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Eight == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Nine);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Nine);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Nine == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Decimal);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Decimal);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Decimal == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Negate);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Negate);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Negate == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Backspace);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Backspace);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Backspace == mock->m_lastCommand);
- vm.ButtonPressed->Execute(CalculatorApp::NumbersAndOperatorsEnum::Clear);
+ vm.ButtonPressed->Execute(NumbersAndOperatorsEnum::Clear);
VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
VERIFY_IS_TRUE(UCM::Command::Clear == mock->m_lastCommand);
-
- for (NumbersAndOperatorsEnum button = NumbersAndOperatorsEnum::Add; button <= NumbersAndOperatorsEnum::None; button++)
- {
- if (button == NumbersAndOperatorsEnum::Decimal ||
- button == NumbersAndOperatorsEnum::Negate ||
- button == NumbersAndOperatorsEnum::Backspace)
- {
- continue;
- }
- vm.ButtonPressed->Execute(button);
- VERIFY_ARE_EQUAL(++callCount, mock->m_sendCommandCallCount);
- VERIFY_IS_TRUE(UCM::Command::None == mock->m_lastCommand);
- }
}
// Tests that when we fire the OnGotFocus, it activates the given control
diff --git a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h
index 1e1b57c8..903fd074 100644
--- a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h
+++ b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h
@@ -42,11 +42,14 @@ namespace CalculatorUnitTests
void SendCommand(UCM::Command command) override;
void SetViewModelCallback(const std::shared_ptr& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& /*newCallback*/) override {}
+ void Calculate() override {}
+ void ResetCategoriesAndRatios() override{}
concurrency::task> RefreshCurrencyRatios() override
{
- co_return std::make_pair(L"", L"");
+ co_return std::make_pair(true, L"");
}
+
UINT m_initCallCount;
UINT m_getCategoriesCallCount;
UINT m_setCurrentCategoryCallCount;