From d3da7e0f224595f5882a09e96139696fd9d2e9eb Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 20 Apr 2025 01:19:08 -0700 Subject: [PATCH 01/25] Decimal data type --- WindowsAppRuntime.sln | 1 + dev/Common/TerminalVelocityFeatures-Decimal.h | 32 + .../TerminalVelocityFeatures-Decimal.xml | 20 + dev/Decimal/Decimal.idl | 18 + dev/Decimal/Decimal.vcxitems | 31 + dev/Decimal/Decimal.vcxitems.filters | 32 + dev/Decimal/DecimalTelemetry.h | 21 + dev/Decimal/M.W.F.Decimal.cpp | 21 + dev/Decimal/M.W.F.Decimal.h | 28 + dev/Decimal/decimal.h | 547 ++++++++++++++++++ dev/Decimal/pch.h | 16 + .../WindowsAppRuntime_DLL.vcxproj | 3 +- test/Decimal/DecimalTests.cpp | 345 +++++++++++ test/Decimal/DecimalTests.vcxproj | 158 +++++ test/Decimal/DecimalTests.vcxproj.filters | 33 ++ test/Decimal/Test.testdef | 11 + test/Decimal/packages.config | 9 + test/Decimal/pch.cpp | 6 + test/Decimal/pch.h | 26 + 19 files changed, 1357 insertions(+), 1 deletion(-) create mode 100644 dev/Common/TerminalVelocityFeatures-Decimal.h create mode 100644 dev/Common/TerminalVelocityFeatures-Decimal.xml create mode 100644 dev/Decimal/Decimal.idl create mode 100644 dev/Decimal/Decimal.vcxitems create mode 100644 dev/Decimal/Decimal.vcxitems.filters create mode 100644 dev/Decimal/DecimalTelemetry.h create mode 100644 dev/Decimal/M.W.F.Decimal.cpp create mode 100644 dev/Decimal/M.W.F.Decimal.h create mode 100644 dev/Decimal/decimal.h create mode 100644 dev/Decimal/pch.h create mode 100644 test/Decimal/DecimalTests.cpp create mode 100644 test/Decimal/DecimalTests.vcxproj create mode 100644 test/Decimal/DecimalTests.vcxproj.filters create mode 100644 test/Decimal/Test.testdef create mode 100644 test/Decimal/packages.config create mode 100644 test/Decimal/pch.cpp create mode 100644 test/Decimal/pch.h diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index ae249756cb..33e1fca1b6 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -2627,6 +2627,7 @@ Global dev\ApplicationData\ApplicationData.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\BackgroundTask\BackgroundTaskBuilder\BackgroundTaskBuilder.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Common\Common.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 + dev\Decimal\Decimal.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\DynamicDependency\API\DynamicDependency.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Licensing\Licensing.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\PackageManager\API\PackageManager.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 diff --git a/dev/Common/TerminalVelocityFeatures-Decimal.h b/dev/Common/TerminalVelocityFeatures-Decimal.h new file mode 100644 index 0000000000..097136943a --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-Decimal.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT IT + +// INPUT FILE: dev\common\TerminalVelocityFeatures-Decimal.xml +// OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.Foundation -Path dev\common\TerminalVelocityFeatures-Decimal.xml -Output dev\common\TerminalVelocityFeatures-Decimal.h + +#if defined(__midlrt) +namespace features +{ + feature_name Feature_Decimal = { DisabledByDefault, FALSE }; +} +#endif // defined(__midlrt) + +// Feature constants +#define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_FOUNDATION_FEATURE_DECIMAL_ENABLED 1 + +#if defined(__cplusplus) + +namespace Microsoft::Windows::Foundation +{ + +__pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_FOUNDATION_FEATURE_DECIMAL_ENABLED_mismatch", "AlwaysEnabled")) +struct Feature_Decimal +{ + static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_FOUNDATION_FEATURE_DECIMAL_ENABLED == 1; } +}; + +} // namespace Microsoft.Windows.Foundation + +#endif // defined(__cplusplus) diff --git a/dev/Common/TerminalVelocityFeatures-Decimal.xml b/dev/Common/TerminalVelocityFeatures-Decimal.xml new file mode 100644 index 0000000000..a70b9ba6d6 --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-Decimal.xml @@ -0,0 +1,20 @@ + + + + + + + + + + Feature_Decimal + Decimal APIs + AlwaysEnabled + + Preview + Stable + + + diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl new file mode 100644 index 0000000000..33a265a649 --- /dev/null +++ b/dev/Decimal/Decimal.idl @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include + +namespace Microsoft.Windows.Foundation +{ + [contractversion(2)] + apicontract DecimalContract{}; + + [contract(DecimalContract, 1)] + runtimeclass Decimal : Windows.Foundation.IStringable + { + Decimal(); + + Decimal Abs(); + } +} diff --git a/dev/Decimal/Decimal.vcxitems b/dev/Decimal/Decimal.vcxitems new file mode 100644 index 0000000000..19d36c5aca --- /dev/null +++ b/dev/Decimal/Decimal.vcxitems @@ -0,0 +1,31 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {dc453de3-18fd-43e7-8103-20763c8b97c8} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/Decimal/Decimal.vcxitems.filters b/dev/Decimal/Decimal.vcxitems.filters new file mode 100644 index 0000000000..f4db261b5a --- /dev/null +++ b/dev/Decimal/Decimal.vcxitems.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + + diff --git a/dev/Decimal/DecimalTelemetry.h b/dev/Decimal/DecimalTelemetry.h new file mode 100644 index 0000000000..f9b283bbe0 --- /dev/null +++ b/dev/Decimal/DecimalTelemetry.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT license. + +#pragma once + +#include + +DECLARE_TRACELOGGING_CLASS(DecimalTelemetryProvider, + "Microsoft.WindowsAppSDK.DecimalTelemetry", + // {a4ed7638-2f9b-4fdf-a06a-d6cd26ff309d} + (0xa4ed7638, 0x2f9b, 0x4fdf, 0xa0, 0x6a, 0xd6, 0xcd, 0x26, 0xff, 0x30, 0x9d)); + +class DecimalTelemetry : public wil::TraceLoggingProvider +{ + IMPLEMENT_TELEMETRY_CLASS(DecimalTelemetry, DecimalTelemetryProvider); + +public: + + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ToDo, PDT_ProductAndServicePerformance); + END_ACTIVITY_CLASS(); +}; diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp new file mode 100644 index 0000000000..4677c08f95 --- /dev/null +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include "pch.h" + +#include "M.W.F.Decimal.h" +#include "Microsoft.Windows.Foundation.Decimal.g.cpp" + +#include "DecimalTelemetry.h" + +namespace winrt::Microsoft::Windows::Foundation::implementation +{ + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Abs() + { + throw hresult_not_implemented(); + } + hstring Decimal::ToString() + { + throw hresult_not_implemented(); + } +} diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h new file mode 100644 index 0000000000..e423c9bc57 --- /dev/null +++ b/dev/Decimal/M.W.F.Decimal.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#pragma once + +#include "Microsoft.Windows.Foundation.Decimal.g.h" + +#include + +namespace winrt::Microsoft::Windows::Foundation::implementation +{ + struct Decimal : DecimalT + { + Decimal() = default; + + winrt::Microsoft::Windows::Foundation::Decimal Abs(); + hstring ToString(); + + private: + ::Microsoft::Windows::Foundation::decimal m_decimal; + }; +} +namespace winrt::Microsoft::Windows::Foundation::factory_implementation +{ + struct Decimal : DecimalT + { + }; +} diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h new file mode 100644 index 0000000000..b4a3065c69 --- /dev/null +++ b/dev/Decimal/decimal.h @@ -0,0 +1,547 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#pragma once + +#include + +#if !defined(_VC_NODEFAULTLIB) +#pragma comment(linker, "/defaultlib:oleaut32.lib") +#endif + +namespace Microsoft::Windows::Foundation +{ +class decimal +{ +public: + decimal() = default; + ~decimal() = default; + + decimal(const decimal& value) : + m_decimal(value.m_decimal) + { + } + + decimal(const decimal&& value) : + m_decimal(value.m_decimal) + { + m_decimal = DECIMAL{}; + } + + decimal(bool value) + { + THROW_IF_FAILED(::VarDecFromBool(value ? VARIANT_TRUE : VARIANT_FALSE, &m_decimal)); + } + + decimal(char value) + { + THROW_IF_FAILED(::VarDecFromI1(value, &m_decimal)); + } + + decimal(std::int16_t value) + { + THROW_IF_FAILED(::VarDecFromI2(value, &m_decimal)); + } + + decimal(std::int32_t value) + { + THROW_IF_FAILED(::VarDecFromI4(value, &m_decimal)); + } + + decimal(std::int64_t value) + { + THROW_IF_FAILED(::VarDecFromI8(value, &m_decimal)); + } + + decimal(std::uint8_t value) + { + THROW_IF_FAILED(::VarDecFromUI1(value, &m_decimal)); + } + + decimal(std::uint16_t value) + { + THROW_IF_FAILED(::VarDecFromUI2(value, &m_decimal)); + } + + decimal(std::uint32_t value) + { + THROW_IF_FAILED(::VarDecFromUI4(value, &m_decimal)); + } + + decimal(std::uint64_t value) + { + THROW_IF_FAILED(::VarDecFromUI8(value, &m_decimal)); + } + + decimal(float value) + { + THROW_IF_FAILED(::VarDecFromR4(value, &m_decimal)); + } + + decimal(double value) + { + THROW_IF_FAILED(::VarDecFromR8(value, &m_decimal)); + } + + decimal(long value) + { + THROW_IF_FAILED(::VarDecFromI4(value, &m_decimal)); + } + + decimal(unsigned long value) + { + THROW_IF_FAILED(::VarDecFromUI4(value, &m_decimal)); + } + +#if defined(TODO_STRING) + template + decimal(const string_type& value) + { + auto str{ wil::str_raw_ptr(value) }; + THROW_IF_FAILED(::VarDecFromStr(str, GetThreadLocale(), 0, &m_decimal)); + } +#endif // defined(TODO_STRING) + +#if defined(TODO_STRING) + template + decimal(const string_type& value, const LCID locale) + { + auto str{ wil::str_raw_ptr(value) }; + THROW_IF_FAILED(::VarDecFromStr(str, locale, 0, &m_decimal)); + } +#endif // defined(TODO_STRING) + + decimal& operator=(const decimal& value) + { + if (&value != this) + { + m_decimal = value.m_decimal; + } + return *this; + } + + decimal& operator=(const decimal&& value) + { + if (&value != this) + { + m_decimal = value.m_decimal; + m_decimal = DECIMAL{}; + } + return *this; + } + + decimal& operator=(bool value) + { + THROW_IF_FAILED(::VarDecFromBool(value ? VARIANT_TRUE : VARIANT_FALSE, &m_decimal)); + return *this; + } + + decimal& operator=(char value) + { + THROW_IF_FAILED(::VarDecFromI1(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::int16_t value) + { + THROW_IF_FAILED(::VarDecFromI2(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::int32_t value) + { + THROW_IF_FAILED(::VarDecFromI4(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::int64_t value) + { + THROW_IF_FAILED(::VarDecFromI8(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::uint8_t value) + { + THROW_IF_FAILED(::VarDecFromUI1(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::uint16_t value) + { + THROW_IF_FAILED(::VarDecFromUI2(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::uint32_t value) + { + THROW_IF_FAILED(::VarDecFromUI4(value, &m_decimal)); + return *this; + } + + decimal& operator=(std::uint64_t value) + { + THROW_IF_FAILED(::VarDecFromUI8(value, &m_decimal)); + return *this; + } + + decimal& operator=(float value) + { + THROW_IF_FAILED(::VarDecFromR4(value, &m_decimal)); + return *this; + } + + decimal& operator=(double value) + { + THROW_IF_FAILED(::VarDecFromR8(value, &m_decimal)); + return *this; + } + + decimal& operator=(long value) + { + THROW_IF_FAILED(::VarDecFromI4(value, &m_decimal)); + return *this; + } + + decimal& operator=(unsigned long value) + { + THROW_IF_FAILED(::VarDecFromUI4(value, &m_decimal)); + return *this; + } + +#if defined(TODO_STRING) + template + decimal& operator=(const string_type& value) + { + auto str{ wil::str_raw_ptr(value) }; + THROW_IF_FAILED(::VarDecFromStr(str, GetThreadLocale(), 0, &m_decimal)); + } +#endif // defined(TODO_STRING) + + bool to_bool() const + { + VARIANT_BOOL value{}; + THROW_IF_FAILED(::VarBoolFromDec(const_cast(&m_decimal), &value)); + return value; + } + + char to_char() const + { + char value{}; + THROW_IF_FAILED(::VarI1FromDec(const_cast(&m_decimal), &value)); + return value; + } + + std::int16_t to_int16() const + { + std::int16_t value{}; + THROW_IF_FAILED(::VarI2FromDec(const_cast(&m_decimal), &value)); + return value; + } + + std::int32_t to_int32() const + { + return static_cast(to_long()); + } + + std::int64_t to_int64() const + { + std::int64_t value{}; + THROW_IF_FAILED(::VarI8FromDec(const_cast(&m_decimal), &value)); + return value; + } + + std::uint8_t to_uint8() const + { + std::uint8_t value{}; + THROW_IF_FAILED(::VarUI1FromDec(const_cast(&m_decimal), &value)); + return value; + } + + std::uint16_t to_uint16() const + { + std::uint16_t value{}; + THROW_IF_FAILED(::VarUI2FromDec(const_cast(&m_decimal), &value)); + return value; + } + + std::uint32_t to_uint32() const + { + return static_cast(to_ulong()); + } + + std::uint64_t to_uint64() const + { + std::uint64_t value{}; + THROW_IF_FAILED(::VarUI8FromDec(const_cast(&m_decimal), &value)); + return value; + } + + float to_float() const + { + float value{}; + THROW_IF_FAILED(::VarR4FromDec(const_cast(&m_decimal), &value)); + return value; + } + + double to_double() const + { + double value{}; + THROW_IF_FAILED(::VarR8FromDec(const_cast(&m_decimal), &value)); + return value; + } + + long to_long() const + { + long value{}; + THROW_IF_FAILED(::VarI4FromDec(&m_decimal, &value)); + return value; + } + + unsigned long to_ulong() const + { + unsigned long value{}; + THROW_IF_FAILED(::VarUI4FromDec(const_cast(&m_decimal), &value)); + return value; + } + +#if defined(TODO_STRING) + template + string_type to_string() const + { + return to_string(GetThreadLocale()); + } +#endif // defined(TODO_STRING) + +#if defined(TODO_STRING) + template + string_type to_string(const LCID locale) const + { + wil::unique_bstr bstr; + THROW_IF_FAILED(::VarBstrFromDec(&m_decimal, locale, 0, wil::out_param(bstr))); + return wil::make_unique_string(bstr.get()); + } +#endif // defined(TODO_STRING) + + bool operator==(const decimal& value) const + { + return compare(value) == 0; + } + + bool operator==(const double value) const + { + return compare(value) == 0; + } + + bool operator!=(const decimal& value) const + { + return compare(value) != 0; + } + + bool operator!=(const double value) const + { + return compare(value) != 0; + } + + bool operator< (const decimal& value) const + { + return compare(value) < 0; + } + + bool operator< (const double value) const + { + return compare(value) < 0; + } + + bool operator<=(const decimal& value) const + { + return compare(value) <= 0; + } + + bool operator<=(const double value) const + { + return compare(value) <= 0; + } + + bool operator> (const decimal& value) const + { + return compare(value) > 0; + } + + bool operator> (const double value) const + { + return compare(value) > 0; + } + + bool operator>=(const decimal& value) const + { + return compare(value) >= 0; + } + + bool operator>=(const double value) const + { + return compare(value) >= 0; + } + + int compare(const decimal& value) const + { + static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); + static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); + static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); + return ::VarDecCmp(const_cast(&m_decimal), const_cast(&value.m_decimal)) - 1; + } + + int compare(const double value) const + { + static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); + static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); + static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); + return ::VarDecCmpR8(const_cast(&m_decimal), value) - 1; + } + + decimal operator+() const + { + return *this; + } + + decimal operator-() const + { + decimal value{}; + THROW_IF_FAILED(::VarDecNeg(const_cast(&m_decimal), &value.m_decimal)); + return value; + } + + decimal abs() const + { + decimal value{}; + THROW_IF_FAILED(::VarDecAbs(const_cast(&m_decimal), &value.m_decimal)); + return value; + } + + decimal fix() const + { + decimal value{}; + THROW_IF_FAILED(::VarDecFix(const_cast(&m_decimal), &value.m_decimal)); + return value; + } + + decimal integer() const + { + decimal value{}; + THROW_IF_FAILED(::VarDecInt(const_cast(&m_decimal), &value.m_decimal)); + return value; + } + + decimal operator+(const decimal& value) const + { + decimal result{}; + THROW_IF_FAILED(::VarDecAdd(const_cast(&m_decimal), const_cast(&value.m_decimal), &result.m_decimal)); + return result; + } + + decimal& operator+=(const decimal& value) + { + *this = operator+(value); + return *this; + } + + decimal operator-(const decimal& value) const + { + decimal result{}; + THROW_IF_FAILED(::VarDecSub(const_cast(&m_decimal), const_cast(&value.m_decimal), &result.m_decimal)); + return result; + } + + decimal& operator-=(const decimal& value) + { + *this = operator-(value); + return *this; + } + + decimal operator*(const decimal& value) const + { + decimal result{}; + THROW_IF_FAILED(::VarDecMul(const_cast(&m_decimal), const_cast(&value.m_decimal), &result.m_decimal)); + return result; + } + + decimal& operator*=(const decimal& value) + { + *this = operator*(value); + return *this; + } + + decimal operator/(const decimal& value) const + { + decimal result{}; + THROW_IF_FAILED(::VarDecDiv(const_cast(&m_decimal), const_cast(&value.m_decimal), &result.m_decimal)); + return result; + } + + decimal& operator/=(const decimal& value) + { + *this = operator/(value); + return *this; + } + + decimal operator%(const decimal& value) const + { + VARIANT left{}; + left.vt = VT_DECIMAL; + left.decVal = m_decimal; + + VARIANT right{}; + right.vt = VT_DECIMAL; + right.decVal = value.m_decimal; + + VARIANT result{}; + THROW_IF_FAILED(::VarMod(&left, &right, &result)); + return decimal(result.decVal); + } + + decimal& operator%=(const decimal& value) + { + *this = operator%(value); + return *this; + } + + decimal round(const std::int32_t decimalPlaces) const + { + decimal value{}; + THROW_IF_FAILED(::VarDecRound(const_cast(&m_decimal), decimalPlaces, &value.m_decimal)); + return value; + } +private: + decimal(const DECIMAL& value) : + m_decimal(value) + { + } + +private: + DECIMAL m_decimal{}; +}; +} + +inline Microsoft::Windows::Foundation::decimal operator+(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) +{ + return left.operator+(right); +} + +inline Microsoft::Windows::Foundation::decimal operator-(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) +{ + return left.operator+(right); +} + +inline Microsoft::Windows::Foundation::decimal operator*(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) +{ + return left.operator+(right); +} + +inline Microsoft::Windows::Foundation::decimal operator/(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) +{ + return left.operator+(right); +} + +inline Microsoft::Windows::Foundation::decimal operator%(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) +{ + return left.operator+(right); +} diff --git a/dev/Decimal/pch.h b/dev/Decimal/pch.h new file mode 100644 index 0000000000..dbe88742de --- /dev/null +++ b/dev/Decimal/pch.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#pragma once + +#include + +#include + +#include +#include +#include +#include + +#include +#include diff --git a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj index c5ac889f59..a0b5a2c924 100644 --- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj +++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj @@ -106,6 +106,7 @@ + @@ -330,4 +331,4 @@ - \ No newline at end of file + diff --git a/test/Decimal/DecimalTests.cpp b/test/Decimal/DecimalTests.cpp new file mode 100644 index 0000000000..ec4b896caa --- /dev/null +++ b/test/Decimal/DecimalTests.cpp @@ -0,0 +1,345 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include "pch.h" + +#include + +namespace TD = ::Test::Diagnostics; +namespace TB = ::Test::Bootstrap; +namespace TP = ::Test::Packages; +namespace TD = ::Test::Diagnostics; + +static const winrt::hstring null_hstring; + +namespace Test::ApplicationData::Tests +{ + class ApplicationDataTests + { + public: + BEGIN_TEST_CLASS(ApplicationDataTests) + TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") + TEST_CLASS_PROPERTY(L"RunAs", L"RestrictedUser") + END_TEST_CLASS() + + TEST_CLASS_SETUP(ClassSetup) + { + ::TD::DumpExecutionContext(); + ::TB::Setup(); + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + ::TB::Cleanup(); + return true; + } + + TEST_METHOD(ctor) + { + const std::int64_t data{}; + Microsoft::Windows::Foundation::decimal decimal; + const auto value{ decimal.to_int64() }; + VERIFY_ARE_EQUAL(data, value); + } + + TEST_METHOD(ctor_to_assign_bool) + { + const bool data{ true }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_bool() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_bool() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_char) + { + const char data{ -123 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_char() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_char() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_int16) + { + const std::uint16_t data{ -32109 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_int16() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_int16() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_int32) + { + const std::int32_t data{ -1234567890 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_int32() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_int32() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_int64) + { + const std::int64_t data{ 0x8000000000000000 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_int64() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_int64() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_uint8) + { + const std::uint8_t data{ 123 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_uint8() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_uint16() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_uint16) + { + const std::uint16_t data{ 32109 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_uint16() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_uint16() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_uint32) + { + const std::uint32_t data{ 1234567890 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_uint32() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_uint32() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_uint64) + { + const std::uint64_t data{ 0x7FFFFFFFFFFFFFFF }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_uint64() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_uint64() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_float) + { + const float data{ -1.25 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_float() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_float() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_double) + { + const double data{ -1.25 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_double() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_double() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_long) + { + const long data{ -1234567890 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_long() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_long() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_ulong) + { + const unsigned long data{ 1234567890 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_ulong() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to{ object.to_ulong() }; + VERIFY_ARE_EQUAL(data, to); + } + + TEST_METHOD(ctor_to_assign_string) + { + //TODO + } + + TEST_METHOD(compare_bool) + { + //TODO + } + + TEST_METHOD(compare_char) + { + //TODO + } + + TEST_METHOD(compare_int16) + { + //TODO + } + + TEST_METHOD(compare_int32) + { + //TODO + } + + TEST_METHOD(compare_int64) + { + //TODO + } + + TEST_METHOD(compare_uint8) + { + //TODO + } + + TEST_METHOD(compare_uint16) + { + //TODO + } + + TEST_METHOD(compare_uint32) + { + //TODO + } + + TEST_METHOD(compare_uint64) + { + //TODO + } + + TEST_METHOD(compare_float) + { + //TODO + } + + TEST_METHOD(compare_double) + { + //TODO + } + + TEST_METHOD(compare_long) + { + //TODO + } + + TEST_METHOD(compare_ulong) + { + //TODO + } + + TEST_METHOD(compare_string) + { + //TODO + } + + TEST_METHOD(operator_pos) + { + //TODO + } + + TEST_METHOD(operator_neg) + { + //TODO + } + + TEST_METHOD(abs) + { + //TODO + } + + TEST_METHOD(fix) + { + //TODO + } + + TEST_METHOD(integer) + { + //TODO + } + + TEST_METHOD(operator_add) + { + //TODO + } + + TEST_METHOD(operator_subtract) + { + //TODO + } + + TEST_METHOD(operator_multiply) + { + //TODO + } + + TEST_METHOD(operator_divide) + { + //TODO + } + + TEST_METHOD(operator_modulo) + { + //TODO + } + + TEST_METHOD(operator_round) + { + //TODO + } + }; +} diff --git a/test/Decimal/DecimalTests.vcxproj b/test/Decimal/DecimalTests.vcxproj new file mode 100644 index 0000000000..e5a6214b6b --- /dev/null +++ b/test/Decimal/DecimalTests.vcxproj @@ -0,0 +1,158 @@ + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 16.0 + {4CBAF81E-F2F2-437c-BE4B-8F457DA572AA} + Win32Proj + DecimalTests + 10.0 + NativeUnitTestProject + DecimalTests + + + DynamicLibrary + false + v143 + Unicode + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + Use + true + pch.h + $(RepoRoot)\test\inc;$(RepoRoot)\dev\common;$(VCInstallDir)UnitTest\include;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)\..\WindowsAppRuntime_BootstrapDLL;%(AdditionalIncludeDirectories) + $(RepoRoot);%(AdditionalIncludeDirectories) + + + Windows + onecore.lib;onecoreuap.lib;Microsoft.WindowsAppRuntime.lib;wex.common.lib;wex.logger.lib;te.common.lib;%(AdditionalDependencies) + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories);$(OutDir)\..\WindowsAppRuntime_DLL + Microsoft.WindowsAppRuntime.Bootstrap.dll;%(DelayLoadDLLs) + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + WIN32;%(PreprocessorDefinitions) + + + + + Create + + + + + + + + + + + + $(OutDir)\..\WindowsAppRuntime_DLL\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd + true + + + + + + + + {f76b776e-86f5-48c5-8fc7-d2795ecc9746} + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + diff --git a/test/Decimal/DecimalTests.vcxproj.filters b/test/Decimal/DecimalTests.vcxproj.filters new file mode 100644 index 0000000000..17872adfc2 --- /dev/null +++ b/test/Decimal/DecimalTests.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + + + + diff --git a/test/Decimal/Test.testdef b/test/Decimal/Test.testdef new file mode 100644 index 0000000000..dc7f2ef914 --- /dev/null +++ b/test/Decimal/Test.testdef @@ -0,0 +1,11 @@ +{ + "Tests": [ + { + "Description": "DecimalTests tests for feature Decimal", + "Filename": "DecimalTests.dll", + "Parameters": "", + "Architectures": ["x86", "x64", "arm64"], + "Status": "Enabled" + } + ] +} diff --git a/test/Decimal/packages.config b/test/Decimal/packages.config new file mode 100644 index 0000000000..0c13ff7b9c --- /dev/null +++ b/test/Decimal/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/Decimal/pch.cpp b/test/Decimal/pch.cpp new file mode 100644 index 0000000000..f59e66e263 --- /dev/null +++ b/test/Decimal/pch.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" diff --git a/test/Decimal/pch.h b/test/Decimal/pch.h new file mode 100644 index 0000000000..1d9596445a --- /dev/null +++ b/test/Decimal/pch.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#ifndef PCH_H +#define PCH_H + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#endif //PCH_H From e01ff64e515f279594cacfa44cf2b7794ac8bc71 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 20 Apr 2025 01:26:53 -0700 Subject: [PATCH 02/25] Added tests --- WindowsAppRuntime.sln | 22 +++++++ test/Decimal/DecimalTests.cpp | 58 +++++++++---------- test/inc/WindowsAppRuntime.Test.Diagnostics.h | 1 + 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 33e1fca1b6..555283a478 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -685,6 +685,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StoragePickers", "dev\Inter EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StoragePickersTests", "test\StoragePickersTests\StoragePickersTests.vcxproj", "{85C86306-46D1-4563-8303-0A79DF923586}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTests", "test\Decimal\DecimalTests.vcxproj", "{4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2387,6 +2391,22 @@ Global {85C86306-46D1-4563-8303-0A79DF923586}.Release|x64.Build.0 = Release|x64 {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.ActiveCfg = Release|Win32 {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.Build.0 = Release|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.Build.0 = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.Build.0 = Debug|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.ActiveCfg = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.Build.0 = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.ActiveCfg = Debug|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.Build.0 = Debug|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.ActiveCfg = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.Build.0 = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.ActiveCfg = Release|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.Build.0 = Release|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.ActiveCfg = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.Build.0 = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.ActiveCfg = Release|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2595,6 +2615,8 @@ Global {8E01AA4F-A16A-4E3F-A59F-6D49422B4410} = {716C26A0-E6B0-4981-8412-D14A4D410531} {A39E7B2F-5F67-47DD-8443-531D095CA7F3} = {3B706C5C-55E0-4B76-BF59-89E20FE46795} {85C86306-46D1-4563-8303-0A79DF923586} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/test/Decimal/DecimalTests.cpp b/test/Decimal/DecimalTests.cpp index ec4b896caa..585a593824 100644 --- a/test/Decimal/DecimalTests.cpp +++ b/test/Decimal/DecimalTests.cpp @@ -52,8 +52,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_bool() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_bool() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_char) @@ -65,21 +65,21 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_char() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_char() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_int16) { - const std::uint16_t data{ -32109 }; + const std::int16_t data{ -32109}; Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_int16() }; VERIFY_ARE_EQUAL(data, to); Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_int16() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_int16() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_int32) @@ -91,21 +91,21 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_int32() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_int32() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_int64) { - const std::int64_t data{ 0x8000000000000000 }; + const std::int64_t data{ -1234567890123456789 }; Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_int64() }; VERIFY_ARE_EQUAL(data, to); Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_int64() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_int64() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_uint8) @@ -117,8 +117,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_uint16() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_uint16() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_uint16) @@ -130,8 +130,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_uint16() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_uint16() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_uint32) @@ -143,21 +143,21 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_uint32() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_uint32() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_uint64) { - const std::uint64_t data{ 0x7FFFFFFFFFFFFFFF }; + const std::uint64_t data{ 0xFEDCBA0987654321 }; Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_uint64() }; VERIFY_ARE_EQUAL(data, to); Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_uint64() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_uint64() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_float) @@ -169,8 +169,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_float() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_float() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_double) @@ -182,8 +182,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_double() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_double() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_long) @@ -195,8 +195,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_long() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_long() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_ulong) @@ -208,8 +208,8 @@ namespace Test::ApplicationData::Tests Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to{ object.to_ulong() }; - VERIFY_ARE_EQUAL(data, to); + const auto to2{ object.to_ulong() }; + VERIFY_ARE_EQUAL(data, to2); } TEST_METHOD(ctor_to_assign_string) diff --git a/test/inc/WindowsAppRuntime.Test.Diagnostics.h b/test/inc/WindowsAppRuntime.Test.Diagnostics.h index 9d546c3510..54c766fb53 100644 --- a/test/inc/WindowsAppRuntime.Test.Diagnostics.h +++ b/test/inc/WindowsAppRuntime.Test.Diagnostics.h @@ -7,6 +7,7 @@ #include #include +#include #include From 38aca21cb27b4d98c660eeeb62b052d66fc652f4 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 21 Apr 2025 01:33:37 -0700 Subject: [PATCH 03/25] More fixes and tests. Modulo () is horked, needs work --- dev/Decimal/decimal.h | 185 ++-- test/Decimal/DecimalTests.cpp | 997 +++++++++++++++++++- test/inc/WindowsAppRuntime.Test.Bootstrap.h | 8 +- 3 files changed, 1078 insertions(+), 112 deletions(-) diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index b4a3065c69..edebe10441 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -30,7 +30,16 @@ class decimal decimal(bool value) { - THROW_IF_FAILED(::VarDecFromBool(value ? VARIANT_TRUE : VARIANT_FALSE, &m_decimal)); + // VARIANT_TRUE is weird by today's standards: + // typedef short VARIANT_BOOL; + // #define VARIANT_TRUE ((VARIANT_BOOL) 0xffff) + // #define VARIANT_FALSE ((VARIANT_BOOL) 0) + // Thus + // VarDecFromBool(VARIANT_TRUE) == -1 + // VarDecFromBool(VARIANT_FALSE) == 0 + // But decimal(true) would be expected to be 1 (not -1) + // So we intentionally ignore VarDecFromBool() and treat decimal(bool) == 0 or 1 + THROW_IF_FAILED(::VarDecFromUI4(value ? 1 : 0, &m_decimal)); } decimal(char value) @@ -93,23 +102,39 @@ class decimal THROW_IF_FAILED(::VarDecFromUI4(value, &m_decimal)); } -#if defined(TODO_STRING) - template - decimal(const string_type& value) + decimal(PCWSTR value) { - auto str{ wil::str_raw_ptr(value) }; - THROW_IF_FAILED(::VarDecFromStr(str, GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value, GetThreadLocale(), 0, &m_decimal)); } -#endif // defined(TODO_STRING) -#if defined(TODO_STRING) - template - decimal(const string_type& value, const LCID locale) + decimal(PCWSTR value, const LCID locale) { - auto str{ wil::str_raw_ptr(value) }; - THROW_IF_FAILED(::VarDecFromStr(str, locale, 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value, locale, 0, &m_decimal)); } -#endif // defined(TODO_STRING) + + decimal(const std::wstring& value) + { + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), GetThreadLocale(), 0, &m_decimal)); + } + + decimal(const std::wstring& value, const LCID locale) + { + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), locale, 0, &m_decimal)); + } + +#if defined(WINRT_BASE_H) + decimal(const winrt::hstring& value) + { + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), GetThreadLocale(), 0, &m_decimal)); + } +#endif // defined(WINRT_BASE_H) + +#if defined(WINRT_BASE_H) + decimal(const winrt::hstring& value, const LCID locale) + { + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), locale, 0, &m_decimal)); + } +#endif // defined(WINRT_BASE_H) decimal& operator=(const decimal& value) { @@ -132,7 +157,16 @@ class decimal decimal& operator=(bool value) { - THROW_IF_FAILED(::VarDecFromBool(value ? VARIANT_TRUE : VARIANT_FALSE, &m_decimal)); + // VARIANT_TRUE is weird by today's standards: + // typedef short VARIANT_BOOL; + // #define VARIANT_TRUE ((VARIANT_BOOL) 0xffff) + // #define VARIANT_FALSE ((VARIANT_BOOL) 0) + // Thus + // VarDecFromBool(VARIANT_TRUE) == -1 + // VarDecFromBool(VARIANT_FALSE) == 0 + // But decimal(true) would be expected to be 1 (not -1) + // So we intentionally ignore VarDecFromBool() and treat decimal(bool) == 0 or 1 + THROW_IF_FAILED(::VarDecFromUI4(value ? 1 : 0, &m_decimal)); return *this; } @@ -208,20 +242,28 @@ class decimal return *this; } -#if defined(TODO_STRING) - template - decimal& operator=(const string_type& value) + decimal& operator=(PCWSTR value) { - auto str{ wil::str_raw_ptr(value) }; - THROW_IF_FAILED(::VarDecFromStr(str, GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value, GetThreadLocale(), 0, &m_decimal)); + return *this; } -#endif // defined(TODO_STRING) + + decimal& operator=(const std::wstring& value) + { + return operator=(value.c_str()); + } + +#if defined(WINRT_BASE_H) + decimal& operator=(const winrt::hstring& value) + { + return operator=(value.c_str()); + } +#endif // defined(WINRT_BASE_H) bool to_bool() const { - VARIANT_BOOL value{}; - THROW_IF_FAILED(::VarBoolFromDec(const_cast(&m_decimal), &value)); - return value; + // Treat all values != 0 as true (good) + return m_decimal.Hi32 | m_decimal.Mid32 | m_decimal.Lo32; } char to_char() const @@ -304,40 +346,40 @@ class decimal return value; } -#if defined(TODO_STRING) - template - string_type to_string() const + std::wstring to_string() const { - return to_string(GetThreadLocale()); + return to_string(GetThreadLocale()); } -#endif // defined(TODO_STRING) -#if defined(TODO_STRING) - template - string_type to_string(const LCID locale) const + std::wstring to_string(const LCID locale) const { wil::unique_bstr bstr; THROW_IF_FAILED(::VarBstrFromDec(&m_decimal, locale, 0, wil::out_param(bstr))); - return wil::make_unique_string(bstr.get()); + return std::wstring{ bstr.get() }; } -#endif // defined(TODO_STRING) - bool operator==(const decimal& value) const +#if defined(WINRT_BASE_H) + winrt::hstring to_hstring() const { - return compare(value) == 0; + return to_hstring(GetThreadLocale()); } +#endif // defined(WINRT_BASE_H) - bool operator==(const double value) const +#if defined(WINRT_BASE_H) + winrt::hstring to_hstring(const LCID locale) const { - return compare(value) == 0; + wil::unique_bstr bstr; + THROW_IF_FAILED(::VarBstrFromDec(&m_decimal, locale, 0, wil::out_param(bstr))); + return winrt::hstring{ bstr.get() }; } +#endif // defined(WINRT_BASE_H) - bool operator!=(const decimal& value) const + bool operator==(const decimal& value) const { - return compare(value) != 0; + return compare(value) == 0; } - bool operator!=(const double value) const + bool operator!=(const decimal& value) const { return compare(value) != 0; } @@ -347,41 +389,21 @@ class decimal return compare(value) < 0; } - bool operator< (const double value) const - { - return compare(value) < 0; - } - bool operator<=(const decimal& value) const { return compare(value) <= 0; } - bool operator<=(const double value) const - { - return compare(value) <= 0; - } - bool operator> (const decimal& value) const { return compare(value) > 0; } - bool operator> (const double value) const - { - return compare(value) > 0; - } - bool operator>=(const decimal& value) const { return compare(value) >= 0; } - bool operator>=(const double value) const - { - return compare(value) >= 0; - } - int compare(const decimal& value) const { static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); @@ -390,14 +412,6 @@ class decimal return ::VarDecCmp(const_cast(&m_decimal), const_cast(&value.m_decimal)) - 1; } - int compare(const double value) const - { - static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); - static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); - static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); - return ::VarDecCmpR8(const_cast(&m_decimal), value) - 1; - } - decimal operator+() const { return *this; @@ -417,6 +431,7 @@ class decimal return value; } + /// Chop to integer. decimal fix() const { decimal value{}; @@ -424,6 +439,7 @@ class decimal return value; } + /// Round down to integer. decimal integer() const { decimal value{}; @@ -485,17 +501,30 @@ class decimal decimal operator%(const decimal& value) const { - VARIANT left{}; - left.vt = VT_DECIMAL; - left.decVal = m_decimal; + // VarMod() operates on I4 (int32) at best (not even I8 aka int64) + // So let's do it the grade school way... + // + // remainder = left % right + // aka + // q = (left / right) + // remainder = left - (right * FIX(left / right) * right) + + static const Microsoft::Windows::Foundation::decimal zero{}; + static const Microsoft::Windows::Foundation::decimal one{ 1 }; + if ((*this == value) || (value == one)) + { + return zero; + } - VARIANT right{}; - right.vt = VT_DECIMAL; - right.decVal = value.m_decimal; + const Microsoft::Windows::Foundation::decimal& left{ *this }; + const Microsoft::Windows::Foundation::decimal& right{ value }; + const bool left_is_negative{ m_decimal.sign != 0 }; - VARIANT result{}; - THROW_IF_FAILED(::VarMod(&left, &right, &result)); - return decimal(result.decVal); + Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; + Microsoft::Windows::Foundation::decimal fix{ quotient.fix() }; + Microsoft::Windows::Foundation::decimal product{ quotient * fix }; + Microsoft::Windows::Foundation::decimal remainder{ left_is_negative ? left + product : left - product }; + return remainder; } decimal& operator%=(const decimal& value) @@ -521,6 +550,7 @@ class decimal }; } +/* inline Microsoft::Windows::Foundation::decimal operator+(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) { return left.operator+(right); @@ -545,3 +575,4 @@ inline Microsoft::Windows::Foundation::decimal operator%(const Microsoft::Window { return left.operator+(right); } +*/ diff --git a/test/Decimal/DecimalTests.cpp b/test/Decimal/DecimalTests.cpp index 585a593824..488e187e65 100644 --- a/test/Decimal/DecimalTests.cpp +++ b/test/Decimal/DecimalTests.cpp @@ -10,14 +10,58 @@ namespace TB = ::Test::Bootstrap; namespace TP = ::Test::Packages; namespace TD = ::Test::Diagnostics; -static const winrt::hstring null_hstring; +namespace WEX::TestExecution +{ + // Teach TAEF how to format a Microsoft::Windows::Foundation::decimal + template <> + class VerifyOutputTraits + { + public: + static WEX::Common::NoThrowString ToString(Microsoft::Windows::Foundation::decimal const& value) + { + const auto s{ value.to_string() }; + return WEX::Common::NoThrowString().Format(L"\"%s\"", s.c_str()); + } + }; + + // Teach TAEF how to compare a Microsoft::Windows::Foundation::decimal + template <> + class VerifyCompareTraits + { + public: + static bool AreEqual(Microsoft::Windows::Foundation::decimal const& expected, Microsoft::Windows::Foundation::decimal const& actual) + { + return expected == actual; + } + + static bool AreSame(Microsoft::Windows::Foundation::decimal const& expected, Microsoft::Windows::Foundation::decimal const& actual) + { + return &expected == &actual; + } + + static bool IsLessThan(Microsoft::Windows::Foundation::decimal const& expectedLess, Microsoft::Windows::Foundation::decimal const& expectedGreater) + { + return expectedLess < expectedGreater; + } + + static bool IsGreaterThan(Microsoft::Windows::Foundation::decimal const& expectedGreater, Microsoft::Windows::Foundation::decimal const& expectedLess) + { + return expectedGreater > expectedLess; + } -namespace Test::ApplicationData::Tests + static bool IsNull(Microsoft::Windows::Foundation::decimal const& /*object*/) + { + return false; + } + }; +} + +namespace Test::Decimal::Tests { - class ApplicationDataTests + class DecimalTests { public: - BEGIN_TEST_CLASS(ApplicationDataTests) + BEGIN_TEST_CLASS(DecimalTests) TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") TEST_CLASS_PROPERTY(L"RunAs", L"RestrictedUser") END_TEST_CLASS() @@ -25,7 +69,7 @@ namespace Test::ApplicationData::Tests TEST_CLASS_SETUP(ClassSetup) { ::TD::DumpExecutionContext(); - ::TB::Setup(); + ::TB::Setup(TB::Packages::Framework); return true; } @@ -212,134 +256,1025 @@ namespace Test::ApplicationData::Tests VERIFY_ARE_EQUAL(data, to2); } + TEST_METHOD(ctor_to_assign_pcwstr) + { + PCWSTR data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_string() }; + VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str())); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_string() }; + VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str()), std::format(L"'{}' == '{}'", data, to.c_str()).c_str()); + } + + TEST_METHOD(ctor_to_assign_pcwstr_lcid) + { + PCWSTR data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); + const auto to{ object.to_string(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str())); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_string(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str()), std::format(L"'{}' == '{}'", data, to.c_str()).c_str()); + } + TEST_METHOD(ctor_to_assign_string) { - //TODO + const std::wstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_string() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_string() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(ctor_to_assign_string_lcid) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); + const auto to{ object.to_hstring(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(data, to2); } +#if defined(WINRT_BASE_H) + TEST_METHOD(ctor_to_assign_hstring) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_hstring() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring() }; + VERIFY_ARE_EQUAL(data, to2); + } +#endif // defined(WINRT_BASE_H) + +#if defined(WINRT_BASE_H) + TEST_METHOD(ctor_to_assign_hstring_lcid) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); + const auto to{ object.to_hstring(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(GetSystemDefaultLCID()) }; + VERIFY_ARE_EQUAL(data, to2); + } +#endif // defined(WINRT_BASE_H) + TEST_METHOD(compare_bool) { - //TODO + Microsoft::Windows::Foundation::decimal decimal_false(false); + Microsoft::Windows::Foundation::decimal decimal_true(true); + VERIFY_ARE_EQUAL(0, decimal_false.compare(decimal_false)); + VERIFY_ARE_EQUAL(0, decimal_true.compare(decimal_true)); + VERIFY_ARE_EQUAL(-1, decimal_false.compare(decimal_true)); + VERIFY_ARE_EQUAL(1, decimal_true.compare(decimal_false)); + + VERIFY_IS_TRUE(decimal_true == decimal_true); + VERIFY_IS_FALSE(decimal_true != decimal_true); + VERIFY_IS_FALSE(decimal_true < decimal_true); + VERIFY_IS_TRUE(decimal_true <= decimal_true); + VERIFY_IS_FALSE(decimal_true > decimal_true); + VERIFY_IS_TRUE(decimal_true >= decimal_true); } TEST_METHOD(compare_char) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-123)); + Microsoft::Windows::Foundation::decimal right(static_cast(123)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_int16) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-32109)); + Microsoft::Windows::Foundation::decimal right(static_cast(32109)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_int32) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); + Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_int64) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890123456789)); + Microsoft::Windows::Foundation::decimal right(static_cast(1234567890123456789)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_uint8) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(123)); + Microsoft::Windows::Foundation::decimal right(static_cast(234)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_uint16) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(32109)); + Microsoft::Windows::Foundation::decimal right(static_cast(65432)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_uint32) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); + Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_uint64) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(0x1234567890ABCDEF)); + Microsoft::Windows::Foundation::decimal right(static_cast(0xFEDCBA0987654321)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_float) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); + Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_double) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); + Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_long) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); + Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_ulong) { - //TODO + Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); + Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(compare_string) { - //TODO + Microsoft::Windows::Foundation::decimal left(L"-12.345"); + Microsoft::Windows::Foundation::decimal right(L"12.345"); + VERIFY_ARE_EQUAL(0, left.compare(left)); + VERIFY_ARE_EQUAL(0, right.compare(right)); + VERIFY_ARE_EQUAL(-1, left.compare(right)); + VERIFY_ARE_EQUAL(1, right.compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); } TEST_METHOD(operator_pos) { - //TODO + Microsoft::Windows::Foundation::decimal zero(L"0"); + Microsoft::Windows::Foundation::decimal pos(L"12.345"); + Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + + const auto zero_value{ +zero }; + VERIFY_IS_TRUE(zero_value == zero); + VERIFY_IS_TRUE(zero_value != pos); + VERIFY_IS_TRUE(zero_value != neg); + VERIFY_IS_TRUE(zero_value < pos); + VERIFY_IS_TRUE(zero_value > neg); + + const auto pos_value{ +pos }; + VERIFY_IS_TRUE(pos_value != zero); + VERIFY_IS_TRUE(pos_value == pos); + VERIFY_IS_TRUE(pos_value != neg); + VERIFY_IS_TRUE(pos_value > zero); + VERIFY_IS_TRUE(pos_value > neg); + + const auto neg_value{ +neg }; + VERIFY_IS_TRUE(neg_value != zero); + VERIFY_IS_TRUE(neg_value != pos); + VERIFY_IS_TRUE(neg_value == neg); + VERIFY_IS_TRUE(neg_value < zero); + VERIFY_IS_TRUE(neg_value < pos); } TEST_METHOD(operator_neg) { - //TODO + Microsoft::Windows::Foundation::decimal zero(L"0"); + Microsoft::Windows::Foundation::decimal pos(L"12.345"); + Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + + const auto zero_value{ -zero }; + VERIFY_IS_TRUE(zero_value == zero); + VERIFY_IS_TRUE(zero_value != pos); + VERIFY_IS_TRUE(zero_value != neg); + VERIFY_IS_TRUE(zero_value < pos); + VERIFY_IS_TRUE(zero_value > neg); + + const auto pos_value{ -neg }; + VERIFY_IS_TRUE(pos_value != zero); + VERIFY_IS_TRUE(pos_value == pos); + VERIFY_IS_TRUE(pos_value != neg); + VERIFY_IS_TRUE(pos_value > zero); + VERIFY_IS_TRUE(pos_value > neg); + + const auto neg_value{ -pos }; + VERIFY_IS_TRUE(neg_value != zero); + VERIFY_IS_TRUE(neg_value != pos); + VERIFY_IS_TRUE(neg_value == neg); + VERIFY_IS_TRUE(neg_value < zero); + VERIFY_IS_TRUE(neg_value < pos); } TEST_METHOD(abs) { - //TODO + Microsoft::Windows::Foundation::decimal zero(L"0"); + Microsoft::Windows::Foundation::decimal pos(L"12.345"); + Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + + const auto zero_value{ zero.abs() }; + VERIFY_IS_TRUE(zero_value == zero); + VERIFY_IS_TRUE(zero_value != pos); + VERIFY_IS_TRUE(zero_value != neg); + VERIFY_IS_TRUE(zero_value < pos); + VERIFY_IS_TRUE(zero_value > neg); + + const auto pos_value{ pos.abs() }; + VERIFY_IS_TRUE(pos_value != zero); + VERIFY_IS_TRUE(pos_value == pos); + VERIFY_IS_TRUE(pos_value != neg); + VERIFY_IS_TRUE(pos_value > zero); + VERIFY_IS_TRUE(pos_value > neg); + + const auto neg_value{ neg.abs() }; + VERIFY_IS_TRUE(neg_value != zero); + VERIFY_IS_TRUE(neg_value == pos); + VERIFY_IS_TRUE(neg_value != neg); + VERIFY_IS_TRUE(neg_value > zero); + VERIFY_IS_TRUE(neg_value == pos); } TEST_METHOD(fix) { - //TODO + Microsoft::Windows::Foundation::decimal zero(L"0"); + const auto value{ zero.fix() }; + VERIFY_IS_TRUE(value == zero); + + Microsoft::Windows::Foundation::decimal pos(L"12.345"); + Microsoft::Windows::Foundation::decimal pos_fix(L"12"); + const auto pos_value{ pos.fix() }; + VERIFY_IS_TRUE(pos_value == pos_fix); + + Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + Microsoft::Windows::Foundation::decimal neg_fix(L"-12"); + const auto neg_value{ neg.fix() }; + VERIFY_IS_TRUE(neg_value == neg_fix); } TEST_METHOD(integer) { - //TODO + Microsoft::Windows::Foundation::decimal zero(L"0"); + const auto value{ zero.integer() }; + VERIFY_IS_TRUE(value == zero); + + Microsoft::Windows::Foundation::decimal pos(L"12.345"); + Microsoft::Windows::Foundation::decimal pos_integer(L"12"); + const auto pos_value{ pos.integer() }; + VERIFY_IS_TRUE(pos_value == pos_integer); + + Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + Microsoft::Windows::Foundation::decimal neg_integer(L"-13"); + const auto neg_value{ neg.integer() }; + VERIFY_IS_TRUE(neg_value == neg_integer); } TEST_METHOD(operator_add) { - //TODO + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"3" }, + { L"123", L"4567", L"4690" }, + { L"1", L"-2", L"-1" }, + { L"-1", L"-2", L"-3" }, + { L"-1", L"2", L"1" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"4.65" }, + { L"-1.2", L"3.45", L"2.25" }, + { L"1.2", L"-3.45", L"-2.25" }, + { L"-1.2", L"-3.45", L"-4.65" }, + { L".2", L".45", L".65" }, + { L"-.2", L".45", L".25" }, + { L".2", L"-.45", L"-.25" }, + { L"-.2", L"-.45", L"-.65" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left + right }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s + %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } } TEST_METHOD(operator_subtract) { - //TODO + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"-1" }, + { L"123", L"4567", L"-4444" }, + { L"1", L"-2", L"3" }, + { L"-1", L"-2", L"1" }, + { L"-1", L"2", L"-3" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"-2.25" }, + { L"-1.2", L"3.45", L"-4.65" }, + { L"1.2", L"-3.45", L"4.65" }, + { L"-1.2", L"-3.45", L"2.25" }, + { L".2", L".45", L"-.25" }, + { L"-.2", L".45", L"-.65" }, + { L".2", L"-.45", L".65" }, + { L"-.2", L"-.45", L".25" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left - right }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s - %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } } TEST_METHOD(operator_multiply) { - //TODO + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"2" }, + { L"123", L"4567", L"561741" }, + { L"1", L"-2", L"-2" }, + { L"-1", L"-2", L"2" }, + { L"-1", L"2", L"-2" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"4.140" }, + { L"-1.2", L"3.45", L"-4.140" }, + { L"1.2", L"-3.45", L"-4.140" }, + { L"-1.2", L"-3.45", L"4.140" }, + { L".2", L".45", L"0.090" }, + { L"-.2", L".45", L"-0.090" }, + { L".2", L"-.45", L"-0.090" }, + { L"-.2", L"-.45", L"0.090" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left * right }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s * %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } } TEST_METHOD(operator_divide) { - //TODO + try + { + Microsoft::Windows::Foundation::decimal data{ 123 }; + Microsoft::Windows::Foundation::decimal zero{}; + const auto result{ data / zero }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"0.5" }, + { L"123", L"4567", L"0.0269323407050580249616816291" }, + { L"1", L"-2", L"-0.5" }, + { L"-1", L"-2", L"0.5" }, + { L"-1", L"2", L"-0.5" }, + { L"1.2", L"3.45", L"0.3478260869565217391304347826" }, + { L"-1.2", L"3.45", L"-0.3478260869565217391304347826" }, + { L"1.2", L"-3.45", L"-0.3478260869565217391304347826" }, + { L"-1.2", L"-3.45", L"0.3478260869565217391304347826" }, + { L".2", L".45", L"0.4444444444444444444444444444" }, + { L"-.2", L".45", L"-0.4444444444444444444444444444" }, + { L".2", L"-.45", L"-0.4444444444444444444444444444" }, + { L"-.2", L"-.45", L"0.4444444444444444444444444444" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left / right }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s / %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } } TEST_METHOD(operator_modulo) { - //TODO + try + { + Microsoft::Windows::Foundation::decimal data{ 123 }; + Microsoft::Windows::Foundation::decimal zero{}; + const auto result{ data / zero }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"1" }, + { L"123", L"4567", L"123" }, + { L"1", L"-2", L"1" }, + { L"-1", L"-2", L"-1" }, + { L"-1", L"2", L"-1" }, + { L"1.2", L"3.45", L"1.2" }, + { L"-1.2", L"3.45", L"-1.2" }, + { L"1.2", L"-3.45", L"1.2" }, + { L"-1.2", L"-3.45", L"-1.2" }, + { L".2", L".45", L"0.2" }, + { L"-.2", L".45", L"-0.2" }, + { L".2", L"-.45", L"0.2" }, + { L"-.2", L"-.45", L"-0.2" }, + + { L"2", L"1", L"0" }, + { L"4567", L"123", L"16" }, + { L"-2", L"1", L"0" }, + { L"-2", L"-1", L"0" }, + { L"2", L"-1", L"0" }, + { L"3.45", L"1.2", L"1.05" }, + { L"3.45", L"-1.2", L"1.05" }, + { L"-3.45", L"1.2", L"-1.05" }, + { L"-3.45", L"-1.2", L"-1.05" }, + { L".45", L".2", L"0.05" }, + { L".45", L"-.2", L"0.05" }, + { L"-.45", L".2", L"-0.05" }, + { L"-.45", L"-.2", L"-0.05" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + WEX::Logging::Log::Comment(L"----------"); + + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left % right }; + + Microsoft::Windows::Foundation::decimal zero{ 0 }; + const bool left_is_negative{ left < zero }; + const bool right_is_negative{ right < zero }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"sign=%s %d", left_is_negative ? L"-" : L"+", left.compare(zero))); + + Microsoft::Windows::Foundation::decimal one{ 1 }; + + Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; + Microsoft::Windows::Foundation::decimal fix{ quotient.integer() }; + Microsoft::Windows::Foundation::decimal product{ fix * right.abs() }; + //Microsoft::Windows::Foundation::decimal remainder{ left_is_negative ? left + product : left - product }; + Microsoft::Windows::Foundation::decimal remainder{ left - product }; + if (right.abs() == one) { remainder = zero; } + else if (left_is_negative && !right_is_negative) { remainder += product; } + else if (left_is_negative && right_is_negative) { remainder = -remainder; } + else if (!left_is_negative && right_is_negative) { remainder += product; } + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"l=%s r=%s q=%s f=%s p=%s r=%s", + left.to_string().c_str(), right.to_string().c_str(), quotient.to_string().c_str(), fix.to_string().c_str(), product.to_string().c_str(), remainder.to_string().c_str())); + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s\n== %s - (FIX(%s / %s) * %s)\n== %s - (%s * %s)\n== %s - %s\n==> %s <--> %s %s", + left.to_string().c_str(), right.to_string().c_str(), + left.to_string().c_str(), left.abs().to_string().c_str(), right.abs().to_string().c_str(), right.abs().to_string().c_str(), + left.to_string().c_str(), fix.abs().to_string().c_str(), right.abs().to_string().c_str(), + left.to_string().c_str(), product.abs().to_string().c_str(), + remainder.to_string().c_str(), expected.to_string().c_str(), (remainder == expected ? L"" : L"********************"))); + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s %% %s = %s vs %s", + // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } + + { + Microsoft::Windows::Foundation::decimal zero{}; + Microsoft::Windows::Foundation::decimal one{ 1 }; + + Microsoft::Windows::Foundation::decimal n_1{ L"1" }; + Microsoft::Windows::Foundation::decimal n_2{ L"2" }; + Microsoft::Windows::Foundation::decimal n_2_div_1{ n_2 / n_1 }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_1.to_string().c_str(), n_1.integer().to_string().c_str(), n_1.integer().to_string().c_str())); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_2.to_string().c_str(), n_2.integer().to_string().c_str(), n_2.integer().to_string().c_str())); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_2_div_1.to_string().c_str(), n_2_div_1.integer().to_string().c_str(), n_2_div_1.integer().to_string().c_str())); + + const Microsoft::Windows::Foundation::decimal& left{ n_2 }; + const Microsoft::Windows::Foundation::decimal& right{ n_1 }; + + Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; + Microsoft::Windows::Foundation::decimal fix{ quotient.integer() }; + Microsoft::Windows::Foundation::decimal product{ quotient * fix }; + Microsoft::Windows::Foundation::decimal remainder{ left == right || right == one ? zero : left - product }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"l=%s r=%s q=%s f=%s p=%s r=%s", + left.to_string().c_str(), right.to_string().c_str(), quotient.to_string().c_str(), fix.to_string().c_str(), product.to_string().c_str(), remainder.to_string().c_str())); + + } } TEST_METHOD(operator_round) { - //TODO + Microsoft::Windows::Foundation::decimal n_1_888{ L"1.888" }; + Microsoft::Windows::Foundation::decimal n_neg1_888{ L"-1.888" }; + Microsoft::Windows::Foundation::decimal n_1_25{ L"1.25" }; + Microsoft::Windows::Foundation::decimal n_neg1_25{ L"-1.25" }; + + Microsoft::Windows::Foundation::decimal n_2{ L"2" }; + Microsoft::Windows::Foundation::decimal n_1_9{ L"1.9" }; + Microsoft::Windows::Foundation::decimal n_1_89{ L"1.89" }; + Microsoft::Windows::Foundation::decimal n_neg1_9{ L"1.9" }; + Microsoft::Windows::Foundation::decimal n_neg1_89{ L"1.89" }; + + Microsoft::Windows::Foundation::decimal n_1_888_round_0{ n_1_888.round(0) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", + n_1_888.to_string().c_str(), n_1_888_round_0.to_string().c_str(), n_2.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal n_1_888_round_1{ n_1_888.round(1) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", + n_1_888.to_string().c_str(), n_1_888_round_1.to_string().c_str(), n_1_9.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal n_1_888_round_2{ n_1_888.round(2) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", + n_1_888.to_string().c_str(), n_1_888_round_2.to_string().c_str(), n_1_89.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal n_1_888_round_3{ n_1_888.round(3) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", + n_1_888.to_string().c_str(), n_1_888_round_3.to_string().c_str(), n_1_888.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal n_1_888_round_4{ n_1_888.round(4) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", + n_1_888.to_string().c_str(), n_1_888_round_4.to_string().c_str(), n_1_888.to_string().c_str())); } }; } diff --git a/test/inc/WindowsAppRuntime.Test.Bootstrap.h b/test/inc/WindowsAppRuntime.Test.Bootstrap.h index 306dc56003..1c10e293b1 100644 --- a/test/inc/WindowsAppRuntime.Test.Bootstrap.h +++ b/test/inc/WindowsAppRuntime.Test.Bootstrap.h @@ -149,16 +149,16 @@ namespace Test::Bootstrap s_bootstrapDll.reset(); } - inline void Setup() + inline void Setup(Test::Bootstrap::Packages packagesToSetup = Test::Bootstrap::Packages::Default) { - SetupPackages(); + SetupPackages(packagesToSetup); SetupBootstrap(); } - inline void Cleanup() + inline void Cleanup(Test::Bootstrap::Packages packagesToSetup = Test::Bootstrap::Packages::Default) { CleanupBootstrap(); - CleanupPackages(); + CleanupPackages(packagesToSetup); } } From 7746884ec7396c641bafbd9f79910a3d447b45a7 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 21 Apr 2025 23:23:14 -0700 Subject: [PATCH 04/25] Added dev\Decimal project. Defined Decimal runtimeclass, partially implemented --- WindowsAppRuntime.sln | 6 + dev/Decimal/Decimal.idl | 77 ++++++++++++ dev/Decimal/M.W.F.Decimal.cpp | 220 +++++++++++++++++++++++++++++++++- dev/Decimal/M.W.F.Decimal.h | 84 +++++++++++++ dev/Decimal/decimal.h | 59 ++++----- 5 files changed, 412 insertions(+), 34 deletions(-) diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 555283a478..c600f6e1f2 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -689,6 +689,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{02EA EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTests", "test\Decimal\DecimalTests.vcxproj", "{4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{5012149E-F09F-4F18-A03C-FFE597203821}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2617,6 +2621,8 @@ Global {85C86306-46D1-4563-8303-0A79DF923586} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {5012149E-F09F-4F18-A03C-FFE597203821} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} + {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {5012149E-F09F-4F18-A03C-FFE597203821} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index 33a265a649..afc0e44b7b 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -8,11 +8,88 @@ namespace Microsoft.Windows.Foundation [contractversion(2)] apicontract DecimalContract{}; + [contract(DecimalContract, 1)] + struct DecimalValue + { + UInt16 Reserved; + UInt8 Scale; + UInt8 Sign; + UInt32 Hi32; + UInt64 Lo64; + }; + [contract(DecimalContract, 1)] runtimeclass Decimal : Windows.Foundation.IStringable { Decimal(); + //Decimal(Decimal value); + + static Decimal CreateFromBoolean(Boolean value); + static Decimal CreateFromInt16(Int16 value); + static Decimal CreateFromInt32(Int32 value); + static Decimal CreateFromInt64(Int64 value); + static Decimal CreateFromUInt8(UInt8 value); + static Decimal CreateFromUInt16(UInt16 value); + static Decimal CreateFromUInt32(UInt32 value); + static Decimal CreateFromUInt64(UInt64 value); + static Decimal CreateFromSingle(Single value); + static Decimal CreateFromDouble(Double value); + static Decimal CreateFromString(String value); + static Decimal CreateFromStringWithDefaultSystemLocale(String value); + static Decimal CreateFromStringWithThreadLocale(String value); + static Decimal Create(IInspectable value); + static Decimal CreateFromDecimalValue(DecimalValue value); + + void SetFromBoolean(Boolean value); + void SetFromInt16(Int16 value); + void SetFromInt32(Int32 value); + void SetFromInt64(Int64 value); + void SetFromUInt8(UInt8 value); + void SetFromUInt16(UInt16 value); + void SetFromUInt32(UInt32 value); + void SetFromUInt64(UInt64 value); + void SetFromSingle(Single value); + void SetFromDouble(Double value); + void SetFromString(String value); + void SetFromStringWithDefaultSystemLocale(String value); + void SetFromStringWithThreadLocale(String value); + void Set(IInspectable value); + void SetFromDecimalValue(DecimalValue value); + + Boolean ToBoolean(); + Int16 ToInt16(); + Int32 ToInt32(); + Int64 ToInt64(); + UInt8 ToUInt8(); + UInt16 ToUInt16(); + UInt32 ToUInt32(); + UInt64 ToUInt64(); + Single ToSingle(); + Double ToDouble(); + //String ToString(); inherited from IStringable + String ToStringWithDefaultSystemLocale(); + String ToStringWithThreadLocale(); + IInspectable ToObject(); + DecimalValue ToDecimalValue(); + + Int32 Compare(Decimal value); + + Decimal Negate(); Decimal Abs(); + + /// Return the value's integer portion (zero to the right of the decimal point). + Decimal Fix(); + + /// Return the value rounded down to the nearest integer. + Decimal Integer(); + + Decimal Round(Int32 decimalPlaces); + + Decimal Add(Decimal value); + Decimal Sub(Decimal value); //TODO Subtract() ? + Decimal Mul(Decimal value); //TODO Multiply() ? + Decimal Div(Decimal value); //TODO Divide() ? + Decimal Mod(Decimal value); //TODO Modulo() or Remainder() ? } } diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index 4677c08f95..29cdf54c57 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -10,10 +10,228 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { - winrt::Microsoft::Windows::Foundation::Decimal Decimal::Abs() + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromBoolean(bool value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromInt16(int16_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromInt32(int32_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromInt64(int64_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromUInt8(uint8_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromUInt16(uint16_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromUInt32(uint32_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromUInt64(uint64_t value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromSingle(float value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromDouble(double value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromString(hstring const& value) + { + throw hresult_not_implemented(); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithDefaultSystemLocale(hstring const& value) + { + throw hresult_not_implemented(); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithThreadLocale(hstring const& value) + { + throw hresult_not_implemented(); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Create(winrt::Windows::Foundation::IInspectable const& value) + { + throw hresult_not_implemented(); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) + { + return winrt::make(to_decimal(value)); + } + void Decimal::SetFromBoolean(bool value) + { + m_decimal = value; + } + void Decimal::SetFromInt16(int16_t value) + { + m_decimal = value; + } + void Decimal::SetFromInt32(int32_t value) + { + m_decimal = value; + } + void Decimal::SetFromInt64(int64_t value) + { + m_decimal = value; + } + void Decimal::SetFromUInt8(uint8_t value) + { + m_decimal = value; + } + void Decimal::SetFromUInt16(uint16_t value) + { + m_decimal = value; + } + void Decimal::SetFromUInt32(uint32_t value) + { + m_decimal = value; + } + void Decimal::SetFromUInt64(uint64_t value) + { + m_decimal = value; + } + void Decimal::SetFromSingle(float value) + { + m_decimal = value; + } + void Decimal::SetFromDouble(double value) + { + m_decimal = value; + } + void Decimal::SetFromString(hstring const& value) + { + throw hresult_not_implemented(); + } + void Decimal::SetFromStringWithDefaultSystemLocale(hstring const& value) + { + throw hresult_not_implemented(); + } + void Decimal::SetFromStringWithThreadLocale(hstring const& value) + { + throw hresult_not_implemented(); + } + void Decimal::Set(winrt::Windows::Foundation::IInspectable const& value) + { + throw hresult_not_implemented(); + } + void Decimal::SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) + { + const auto& decimalValue{ *reinterpret_cast(&value) }; + m_decimal = decimalValue; + } + bool Decimal::ToBoolean() + { + return m_decimal.to_bool(); + } + int16_t Decimal::ToInt16() + { + return m_decimal.to_int16(); + } + int32_t Decimal::ToInt32() + { + return m_decimal.to_int32(); + } + int64_t Decimal::ToInt64() + { + return m_decimal.to_int64(); + } + uint8_t Decimal::ToUInt8() + { + return m_decimal.to_uint8(); + } + uint16_t Decimal::ToUInt16() + { + return m_decimal.to_uint16(); + } + uint32_t Decimal::ToUInt32() + { + return m_decimal.to_uint32(); + } + uint64_t Decimal::ToUInt64() + { + return m_decimal.to_uint64(); + } + float Decimal::ToSingle() + { + return m_decimal.to_float(); + } + double Decimal::ToDouble() + { + return m_decimal.to_double(); + } + hstring Decimal::ToStringWithDefaultSystemLocale() + { + throw hresult_not_implemented(); + } + hstring Decimal::ToStringWithThreadLocale() + { + throw hresult_not_implemented(); + } + winrt::Windows::Foundation::IInspectable Decimal::ToObject() { throw hresult_not_implemented(); } + winrt::Microsoft::Windows::Foundation::DecimalValue Decimal::ToDecimalValue() + { + const auto& decimal{ m_decimal.to_decimal() }; + return *reinterpret_cast(&decimal); + } + int32_t Decimal::Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return m_decimal.compare(to_DECIMAL(value.ToDecimalValue())); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Negate() + { + return winrt::make(-m_decimal); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Abs() + { + return winrt::make(m_decimal.abs()); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Fix() + { + return winrt::make(m_decimal.fix()); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Integer() + { + return winrt::make(m_decimal.integer()); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Round(int32_t decimalPlaces) + { + return winrt::make(m_decimal.round(decimalPlaces)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Add(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal + to_decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal - to_decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal * to_decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Div(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal / to_decimal(value)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal % to_decimal(value)); + } hstring Decimal::ToString() { throw hresult_not_implemented(); diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h index e423c9bc57..b5e9a8fafb 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/M.W.F.Decimal.h @@ -9,11 +9,95 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { + inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) + { + return *reinterpret_cast(&value); + } + + inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) + { + return ::Microsoft::Windows::Foundation::decimal{ to_DECIMAL(value) }; + } + + inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return to_decimal(value.ToDecimalValue()); + } + + inline winrt::Microsoft::Windows::Foundation::DecimalValue to_DecimalValue(::Microsoft::Windows::Foundation::decimal const& value) + { + return *reinterpret_cast(&value.to_decimal()); + } + struct Decimal : DecimalT { Decimal() = default; + Decimal(::Microsoft::Windows::Foundation::decimal const& value) : + m_decimal(value) + { + } + + Decimal(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) : + m_decimal(to_DECIMAL(value)) + { + } + + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromBoolean(bool value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromInt16(int16_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromInt32(int32_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromInt64(int64_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromUInt8(uint8_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromUInt16(uint16_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromUInt32(uint32_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromUInt64(uint64_t value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromSingle(float value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDouble(double value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromString(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithDefaultSystemLocale(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithThreadLocale(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal Create(winrt::Windows::Foundation::IInspectable const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); + void SetFromBoolean(bool value); + void SetFromInt16(int16_t value); + void SetFromInt32(int32_t value); + void SetFromInt64(int64_t value); + void SetFromUInt8(uint8_t value); + void SetFromUInt16(uint16_t value); + void SetFromUInt32(uint32_t value); + void SetFromUInt64(uint64_t value); + void SetFromSingle(float value); + void SetFromDouble(double value); + void SetFromString(hstring const& value); + void SetFromStringWithDefaultSystemLocale(hstring const& value); + void SetFromStringWithThreadLocale(hstring const& value); + void Set(winrt::Windows::Foundation::IInspectable const& value); + void SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); + bool ToBoolean(); + int16_t ToInt16(); + int32_t ToInt32(); + int64_t ToInt64(); + uint8_t ToUInt8(); + uint16_t ToUInt16(); + uint32_t ToUInt32(); + uint64_t ToUInt64(); + float ToSingle(); + double ToDouble(); + hstring ToStringWithDefaultSystemLocale(); + hstring ToStringWithThreadLocale(); + winrt::Windows::Foundation::IInspectable ToObject(); + winrt::Microsoft::Windows::Foundation::DecimalValue ToDecimalValue(); + int32_t Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal Negate(); winrt::Microsoft::Windows::Foundation::Decimal Abs(); + winrt::Microsoft::Windows::Foundation::Decimal Fix(); + winrt::Microsoft::Windows::Foundation::Decimal Integer(); + winrt::Microsoft::Windows::Foundation::Decimal Round(int32_t decimalPlaces); + winrt::Microsoft::Windows::Foundation::Decimal Add(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal Div(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value); hstring ToString(); private: diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index edebe10441..2faf9dc10c 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -28,6 +28,11 @@ class decimal m_decimal = DECIMAL{}; } + decimal(const DECIMAL& value) : + m_decimal(value) + { + } + decimal(bool value) { // VARIANT_TRUE is weird by today's standards: @@ -155,6 +160,15 @@ class decimal return *this; } + decimal& operator=(const DECIMAL& value) + { + if (&value != &m_decimal) + { + m_decimal = value; + } + return *this; + } + decimal& operator=(bool value) { // VARIANT_TRUE is weird by today's standards: @@ -260,6 +274,12 @@ class decimal } #endif // defined(WINRT_BASE_H) + const DECIMAL& to_decimal() const + { + // Treat all values != 0 as true (good) + return m_decimal; + } + bool to_bool() const { // Treat all values != 0 as true (good) @@ -405,11 +425,16 @@ class decimal } int compare(const decimal& value) const + { + return compare(value.m_decimal); + } + + int compare(const DECIMAL& value) const { static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); - return ::VarDecCmp(const_cast(&m_decimal), const_cast(&value.m_decimal)) - 1; + return ::VarDecCmp(const_cast(&m_decimal), const_cast(&value)) - 1; } decimal operator+() const @@ -539,40 +564,8 @@ class decimal THROW_IF_FAILED(::VarDecRound(const_cast(&m_decimal), decimalPlaces, &value.m_decimal)); return value; } -private: - decimal(const DECIMAL& value) : - m_decimal(value) - { - } private: DECIMAL m_decimal{}; }; } - -/* -inline Microsoft::Windows::Foundation::decimal operator+(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) -{ - return left.operator+(right); -} - -inline Microsoft::Windows::Foundation::decimal operator-(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) -{ - return left.operator+(right); -} - -inline Microsoft::Windows::Foundation::decimal operator*(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) -{ - return left.operator+(right); -} - -inline Microsoft::Windows::Foundation::decimal operator/(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) -{ - return left.operator+(right); -} - -inline Microsoft::Windows::Foundation::decimal operator%(const Microsoft::Windows::Foundation::decimal& left, const Microsoft::Windows::Foundation::decimal& right) -{ - return left.operator+(right); -} -*/ From f249e4e2fc53dc83ea00eb838062b1be12808d6b Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Tue, 22 Apr 2025 23:35:01 -0700 Subject: [PATCH 05/25] Revised string forms. Added C# projection --- WindowsAppRuntime.sln | 20 ++++ dev/Decimal/Decimal.idl | 24 +++-- dev/Decimal/M.W.F.Decimal.cpp | 53 +++++++--- dev/Decimal/M.W.F.Decimal.h | 12 ++- dev/Decimal/decimal.h | 12 +-- ...osoft.Windows.Foundation.Projection.csproj | 52 +++++++++ test/Decimal/DecimalTests.cpp | 100 ++++++++++++++++-- 7 files changed, 235 insertions(+), 38 deletions(-) create mode 100644 dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index c600f6e1f2..32d86a20ea 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -693,6 +693,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{5012 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Foundation.Projection", "dev\Projections\CS\Microsoft.Windows.Foundation\Microsoft.Windows.Foundation.Projection.csproj", "{8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2411,6 +2413,22 @@ Global {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.Build.0 = Release|x64 {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.ActiveCfg = Release|Win32 {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.Build.0 = Release|Win32 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|Any CPU.Build.0 = Debug|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|ARM64.ActiveCfg = Debug|arm64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|ARM64.Build.0 = Debug|arm64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|x64.ActiveCfg = Debug|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|x64.Build.0 = Debug|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|x86.ActiveCfg = Debug|x86 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|x86.Build.0 = Debug|x86 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|Any CPU.ActiveCfg = Release|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|Any CPU.Build.0 = Release|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|ARM64.ActiveCfg = Release|arm64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|ARM64.Build.0 = Release|arm64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x64.ActiveCfg = Release|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x64.Build.0 = Release|x64 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x86.ActiveCfg = Release|x86 + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2623,6 +2641,7 @@ Global {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {5012149E-F09F-4F18-A03C-FFE597203821} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {5012149E-F09F-4F18-A03C-FFE597203821} + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} = {716C26A0-E6B0-4981-8412-D14A4D410531} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} @@ -2668,6 +2687,7 @@ Global dev\AccessControl\AccessControl.vcxitems*{c91bcb93-9ed1-4acd-85f3-26f9f6ac52e3}*SharedItemsImports = 9 test\inc\inc.vcxitems*{d5667df6-a151-4081-abc7-b93e8e5604ce}*SharedItemsImports = 4 dev\Deployment\Deployment.vcxitems*{db38fb4d-d04f-4c1d-93e0-f8ae259c5fd6}*SharedItemsImports = 9 + dev\Decimal\Decimal.vcxitems*{dc453de3-18fd-43e7-8103-20763c8b97c8}*SharedItemsImports = 9 dev\EnvironmentManager\ChangeTracker\ChangeTracker.vcxitems*{e15c3465-9d45-495d-92ce-b91ef45e8623}*SharedItemsImports = 9 dev\AppLifecycle\AppLifecycle.vcxitems*{e3a522a3-6635-4a42-bded-1af46a15f63c}*SharedItemsImports = 9 dev\VersionInfo\VersionInfo.vcxitems*{e3edec7f-a24e-4766-bb1d-6bdfba157c51}*SharedItemsImports = 9 diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index afc0e44b7b..1e88989e76 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -34,9 +34,11 @@ namespace Microsoft.Windows.Foundation static Decimal CreateFromUInt64(UInt64 value); static Decimal CreateFromSingle(Single value); static Decimal CreateFromDouble(Double value); - static Decimal CreateFromString(String value); - static Decimal CreateFromStringWithDefaultSystemLocale(String value); - static Decimal CreateFromStringWithThreadLocale(String value); + static Decimal CreateFromString(String value); // LCID=LOCALE_INVARIANT + static Decimal CreateFromStringWithSystemDefaultLocale(String value); // LCID=GetSystemDefaultLCID() + static Decimal CreateFromStringWithUserDefaultLocale(String value); // LCID=GetUserDefaultLCID() + static Decimal CreateFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() + static Decimal CreateFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT static Decimal Create(IInspectable value); static Decimal CreateFromDecimalValue(DecimalValue value); @@ -50,9 +52,11 @@ namespace Microsoft.Windows.Foundation void SetFromUInt64(UInt64 value); void SetFromSingle(Single value); void SetFromDouble(Double value); - void SetFromString(String value); - void SetFromStringWithDefaultSystemLocale(String value); - void SetFromStringWithThreadLocale(String value); + void SetFromString(String value); // LCID=LOCALE_INVARIANT + void SetFromStringWithSystemDefaultLocale(String value); // LCID=GetSystemDefaultLCID() + void SetFromStringWithUserDefaultLocale(String value); // LCID=GetUserDefaultLCID() + void SetFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() + void SetFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT void Set(IInspectable value); void SetFromDecimalValue(DecimalValue value); @@ -66,9 +70,11 @@ namespace Microsoft.Windows.Foundation UInt64 ToUInt64(); Single ToSingle(); Double ToDouble(); - //String ToString(); inherited from IStringable - String ToStringWithDefaultSystemLocale(); - String ToStringWithThreadLocale(); + //String ToString(); inherited from IStringable // LCID=LOCALE_INVARIANT + String ToStringWithSystemDefaultLocale(); // LCID=GetSystemDefaultLCID() + String ToStringWithUserDefaultLocale(); // LCID=GetUserDefaultLCID() + String ToStringWithThreadLocale(); // LCID=GetThreadLocale() + String ToStringWithInvariantLocale(); // LCID=LOCALE_INVARIANT IInspectable ToObject(); DecimalValue ToDecimalValue(); diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index 29cdf54c57..dd0438a42b 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -52,15 +52,23 @@ namespace winrt::Microsoft::Windows::Foundation::implementation } winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromString(hstring const& value) { - throw hresult_not_implemented(); + return winrt::make(::Microsoft::Windows::Foundation::decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithDefaultSystemLocale(hstring const& value) + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithSystemDefaultLocale(hstring const& value) { - throw hresult_not_implemented(); + return winrt::make(::Microsoft::Windows::Foundation::decimal(value, LOCALE_SYSTEM_DEFAULT)); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithUserDefaultLocale(hstring const& value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value, LOCALE_USER_DEFAULT)); } winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithThreadLocale(hstring const& value) { - throw hresult_not_implemented(); + return winrt::make(::Microsoft::Windows::Foundation::decimal(value, GetThreadLocale())); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromStringWithInvariantLocale(hstring const& value) + { + return winrt::make(::Microsoft::Windows::Foundation::decimal(value, LOCALE_INVARIANT)); } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Create(winrt::Windows::Foundation::IInspectable const& value) { @@ -112,15 +120,28 @@ namespace winrt::Microsoft::Windows::Foundation::implementation } void Decimal::SetFromString(hstring const& value) { - throw hresult_not_implemented(); + ::Microsoft::Windows::Foundation::decimal decimal{ value }; + m_decimal = decimal; } - void Decimal::SetFromStringWithDefaultSystemLocale(hstring const& value) + void Decimal::SetFromStringWithSystemDefaultLocale(hstring const& value) { - throw hresult_not_implemented(); + ::Microsoft::Windows::Foundation::decimal decimal(value, LOCALE_SYSTEM_DEFAULT); + m_decimal = decimal; + } + void Decimal::SetFromStringWithUserDefaultLocale(hstring const& value) + { + ::Microsoft::Windows::Foundation::decimal decimal(value, LOCALE_USER_DEFAULT); + m_decimal = decimal; } void Decimal::SetFromStringWithThreadLocale(hstring const& value) { - throw hresult_not_implemented(); + ::Microsoft::Windows::Foundation::decimal decimal(value, GetThreadLocale()); + m_decimal = decimal; + } + void Decimal::SetFromStringWithInvariantLocale(hstring const& value) + { + ::Microsoft::Windows::Foundation::decimal decimal(value, LOCALE_INVARIANT); + m_decimal = decimal; } void Decimal::Set(winrt::Windows::Foundation::IInspectable const& value) { @@ -171,13 +192,21 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { return m_decimal.to_double(); } - hstring Decimal::ToStringWithDefaultSystemLocale() + hstring Decimal::ToStringWithSystemDefaultLocale() { - throw hresult_not_implemented(); + return m_decimal.to_hstring(LOCALE_SYSTEM_DEFAULT); + } + hstring Decimal::ToStringWithUserDefaultLocale() + { + return m_decimal.to_hstring(LOCALE_USER_DEFAULT); } hstring Decimal::ToStringWithThreadLocale() { - throw hresult_not_implemented(); + return m_decimal.to_hstring(GetThreadLocale()); + } + hstring Decimal::ToStringWithInvariantLocale() + { + return m_decimal.to_hstring(LOCALE_INVARIANT); } winrt::Windows::Foundation::IInspectable Decimal::ToObject() { @@ -234,6 +263,6 @@ namespace winrt::Microsoft::Windows::Foundation::implementation } hstring Decimal::ToString() { - throw hresult_not_implemented(); + return m_decimal.to_hstring(); } } diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h index b5e9a8fafb..4d205ba5ca 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/M.W.F.Decimal.h @@ -54,8 +54,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation static winrt::Microsoft::Windows::Foundation::Decimal CreateFromSingle(float value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDouble(double value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromString(hstring const& value); - static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithDefaultSystemLocale(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithSystemDefaultLocale(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithUserDefaultLocale(hstring const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithThreadLocale(hstring const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithInvariantLocale(hstring const& value); static winrt::Microsoft::Windows::Foundation::Decimal Create(winrt::Windows::Foundation::IInspectable const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); void SetFromBoolean(bool value); @@ -69,8 +71,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation void SetFromSingle(float value); void SetFromDouble(double value); void SetFromString(hstring const& value); - void SetFromStringWithDefaultSystemLocale(hstring const& value); + void SetFromStringWithSystemDefaultLocale(hstring const& value); + void SetFromStringWithUserDefaultLocale(hstring const& value); void SetFromStringWithThreadLocale(hstring const& value); + void SetFromStringWithInvariantLocale(hstring const& value); void Set(winrt::Windows::Foundation::IInspectable const& value); void SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); bool ToBoolean(); @@ -83,8 +87,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation uint64_t ToUInt64(); float ToSingle(); double ToDouble(); - hstring ToStringWithDefaultSystemLocale(); + hstring ToStringWithSystemDefaultLocale(); + hstring ToStringWithUserDefaultLocale(); hstring ToStringWithThreadLocale(); + hstring ToStringWithInvariantLocale(); winrt::Windows::Foundation::IInspectable ToObject(); winrt::Microsoft::Windows::Foundation::DecimalValue ToDecimalValue(); int32_t Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value); diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index 2faf9dc10c..aafe385de8 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -109,7 +109,7 @@ class decimal decimal(PCWSTR value) { - THROW_IF_FAILED(::VarDecFromStr(value, GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value, LOCALE_INVARIANT, 0, &m_decimal)); } decimal(PCWSTR value, const LCID locale) @@ -119,7 +119,7 @@ class decimal decimal(const std::wstring& value) { - THROW_IF_FAILED(::VarDecFromStr(value.c_str(), GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), LOCALE_INVARIANT, 0, &m_decimal)); } decimal(const std::wstring& value, const LCID locale) @@ -130,7 +130,7 @@ class decimal #if defined(WINRT_BASE_H) decimal(const winrt::hstring& value) { - THROW_IF_FAILED(::VarDecFromStr(value.c_str(), GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value.c_str(), LOCALE_INVARIANT, 0, &m_decimal)); } #endif // defined(WINRT_BASE_H) @@ -258,7 +258,7 @@ class decimal decimal& operator=(PCWSTR value) { - THROW_IF_FAILED(::VarDecFromStr(value, GetThreadLocale(), 0, &m_decimal)); + THROW_IF_FAILED(::VarDecFromStr(value, LOCALE_INVARIANT, 0, &m_decimal)); return *this; } @@ -368,7 +368,7 @@ class decimal std::wstring to_string() const { - return to_string(GetThreadLocale()); + return to_string(LOCALE_INVARIANT); } std::wstring to_string(const LCID locale) const @@ -381,7 +381,7 @@ class decimal #if defined(WINRT_BASE_H) winrt::hstring to_hstring() const { - return to_hstring(GetThreadLocale()); + return to_hstring(LOCALE_INVARIANT); } #endif // defined(WINRT_BASE_H) diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj b/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj new file mode 100644 index 0000000000..25d6902147 --- /dev/null +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj @@ -0,0 +1,52 @@ + + + net6.0-windows10.0.17763.0 + 10.0.17763.0 + x64;x86;arm64 + AnyCPU + false + + + + true + true + + + + + 8305 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + Microsoft.Windows.Foundation + 10.0.17763.0 + false + + + + + pdbonly + true + + + + + + + + + + + diff --git a/test/Decimal/DecimalTests.cpp b/test/Decimal/DecimalTests.cpp index 488e187e65..fceeecc365 100644 --- a/test/Decimal/DecimalTests.cpp +++ b/test/Decimal/DecimalTests.cpp @@ -295,16 +295,55 @@ namespace Test::Decimal::Tests VERIFY_ARE_EQUAL(data, to2); } - TEST_METHOD(ctor_to_assign_string_lcid) + TEST_METHOD(ctor_to_assign_string_lcid_system_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); - const auto to{ object.to_hstring(GetSystemDefaultLCID()) }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); + const auto to{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(ctor_to_assign_string_lcid_user_default) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); + const auto to{ object.to_hstring(LOCALE_USER_DEFAULT) }; VERIFY_ARE_EQUAL(data, to); Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to2{ object.to_hstring(GetSystemDefaultLCID()) }; + const auto to2{ object.to_hstring(LOCALE_USER_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(ctor_to_assign_string_lcid_thread) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); + const auto to{ object.to_hstring(GetThreadLocale()) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(GetThreadLocale()) }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(ctor_to_assign_string_lcid_invariant) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); + const auto to{ object.to_hstring(LOCALE_INVARIANT) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(LOCALE_INVARIANT) }; VERIFY_ARE_EQUAL(data, to2); } @@ -324,16 +363,61 @@ namespace Test::Decimal::Tests #endif // defined(WINRT_BASE_H) #if defined(WINRT_BASE_H) - TEST_METHOD(ctor_to_assign_hstring_lcid) + TEST_METHOD(ctor_to_assign_hstring_lcid_system_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); - const auto to{ object.to_hstring(GetSystemDefaultLCID()) }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); + const auto to{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to2); + } +#endif // defined(WINRT_BASE_H) + +#if defined(WINRT_BASE_H) + TEST_METHOD(ctor_to_assign_hstring_lcid_user_default) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); + const auto to{ object.to_hstring(LOCALE_USER_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(LOCALE_USER_DEFAULT) }; + VERIFY_ARE_EQUAL(data, to2); + } +#endif // defined(WINRT_BASE_H) + +#if defined(WINRT_BASE_H) + TEST_METHOD(ctor_to_assign_hstring_lcid_thread) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); + const auto to{ object.to_hstring(GetThreadLocale()) }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_hstring(GetThreadLocale()) }; + VERIFY_ARE_EQUAL(data, to2); + } +#endif // defined(WINRT_BASE_H) + +#if defined(WINRT_BASE_H) + TEST_METHOD(ctor_to_assign_hstring_lcid_invariant) + { + const winrt::hstring data{ L"-12.345" }; + Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); + const auto to{ object.to_hstring(LOCALE_INVARIANT) }; VERIFY_ARE_EQUAL(data, to); Microsoft::Windows::Foundation::decimal object2; object2 = data; - const auto to2{ object.to_hstring(GetSystemDefaultLCID()) }; + const auto to2{ object.to_hstring(LOCALE_INVARIANT) }; VERIFY_ARE_EQUAL(data, to2); } #endif // defined(WINRT_BASE_H) From 771de16bd9cfbf1fbfb6039c6cc8d52b4426128b Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Wed, 23 Apr 2025 00:53:36 -0700 Subject: [PATCH 06/25] More tests --- WindowsAppRuntime.sln | 74 +++++--- test/Decimal/{ => CPP}/DecimalTests.cpp | 0 test/Decimal/{ => CPP}/DecimalTests.vcxproj | 0 .../{ => CPP}/DecimalTests.vcxproj.filters | 0 test/Decimal/{ => CPP}/Test.testdef | 0 test/Decimal/{ => CPP}/packages.config | 0 test/Decimal/{ => CPP}/pch.cpp | 0 test/Decimal/{ => CPP}/pch.h | 0 test/Decimal/CS/DecimalTest_CS.csproj | 36 ++++ test/Decimal/CS/DotNetTests.cs | 158 ++++++++++++++++++ test/Decimal/CS/Program.cs | 41 +++++ test/Decimal/CS/Verify.cs | 83 +++++++++ test/Decimal/CS/WinAppSDKTests.cs | 18 ++ 13 files changed, 391 insertions(+), 19 deletions(-) rename test/Decimal/{ => CPP}/DecimalTests.cpp (100%) rename test/Decimal/{ => CPP}/DecimalTests.vcxproj (100%) rename test/Decimal/{ => CPP}/DecimalTests.vcxproj.filters (100%) rename test/Decimal/{ => CPP}/Test.testdef (100%) rename test/Decimal/{ => CPP}/packages.config (100%) rename test/Decimal/{ => CPP}/pch.cpp (100%) rename test/Decimal/{ => CPP}/pch.h (100%) create mode 100644 test/Decimal/CS/DecimalTest_CS.csproj create mode 100644 test/Decimal/CS/DotNetTests.cs create mode 100644 test/Decimal/CS/Program.cs create mode 100644 test/Decimal/CS/Verify.cs create mode 100644 test/Decimal/CS/WinAppSDKTests.cs diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 32d86a20ea..ff71c0ac3c 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -687,14 +687,31 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StoragePickersTests", "test EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTests", "test\Decimal\DecimalTests.vcxproj", "{4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{5012149E-F09F-4F18-A03C-FFE597203821}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Foundation.Projection", "dev\Projections\CS\Microsoft.Windows.Foundation\Microsoft.Windows.Foundation.Projection.csproj", "{8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS", "CS", "{AB515C38-1A93-40FE-917B-1998DCEB811C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTests", "test\Decimal\CPP\DecimalTests.vcxproj", "{4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}" + ProjectSection(ProjectDependencies) = postProject + {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} = {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} + {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecimalTest_CS", "test\Decimal\CS\DecimalTest_CS.csproj", "{041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}" + ProjectSection(ProjectDependencies) = postProject + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} = {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} + {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} = {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} + {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} + {D6574FD6-8D13-4412-9FCB-308D44063CDA} = {D6574FD6-8D13-4412-9FCB-308D44063CDA} + {F76B776E-86F5-48C5-8FC7-D2795ECC9746} = {F76B776E-86F5-48C5-8FC7-D2795ECC9746} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2397,22 +2414,6 @@ Global {85C86306-46D1-4563-8303-0A79DF923586}.Release|x64.Build.0 = Release|x64 {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.ActiveCfg = Release|Win32 {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.Build.0 = Release|Win32 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.ActiveCfg = Debug|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.Build.0 = Debug|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.Build.0 = Debug|ARM64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.ActiveCfg = Debug|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.Build.0 = Debug|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.ActiveCfg = Debug|Win32 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.Build.0 = Debug|Win32 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.ActiveCfg = Release|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.Build.0 = Release|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.ActiveCfg = Release|ARM64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.Build.0 = Release|ARM64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.ActiveCfg = Release|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.Build.0 = Release|x64 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.ActiveCfg = Release|Win32 - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.Build.0 = Release|Win32 {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|Any CPU.ActiveCfg = Debug|x64 {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|Any CPU.Build.0 = Debug|x64 {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Debug|ARM64.ActiveCfg = Debug|arm64 @@ -2429,6 +2430,38 @@ Global {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x64.Build.0 = Release|x64 {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x86.ActiveCfg = Release|x86 {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}.Release|x86.Build.0 = Release|x86 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|Any CPU.Build.0 = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|ARM64.Build.0 = Debug|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.ActiveCfg = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x64.Build.0 = Debug|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.ActiveCfg = Debug|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Debug|x86.Build.0 = Debug|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.ActiveCfg = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|Any CPU.Build.0 = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.ActiveCfg = Release|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|ARM64.Build.0 = Release|ARM64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.ActiveCfg = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x64.Build.0 = Release|x64 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.ActiveCfg = Release|Win32 + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA}.Release|x86.Build.0 = Release|Win32 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|Any CPU.Build.0 = Debug|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|ARM64.ActiveCfg = Debug|arm64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|ARM64.Build.0 = Debug|arm64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|x64.ActiveCfg = Debug|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|x64.Build.0 = Debug|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|x86.ActiveCfg = Debug|x86 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Debug|x86.Build.0 = Debug|x86 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|Any CPU.ActiveCfg = Release|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|Any CPU.Build.0 = Release|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|ARM64.ActiveCfg = Release|arm64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|ARM64.Build.0 = Release|arm64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x64.ActiveCfg = Release|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x64.Build.0 = Release|x64 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x86.ActiveCfg = Release|x86 + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2638,10 +2671,13 @@ Global {A39E7B2F-5F67-47DD-8443-531D095CA7F3} = {3B706C5C-55E0-4B76-BF59-89E20FE46795} {85C86306-46D1-4563-8303-0A79DF923586} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} - {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {5012149E-F09F-4F18-A03C-FFE597203821} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {5012149E-F09F-4F18-A03C-FFE597203821} {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} = {716C26A0-E6B0-4981-8412-D14A4D410531} + {7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {AB515C38-1A93-40FE-917B-1998DCEB811C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53} + {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5} = {AB515C38-1A93-40FE-917B-1998DCEB811C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/test/Decimal/DecimalTests.cpp b/test/Decimal/CPP/DecimalTests.cpp similarity index 100% rename from test/Decimal/DecimalTests.cpp rename to test/Decimal/CPP/DecimalTests.cpp diff --git a/test/Decimal/DecimalTests.vcxproj b/test/Decimal/CPP/DecimalTests.vcxproj similarity index 100% rename from test/Decimal/DecimalTests.vcxproj rename to test/Decimal/CPP/DecimalTests.vcxproj diff --git a/test/Decimal/DecimalTests.vcxproj.filters b/test/Decimal/CPP/DecimalTests.vcxproj.filters similarity index 100% rename from test/Decimal/DecimalTests.vcxproj.filters rename to test/Decimal/CPP/DecimalTests.vcxproj.filters diff --git a/test/Decimal/Test.testdef b/test/Decimal/CPP/Test.testdef similarity index 100% rename from test/Decimal/Test.testdef rename to test/Decimal/CPP/Test.testdef diff --git a/test/Decimal/packages.config b/test/Decimal/CPP/packages.config similarity index 100% rename from test/Decimal/packages.config rename to test/Decimal/CPP/packages.config diff --git a/test/Decimal/pch.cpp b/test/Decimal/CPP/pch.cpp similarity index 100% rename from test/Decimal/pch.cpp rename to test/Decimal/CPP/pch.cpp diff --git a/test/Decimal/pch.h b/test/Decimal/CPP/pch.h similarity index 100% rename from test/Decimal/pch.h rename to test/Decimal/CPP/pch.h diff --git a/test/Decimal/CS/DecimalTest_CS.csproj b/test/Decimal/CS/DecimalTest_CS.csproj new file mode 100644 index 0000000000..3a923c9cf6 --- /dev/null +++ b/test/Decimal/CS/DecimalTest_CS.csproj @@ -0,0 +1,36 @@ + + + + Exe + net6.0-windows10.0.19041.0 + x86;x64;arm64 + disable + disable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + pdbonly + true + + + + + + + + + + + diff --git a/test/Decimal/CS/DotNetTests.cs b/test/Decimal/CS/DotNetTests.cs new file mode 100644 index 0000000000..cc72f49ee6 --- /dev/null +++ b/test/Decimal/CS/DotNetTests.cs @@ -0,0 +1,158 @@ +using System; +using Test; + +namespace Test.DotNet +{ + class DecimalTests + { + public static void Run() + { + ctor(); + ctor_to_assign_bool(); + ctor_to_assign_int16(); + ctor_to_assign_int32(); + ctor_to_assign_int64(); + ctor_to_assign_uint8(); + ctor_to_assign_uint16(); + ctor_to_assign_uint32(); + ctor_to_assign_uint64(); + ctor_to_assign_float(); + ctor_to_assign_double(); + ctor_to_assign_string(); + compare_int16(); + } + + public static void ctor() + { + var dec = new Decimal(); + var data = decimal.ToInt64(dec); + Verify.AreEqual(dec, data); + } + + public static void ctor_to_assign_bool() + { + bool data = true; + var dec = new Decimal(data ? 1 : 0); + var to = ((int)dec == 0) ? false : true; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_int16() + { + var data = (short)-123; + var dec = new Decimal(data); + var to = (short)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_int32() + { + var data = (int)-1234567890; + var dec = new Decimal(data); + var to = (int)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_int64() + { + var data = (long)-1234567890123456789; + var dec = new Decimal(data); + var to = (long)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_uint8() + { + var data = (byte)123; + var dec = new Decimal(data); + var to = (byte)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_uint16() + { + var data = (ushort)32109; + var dec = new Decimal(data); + var to = (ushort)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_uint32() + { + var data = (uint)1234567890; + var dec = new Decimal(data); + var to = (uint)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_uint64() + { + var data = (ulong)0xFEDCBA0987654321; + var dec = new Decimal(data); + var to = (ulong)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_float() + { + var data = (float)-1.25; + var dec = new Decimal(data); + var to = (float)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_double() + { + var data = (double)-1.25; + var dec = new Decimal(data); + var to = (double)dec; + Verify.AreEqual(data, to); + } + + public static void ctor_to_assign_string() + { + var data = "-12.345"; + var dec = Decimal.Parse(data); + var to = dec.ToString(); + Verify.AreEqual(data, to); + } + + public static void compare_int16() + { + var left = new Decimal((short)-32109); + var right = new Decimal((short)32109); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + } +} diff --git a/test/Decimal/CS/Program.cs b/test/Decimal/CS/Program.cs new file mode 100644 index 0000000000..f9954367c8 --- /dev/null +++ b/test/Decimal/CS/Program.cs @@ -0,0 +1,41 @@ +using System; +using Test.DotNet; +using Test.WinAppSDK; + +namespace Test +{ + class DecimalTests + { + static void Main(string[] args) + { + if (args.Length == 0) + { + Help(); + } + + foreach (var arg in args) + { + if (arg.Equals("dotnet", StringComparison.OrdinalIgnoreCase)) + { + Test.DotNet.DecimalTests.Run(); + } + else if (arg.Equals("winappsdk", StringComparison.OrdinalIgnoreCase)) + { + Test.WinAppSDK.DecimalTests.Run(); + } + else + { + Help(); + } + } + } + + private static void Help() + { + Console.WriteLine("Usage: DecimalTest_CS \n" + + "where\n" + + " test = dotnet | winappsdk"); + Environment.Exit(1); + } + } +} diff --git a/test/Decimal/CS/Verify.cs b/test/Decimal/CS/Verify.cs new file mode 100644 index 0000000000..daab6502e4 --- /dev/null +++ b/test/Decimal/CS/Verify.cs @@ -0,0 +1,83 @@ +using System; +using System.Diagnostics; + +namespace Test +{ + class Verify + { + public static bool IsTrue(bool value, string message = null) + { + if (value) + { + if (String.IsNullOrEmpty(message)) + { + Console.WriteLine($"Verify: IsTrue ({value})"); + } + else + { + Console.WriteLine($"ERROR: IsTrue ({value}) - {message}"); + } + } + else + { + if (String.IsNullOrEmpty(message)) + { + Console.WriteLine($"ERROR: IsTrue ({value})"); + } + else + { + Console.WriteLine($"ERROR: IsTrue({value}) - {message}"); + } + } + return value; + } + + public static bool IsFalse(bool value, string message = null) + { + if (!value) + { + if (String.IsNullOrEmpty(message)) + { + Console.WriteLine($"Verify: IsFalse ({value})"); + } + else + { + Console.WriteLine($"ERROR: IsFalse ({value}) - {message}"); + } + } + else + { + if (String.IsNullOrEmpty(message)) + { + Console.WriteLine($"ERROR: IsFalse ({value})"); + } + else + { + Console.WriteLine($"ERROR: IsFalse ({value}) - {message}"); + } + } + return !value; + } + + public static bool AreEqual(T left, T right, string message = null) + { + var ok = left.Equals(right); + if (ok) + { + Console.WriteLine($"Verify: AreEqual ({left}, {right})"); + } + else + { + if (String.IsNullOrEmpty(message)) + { + Console.WriteLine($"ERROR: Not equal ({left}, {right})"); + } + else + { + Console.WriteLine($"ERROR: Not equal ({left}, {right}) - {message}"); + } + } + return ok; + } + } +} diff --git a/test/Decimal/CS/WinAppSDKTests.cs b/test/Decimal/CS/WinAppSDKTests.cs new file mode 100644 index 0000000000..e946cf9851 --- /dev/null +++ b/test/Decimal/CS/WinAppSDKTests.cs @@ -0,0 +1,18 @@ +using System; + +namespace Test.WinAppSDK +{ + class DecimalTests + { + public static void Run() + { + } + + private static void ctor() + { + //var decimal = new Microsoft.Windows.Foundation.Decimal(); + //var long data = decimal.to_int64(); + //Verify + } + } +} From b082f76ca0d36f3dbbf31e5b1fe6385a4ff38c01 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Wed, 23 Apr 2025 22:43:44 -0700 Subject: [PATCH 07/25] More work on modulo and tests --- dev/Decimal/decimal.h | 18 ++ test/Decimal/CPP/DecimalTests.cpp | 68 ++++- test/Decimal/CS/DotNetTests.cs | 439 ++++++++++++++++++++++++++++++ 3 files changed, 524 insertions(+), 1 deletion(-) diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index aafe385de8..52fe6e3a2f 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -525,6 +525,24 @@ class decimal } decimal operator%(const decimal& value) const + { + VARIANT left{}; + left.vt = VT_DECIMAL; + left.decVal = m_decimal; + + VARIANT right{}; + right.vt = VT_DECIMAL; + right.decVal = value.m_decimal; + + VARIANT result{}; + THROW_IF_FAILED(::VarMod(&left, &right, &result)); + VARIANT resultAsDecimal{}; + THROW_IF_FAILED(::VariantChangeType(&resultAsDecimal, &result, 0, VT_DECIMAL)); + THROW_HR_IF_MSG(E_UNEXPECTED, resultAsDecimal.vt != VT_DECIMAL, ".vt=%hu", resultAsDecimal.vt); + return Microsoft::Windows::Foundation::decimal{ resultAsDecimal.decVal }; + } + + decimal mod(const decimal& value) const { // VarMod() operates on I4 (int32) at best (not even I8 aka int64) // So let's do it the grade school way... diff --git a/test/Decimal/CPP/DecimalTests.cpp b/test/Decimal/CPP/DecimalTests.cpp index fceeecc365..116d851056 100644 --- a/test/Decimal/CPP/DecimalTests.cpp +++ b/test/Decimal/CPP/DecimalTests.cpp @@ -1211,7 +1211,73 @@ namespace Test::Decimal::Tests } } - TEST_METHOD(operator_modulo) + TEST_METHOD(operator_mod) + { + try + { + Microsoft::Windows::Foundation::decimal data{ 123 }; + Microsoft::Windows::Foundation::decimal zero{}; + const auto result{ data / zero }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"1" }, + { L"123", L"4567", L"123" }, + { L"1", L"-2", L"1" }, + { L"-1", L"-2", L"-1" }, + { L"-1", L"2", L"-1" }, + { L"1.2", L"3.45", L"1.2" }, + { L"-1.2", L"3.45", L"-1.2" }, + { L"1.2", L"-3.45", L"1.2" }, + { L"-1.2", L"-3.45", L"-1.2" }, + { L".2", L".45", L"0.2" }, + { L"-.2", L".45", L"-0.2" }, + { L".2", L"-.45", L"0.2" }, + { L"-.2", L"-.45", L"-0.2" }, + + { L"2", L"1", L"0" }, + { L"4567", L"123", L"16" }, + { L"3.45", L"1.2", L"1.05" }, + { L"2", L"-1", L"0" }, + { L"-2", L"1", L"0" }, + { L"-2", L"-1", L"0" }, + { L"3.45", L"-1.2", L"1.05" }, + { L"-3.45", L"1.2", L"-1.05" }, + { L"-3.45", L"-1.2", L"-1.05" }, + { L".45", L".2", L"0.05" }, + { L".45", L"-.2", L"0.05" }, + { L"-.45", L".2", L"-0.05" }, + { L"-.45", L"-.2", L"-0.05" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + WEX::Logging::Log::Comment(L"----------"); + + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal result{ left.mod(right) }; + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s mod %s = %s vs %s", + // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } + } + + TEST_METHOD(mod) { try { diff --git a/test/Decimal/CS/DotNetTests.cs b/test/Decimal/CS/DotNetTests.cs index cc72f49ee6..cb8c4e386f 100644 --- a/test/Decimal/CS/DotNetTests.cs +++ b/test/Decimal/CS/DotNetTests.cs @@ -20,6 +20,17 @@ public static void Run() ctor_to_assign_double(); ctor_to_assign_string(); compare_int16(); + compare_int32(); + compare_int64(); + compare_uint8(); + compare_uint16(); + compare_uint32(); + compare_uint64(); + compare_float(); + compare_double(); + compare_string(); + operator_neg(); + abs(); } public static void ctor() @@ -154,5 +165,433 @@ public static void compare_int16() Verify.IsTrue(right > left); Verify.IsTrue(right >= left); } + + public static void compare_int32() + { + var left = new Decimal((int)-1234567890); + var right = new Decimal((int)1234567890); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_int64() + { + var left = new Decimal((long)-1234567890123456789); + var right = new Decimal((long)1234567890123456789); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_uint8() + { + var left = new Decimal((byte)123); + var right = new Decimal((byte)234); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_uint16() + { + var left = new Decimal((ushort)32109); + var right = new Decimal((ushort)65432); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_uint32() + { + var left = new Decimal((uint)1234567890); + var right = new Decimal((uint)4019283756); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_uint64() + { + var left = new Decimal((ulong)0x1234567890ABCDEF); + var right = new Decimal((ulong)0xFEDCBA0987654321); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_float() + { + var left = new Decimal((float)-1.25); + var right = new Decimal((float)1.25); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_double() + { + var left = new Decimal((double)-1.25); + var right = new Decimal((double)1.25); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void compare_string() + { + var left = Decimal.Parse("-12.345"); + var right = Decimal.Parse("12.345"); + Verify.AreEqual(0, left.CompareTo(left)); + Verify.AreEqual(0, right.CompareTo(right)); + Verify.AreEqual(-1, left.CompareTo(right)); + Verify.AreEqual(1, right.CompareTo(left)); + + Verify.IsTrue(left == left); + Verify.IsFalse(left != left); + Verify.IsFalse(left < left); + Verify.IsTrue(left <= left); + Verify.IsFalse(left > left); + Verify.IsTrue(left >= left); + + Verify.IsTrue(right == right); + Verify.IsFalse(right != right); + Verify.IsFalse(right < right); + Verify.IsTrue(right <= right); + Verify.IsFalse(right > right); + Verify.IsTrue(right >= right); + + Verify.IsFalse(left == right); + Verify.IsTrue(left != right); + Verify.IsTrue(left < right); + Verify.IsTrue(left <= right); + Verify.IsFalse(left > right); + Verify.IsFalse(left >= right); + + Verify.IsFalse(right == left); + Verify.IsTrue(right != left); + Verify.IsFalse(right < left); + Verify.IsFalse(right <= left); + Verify.IsTrue(right > left); + Verify.IsTrue(right >= left); + } + + public static void operator_neg() + { + var zero = Decimal.Parse("0"); + var pos = Decimal.Parse("12.345"); + var neg = Decimal.Parse("-12.345"); + + var zero_value = -zero; + Verify.AreEqual(0, zero_value.CompareTo(zero)); + Verify.AreEqual(-1, zero_value.CompareTo(pos)); + Verify.AreEqual(1, zero_value.CompareTo(neg)); + + var pos_value = -neg; + Verify.AreEqual(1, pos_value.CompareTo(zero)); + Verify.AreEqual(0, pos_value.CompareTo(pos)); + Verify.AreEqual(1, pos_value.CompareTo(neg)); + + var neg_value = -pos; + Verify.AreEqual(-1, neg_value.CompareTo(zero)); + Verify.AreEqual(-1, neg_value.CompareTo(pos)); + Verify.AreEqual(0, neg_value.CompareTo(neg)); + } + + public static void abs() + { + var zero = Decimal.Parse("0"); + var pos = Decimal.Parse("12.345"); + var neg = Decimal.Parse("-12.345"); + + var zero_value = abs(zero); + Verify.AreEqual(0, zero_value.CompareTo(zero)); + Verify.AreEqual(-1, zero_value.CompareTo(pos)); + Verify.AreEqual(1, zero_value.CompareTo(neg)); + + var pos_value = abs(pos); + Verify.AreEqual(1, pos_value.CompareTo(zero)); + Verify.AreEqual(0, pos_value.CompareTo(pos)); + Verify.AreEqual(1, pos_value.CompareTo(neg)); + + var neg_value = abs(neg); + Verify.AreEqual(1, neg_value.CompareTo(zero)); + Verify.AreEqual(0, neg_value.CompareTo(pos)); + Verify.AreEqual(1, neg_value.CompareTo(neg)); + } + + public static void fix() + { + } + + public static void integer() + { + } + + public static void operator_add() + { + } + + public static void operator_sub() + { + } + + public static void operator_mul() + { + } + + public static void operator_div() + { + } + + public static void operator_mod() + { + } + + public static void mod() + { + } + + public static void round() + { + } + + private static Decimal abs(Decimal value) + { + var zero = new Decimal(0); + return value.CompareTo(zero) < 0 ? -value : value; + } } } From 050788a65b36f6e5c19aadf8bfe73412b9ccadc8 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Thu, 24 Apr 2025 22:33:33 -0700 Subject: [PATCH 08/25] More modulo work. More testing --- WindowsAppRuntime.sln | 28 ++ dev/Decimal/Decimal.idl | 11 + dev/Decimal/M.W.F.Decimal.cpp | 33 +++ dev/Decimal/M.W.F.Decimal.h | 7 + dev/Decimal/decimal.h | 79 ++++-- test/Decimal/CPP/DecimalTests.cpp | 264 +++++++++++++++++- test/Decimal/CS/Program.cs | 26 +- .../CS/DecimalCalculator_CS.csproj | 36 +++ test/Decimal/DecimalCalcuator/CS/Program.cs | 85 ++++++ test/Decimal/DecimalCalcuator/CS/test_mod.cmd | 35 +++ 10 files changed, 567 insertions(+), 37 deletions(-) create mode 100644 test/Decimal/DecimalCalcuator/CS/DecimalCalculator_CS.csproj create mode 100644 test/Decimal/DecimalCalcuator/CS/Program.cs create mode 100644 test/Decimal/DecimalCalcuator/CS/test_mod.cmd diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index ff71c0ac3c..69a9c1b759 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -712,6 +712,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecimalTest_CS", "test\Deci {F76B776E-86F5-48C5-8FC7-D2795ECC9746} = {F76B776E-86F5-48C5-8FC7-D2795ECC9746} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DecimalCalculator", "DecimalCalculator", "{A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{F4F96552-D5B3-4075-A335-ACE45CA6369D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS", "CS", "{6FE937DC-8AEE-4191-B6BA-51A32DE27ABE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecimalCalculator_CS", "test\Decimal\DecimalCalcuator\CS\DecimalCalculator_CS.csproj", "{5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2462,6 +2470,22 @@ Global {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x64.Build.0 = Release|x64 {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x86.ActiveCfg = Release|x86 {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5}.Release|x86.Build.0 = Release|x86 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|Any CPU.ActiveCfg = Debug|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|Any CPU.Build.0 = Debug|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|ARM64.ActiveCfg = Debug|arm64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|ARM64.Build.0 = Debug|arm64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|x64.ActiveCfg = Debug|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|x64.Build.0 = Debug|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|x86.ActiveCfg = Debug|x86 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Debug|x86.Build.0 = Debug|x86 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|Any CPU.ActiveCfg = Release|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|Any CPU.Build.0 = Release|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|ARM64.ActiveCfg = Release|arm64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|ARM64.Build.0 = Release|arm64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x64.ActiveCfg = Release|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x64.Build.0 = Release|x64 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x86.ActiveCfg = Release|x86 + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2678,6 +2702,10 @@ Global {AB515C38-1A93-40FE-917B-1998DCEB811C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {4CBAF81E-F2F2-437C-BE4B-8F457DA572AA} = {7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53} {041C3EC8-85CC-83C3-9815-0B10CBD0E1E5} = {AB515C38-1A93-40FE-917B-1998DCEB811C} + {A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {F4F96552-D5B3-4075-A335-ACE45CA6369D} = {A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3} + {6FE937DC-8AEE-4191-B6BA-51A32DE27ABE} = {A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3} + {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646} = {6FE937DC-8AEE-4191-B6BA-51A32DE27ABE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index 1e88989e76..6401815262 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -93,9 +93,20 @@ namespace Microsoft.Windows.Foundation Decimal Round(Int32 decimalPlaces); Decimal Add(Decimal value); + Decimal AddAssign(Decimal value); + Decimal Sub(Decimal value); //TODO Subtract() ? + Decimal SubAssign(Decimal value); //TODO Subtract() ? + Decimal Mul(Decimal value); //TODO Multiply() ? + Decimal MulAssign(Decimal value); //TODO Multiply() ? + Decimal Div(Decimal value); //TODO Divide() ? + Decimal DivAssign(Decimal value); //TODO Divide() ? + Decimal Mod(Decimal value); //TODO Modulo() or Remainder() ? + Decimal ModAssign(Decimal value); //TODO Modulo() or Remainder() ? + Decimal ModVariant(Decimal value); //TODO Remove? + Decimal ModTruncated(Decimal value); //TODO Remove? } } diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index dd0438a42b..66ee58fe08 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -245,22 +245,55 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { return winrt::make(m_decimal + to_decimal(value)); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::AddAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + m_decimal += to_decimal(value); + return *this; + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal - to_decimal(value)); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::SubAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + m_decimal -= to_decimal(value); + return *this; + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal * to_decimal(value)); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::MulAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + m_decimal *= to_decimal(value); + return *this; + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Div(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal / to_decimal(value)); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::DivAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + m_decimal /= to_decimal(value); + return *this; + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal % to_decimal(value)); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + m_decimal %= to_decimal(value); + return *this; + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModVariant(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal.mod_variant(to_decimal(value))); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModTruncated(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(m_decimal.mod_truncated(to_decimal(value))); + } hstring Decimal::ToString() { return m_decimal.to_hstring(); diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h index 4d205ba5ca..5907f7898c 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/M.W.F.Decimal.h @@ -100,10 +100,17 @@ namespace winrt::Microsoft::Windows::Foundation::implementation winrt::Microsoft::Windows::Foundation::Decimal Integer(); winrt::Microsoft::Windows::Foundation::Decimal Round(int32_t decimalPlaces); winrt::Microsoft::Windows::Foundation::Decimal Add(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal AddAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal SubAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal MulAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Div(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal DivAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal ModAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal ModVariant(winrt::Microsoft::Windows::Foundation::Decimal const& value); + winrt::Microsoft::Windows::Foundation::Decimal ModTruncated(winrt::Microsoft::Windows::Foundation::Decimal const& value); hstring ToString(); private: diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index 52fe6e3a2f..cb4bd0f860 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -22,10 +22,10 @@ class decimal { } - decimal(const decimal&& value) : + decimal(decimal&& value) : m_decimal(value.m_decimal) { - m_decimal = DECIMAL{}; + value.m_decimal = DECIMAL{}; } decimal(const DECIMAL& value) : @@ -150,12 +150,12 @@ class decimal return *this; } - decimal& operator=(const decimal&& value) + decimal& operator=(decimal&& value) { if (&value != this) { m_decimal = value.m_decimal; - m_decimal = DECIMAL{}; + value.m_decimal = DECIMAL{}; } return *this; } @@ -465,6 +465,7 @@ class decimal } /// Round down to integer. + /// @note this rounds down to -infinity. decimal integer() const { decimal value{}; @@ -472,6 +473,30 @@ class decimal return value; } + decimal operator++() + { + return operator+=(decimal(1)); + } + + decimal operator++(int) + { + const decimal before(m_decimal); + operator+=(decimal(1)); + return before; + } + + decimal operator--() + { + return operator-=(decimal(1)); + } + + decimal operator--(int) + { + const decimal before(m_decimal); + operator-=(decimal(1)); + return before; + } + decimal operator+(const decimal& value) const { decimal result{}; @@ -525,6 +550,11 @@ class decimal } decimal operator%(const decimal& value) const + { + return mod_variant(value); + } + + decimal mod_variant(const decimal& value) const { VARIANT left{}; left.vt = VT_DECIMAL; @@ -543,31 +573,36 @@ class decimal } decimal mod(const decimal& value) const + { + return mod_truncated(value); + } + + /// Modulo operation using the Truncated method. + /// @note The % operator in C, C#, Rust and other languages use this method. + /// @note The result's sign will match the current value's sign. + /// @see https://en.wikipedia.org/wiki/Modulo + decimal mod_truncated(const decimal& value) const { // VarMod() operates on I4 (int32) at best (not even I8 aka int64) - // So let's do it the grade school way... + // So let's do it the grade school way and matching .NET's Decimal... // // remainder = left % right // aka - // q = (left / right) - // remainder = left - (right * FIX(left / right) * right) - - static const Microsoft::Windows::Foundation::decimal zero{}; - static const Microsoft::Windows::Foundation::decimal one{ 1 }; - if ((*this == value) || (value == one)) - { - return zero; - } - - const Microsoft::Windows::Foundation::decimal& left{ *this }; - const Microsoft::Windows::Foundation::decimal& right{ value }; + // aleft = ABS(left) + // aright = ABS(right) + // q = (aleft / aright) + // remainder = aleft - (aright * FIX(aleft / aright) * aright) + // remainder = IF left < 0 THEN remainder = -remainder + + const Microsoft::Windows::Foundation::decimal aleft{ abs() }; + const Microsoft::Windows::Foundation::decimal aright{ value.abs() }; const bool left_is_negative{ m_decimal.sign != 0 }; - Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; - Microsoft::Windows::Foundation::decimal fix{ quotient.fix() }; - Microsoft::Windows::Foundation::decimal product{ quotient * fix }; - Microsoft::Windows::Foundation::decimal remainder{ left_is_negative ? left + product : left - product }; - return remainder; + const Microsoft::Windows::Foundation::decimal quotient{ aleft.abs() / aright.abs() }; + const Microsoft::Windows::Foundation::decimal fix{ quotient.fix() }; + const Microsoft::Windows::Foundation::decimal product{ fix * aright }; + const Microsoft::Windows::Foundation::decimal remainder{ aleft - product }; + return left_is_negative ? -remainder : remainder; } decimal& operator%=(const decimal& value) diff --git a/test/Decimal/CPP/DecimalTests.cpp b/test/Decimal/CPP/DecimalTests.cpp index 116d851056..9668615485 100644 --- a/test/Decimal/CPP/DecimalTests.cpp +++ b/test/Decimal/CPP/DecimalTests.cpp @@ -87,6 +87,31 @@ namespace Test::Decimal::Tests VERIFY_ARE_EQUAL(data, value); } + TEST_METHOD(ctor_assign_move) + { + const Microsoft::Windows::Foundation::decimal data{ -1234567890 }; + const Microsoft::Windows::Foundation::decimal zero{}; + + Microsoft::Windows::Foundation::decimal before{ data }; + VERIFY_ARE_EQUAL(data, before); + const Microsoft::Windows::Foundation::decimal after = std::move(before); + VERIFY_ARE_EQUAL(data, after); + VERIFY_ARE_EQUAL(zero, before); + } + + TEST_METHOD(ctor_to_assign_decimal) + { + const Microsoft::Windows::Foundation::decimal data{ -1234567890 }; + Microsoft::Windows::Foundation::decimal object(data); + const auto to{ object.to_decimal() }; + VERIFY_ARE_EQUAL(data, to); + + Microsoft::Windows::Foundation::decimal object2; + object2 = data; + const auto to2{ object.to_decimal() }; + VERIFY_ARE_EQUAL(data, to2); + } + TEST_METHOD(ctor_to_assign_bool) { const bool data{ true }; @@ -1051,6 +1076,106 @@ namespace Test::Decimal::Tests VERIFY_IS_TRUE(neg_value == neg_integer); } + TEST_METHOD(operator_increment) + { + struct values + { + PCWSTR left; + PCWSTR result; + } values[]{ + { L"0", L"1" }, + { L"1", L"2" }, + { L"123", L"124" }, + { L"255", L"256" }, + { L"65535", L"65536" }, + { L"1234567890", L"1234567891" }, + { L"91028374659102837465", L"91028374659102837466" }, + { L"-0", L"1" }, + { L"-1", L"0" }, + { L"-123", L"-122" }, + { L"-255", L"-254" }, + { L"-65535", L"-65534" }, + { L"-1234567890", L"-1234567889" }, + { L"-91028374659102837465", L"-91028374659102837464" }, + { L"1.2", L"2.2" }, + { L"-1.2", L"-0.2" }, + { L".2", L"1.2" }, + { L"-.2", L"0.8" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const Microsoft::Windows::Foundation::decimal before { value.left }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + { + Microsoft::Windows::Foundation::decimal left{ before }; + const Microsoft::Windows::Foundation::decimal returned{ ++left }; + VERIFY_ARE_EQUAL(returned, left, WEX::Common::String().Format(L"++%s value = %s vs %s", + before.to_string().c_str(), left.to_string().c_str(), expected.to_string().c_str())); + VERIFY_ARE_EQUAL(expected, left, WEX::Common::String().Format(L"++%s return = %s vs %s", + before.to_string().c_str(), returned.to_string().c_str(), expected.to_string().c_str())); + } + { + Microsoft::Windows::Foundation::decimal left{ before }; + const Microsoft::Windows::Foundation::decimal returned{ left++ }; + VERIFY_ARE_NOT_EQUAL(returned, left, WEX::Common::String().Format(L"%s++ value = %s vs %s", + before.to_string().c_str(), left.to_string().c_str(), expected.to_string().c_str())); + VERIFY_ARE_EQUAL(expected, left, WEX::Common::String().Format(L"%s++ return = %s vs %s", + before.to_string().c_str(), returned.to_string().c_str(), expected.to_string().c_str())); + } + } + } + + TEST_METHOD(operator_decrement) + { + struct values + { + PCWSTR left; + PCWSTR result; + } values[]{ + { L"0", L"-1" }, + { L"1", L"0" }, + { L"123", L"122" }, + { L"255", L"254" }, + { L"65535", L"65534" }, + { L"1234567890", L"1234567889" }, + { L"91028374659102837465", L"91028374659102837464" }, + { L"-0", L"-1" }, + { L"-1", L"-2" }, + { L"-123", L"-124" }, + { L"-255", L"-256" }, + { L"-65535", L"-65536" }, + { L"-1234567890", L"-1234567891" }, + { L"-91028374659102837465", L"-91028374659102837466" }, + { L"1.2", L"0.2" }, + { L"-1.2", L"-2.2" }, + { L".2", L"-0.8" }, + { L"-.2", L"-1.2" } + }; + for (size_t index=0; index < ARRAYSIZE(values); --index) + { + const auto& value{ values[index] }; + const Microsoft::Windows::Foundation::decimal before { value.left }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + { + Microsoft::Windows::Foundation::decimal left{ before }; + const Microsoft::Windows::Foundation::decimal returned{ --left }; + VERIFY_ARE_EQUAL(returned, left, WEX::Common::String().Format(L"--%s value = %s vs %s", + before.to_string().c_str(), left.to_string().c_str(), expected.to_string().c_str())); + VERIFY_ARE_EQUAL(expected, left, WEX::Common::String().Format(L"--%s return = %s vs %s", + before.to_string().c_str(), returned.to_string().c_str(), expected.to_string().c_str())); + } + { + Microsoft::Windows::Foundation::decimal left{ before }; + const Microsoft::Windows::Foundation::decimal returned{ left-- }; + VERIFY_ARE_NOT_EQUAL(returned, left, WEX::Common::String().Format(L"%s-- value = %s vs %s", + before.to_string().c_str(), left.to_string().c_str(), expected.to_string().c_str())); + VERIFY_ARE_EQUAL(expected, left, WEX::Common::String().Format(L"%s-- return = %s vs %s", + before.to_string().c_str(), returned.to_string().c_str(), expected.to_string().c_str())); + } + } + } + TEST_METHOD(operator_add) { struct values @@ -1086,6 +1211,11 @@ namespace Test::Decimal::Tests const Microsoft::Windows::Foundation::decimal result{ left + right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s + %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal result2{ left }; + result2 += right; + VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s += %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result2.to_string().c_str(), expected.to_string().c_str())); } } @@ -1124,6 +1254,11 @@ namespace Test::Decimal::Tests const Microsoft::Windows::Foundation::decimal result{ left - right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s - %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal result2{ left }; + result2 -= right; + VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s -= %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result2.to_string().c_str(), expected.to_string().c_str())); } } @@ -1162,6 +1297,11 @@ namespace Test::Decimal::Tests const Microsoft::Windows::Foundation::decimal result{ left * right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s * %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal result2{ left }; + result2 *= right; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s *= %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result2.to_string().c_str(), expected.to_string().c_str())); } } @@ -1208,6 +1348,11 @@ namespace Test::Decimal::Tests const Microsoft::Windows::Foundation::decimal result{ left / right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s / %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + + Microsoft::Windows::Foundation::decimal result2{ left }; + result2 /= right; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s /= %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result2.to_string().c_str(), expected.to_string().c_str())); } } @@ -1217,7 +1362,7 @@ namespace Test::Decimal::Tests { Microsoft::Windows::Foundation::decimal data{ 123 }; Microsoft::Windows::Foundation::decimal zero{}; - const auto result{ data / zero }; + const auto result{ data % zero }; VERIFY_FAIL(L"Success is not expected"); } catch (wil::ResultException& e) @@ -1393,6 +1538,123 @@ namespace Test::Decimal::Tests } } + TEST_METHOD(operator_mod_variant_truncated) + { + try + { + Microsoft::Windows::Foundation::decimal data{ 123 }; + Microsoft::Windows::Foundation::decimal zero{}; + const auto result{ data.mod_variant(zero) }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + try + { + Microsoft::Windows::Foundation::decimal data{ 123 }; + Microsoft::Windows::Foundation::decimal zero{}; + const auto result{ data.mod_truncated(zero) }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"1" }, + { L"123", L"4567", L"123" }, + { L"1", L"-2", L"1" }, + { L"-1", L"-2", L"-1" }, + { L"-1", L"2", L"-1" }, + { L"1.2", L"3.45", L"1.2" }, + { L"-1.2", L"3.45", L"-1.2" }, + { L"1.2", L"-3.45", L"1.2" }, + { L"-1.2", L"-3.45", L"-1.2" }, + { L".2", L".45", L"0.2" }, + { L"-.2", L".45", L"-0.2" }, + { L".2", L"-.45", L"0.2" }, + { L"-.2", L"-.45", L"-0.2" }, + + { L"2", L"1", L"0" }, + { L"4567", L"123", L"16" }, + { L"3.45", L"1.2", L"1.05" }, + { L"2", L"-1", L"0" }, + { L"-2", L"1", L"0" }, + { L"-2", L"-1", L"0" }, + { L"3.45", L"-1.2", L"1.05" }, + { L"-3.45", L"1.2", L"-1.05" }, + { L"-3.45", L"-1.2", L"-1.05" }, + { L".45", L".2", L"0.05" }, + { L".45", L"-.2", L"0.05" }, + { L"-.45", L".2", L"-0.05" }, + { L"-.45", L"-.2", L"-0.05" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + WEX::Logging::Log::Comment(L"----------"); + + try + { + const auto& value{ values[index] }; + Microsoft::Windows::Foundation::decimal left{ value.left }; + Microsoft::Windows::Foundation::decimal right{ value.right }; + Microsoft::Windows::Foundation::decimal expected{ value.result }; + Microsoft::Windows::Foundation::decimal result_variant; + try + { + result_variant = left.mod_variant(right); + } + catch (std::exception& e) + { + // As explained in https://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero + // + // ...section [expr.mul] specifically states (for both integer and floating point division, and integer remainder): + // If the second operand of / or % is zero, the behavior is undefined. + // So, it could throw those (or any other) exceptions. It could also format your hard disk and laugh derisively :-) + // + // and + // + // Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley, 1994), + // "low-level events, such as arithmetic overflows and divide by zero, are assumed + // to be handled by a dedicated lower-level mechanism rather than by exceptions. + // This enables C++ to match the behaviour of other languages when it comes to + // arithmetic. It also avoids the problems that occur on heavily pipelined + // architectures where events such as divide by zero are asynchronous."` + // + // Our current implementation shows up as a throw exception of type std::exception or + // derived type so we'll catch that and log what what little we know about what went wrong + WEX::Logging::Log::Comment( + WEX::Common::String().Format(L"%s mod_variant %s == std::exception.what: %hs", + left.to_string().c_str(), right.to_string().c_str(), e.what())); + } + const Microsoft::Windows::Foundation::decimal result_truncated{ left.mod_truncated(right) }; + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L" VARIANT: %s %% %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result_variant.to_string().c_str(), expected.to_string().c_str())); + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"TRUNCATED: %s %% %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result_truncated.to_string().c_str(), expected.to_string().c_str())); + + //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s mod %s = %s vs %s", + // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); + } + catch (std::exception& e) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"std::exception.what: %hs", e.what())); + //VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.cod(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + } + } + TEST_METHOD(operator_round) { Microsoft::Windows::Foundation::decimal n_1_888{ L"1.888" }; diff --git a/test/Decimal/CS/Program.cs b/test/Decimal/CS/Program.cs index f9954367c8..2ec1d2cbc0 100644 --- a/test/Decimal/CS/Program.cs +++ b/test/Decimal/CS/Program.cs @@ -13,26 +13,24 @@ static void Main(string[] args) Help(); } - foreach (var arg in args) + var arg = args[0]; + if (arg.Equals("dotnet", StringComparison.OrdinalIgnoreCase)) { - if (arg.Equals("dotnet", StringComparison.OrdinalIgnoreCase)) - { - Test.DotNet.DecimalTests.Run(); - } - else if (arg.Equals("winappsdk", StringComparison.OrdinalIgnoreCase)) - { - Test.WinAppSDK.DecimalTests.Run(); - } - else - { - Help(); - } + Test.DotNet.DecimalTests.Run(); + } + else if (arg.Equals("winappsdk", StringComparison.OrdinalIgnoreCase)) + { + Test.WinAppSDK.DecimalTests.Run(); + } + else + { + Help(); } } private static void Help() { - Console.WriteLine("Usage: DecimalTest_CS \n" + + Console.WriteLine("Usage: DecimalTest_CS \n" + "where\n" + " test = dotnet | winappsdk"); Environment.Exit(1); diff --git a/test/Decimal/DecimalCalcuator/CS/DecimalCalculator_CS.csproj b/test/Decimal/DecimalCalcuator/CS/DecimalCalculator_CS.csproj new file mode 100644 index 0000000000..3a923c9cf6 --- /dev/null +++ b/test/Decimal/DecimalCalcuator/CS/DecimalCalculator_CS.csproj @@ -0,0 +1,36 @@ + + + + Exe + net6.0-windows10.0.19041.0 + x86;x64;arm64 + disable + disable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + pdbonly + true + + + + + + + + + + + diff --git a/test/Decimal/DecimalCalcuator/CS/Program.cs b/test/Decimal/DecimalCalcuator/CS/Program.cs new file mode 100644 index 0000000000..7d5cd2c0b7 --- /dev/null +++ b/test/Decimal/DecimalCalcuator/CS/Program.cs @@ -0,0 +1,85 @@ +using System; + +namespace Microsoft.Windows.Foundation +{ + class DecimalCalculator + { + public static void Main(string[] args) + { + if (args.Length < 2) + { + Help(); + } + + string op = args[0]; + Decimal left = Decimal.Parse(args[1]); + Decimal right = (args.Length >= 3 ? Decimal.Parse(args[2]) : new Decimal(0)); + string expected = (args.Length >= 4 ? args[3] : null); + Decimal result = new Decimal(0); + if (args.Length == 3) + { + // NOTE: Decimal unary operators not supported by C#: ! ~ + switch (op) + { + case "+": result = +left; Console.Write($"{op}{left} = {result}"); break; + case "-": result = -left; Console.Write($"{op}{left} = {result}"); break; + case "++": result = ++left; Console.Write($"{op}{left} = {result}"); break; + case "--": result = --left; Console.Write($"{op}{left} = {result}"); break; + case "int32": expected = null; Console.WriteLine($"{op} {left} = {(int)left}"); break; + case "int64": expected = null; Console.WriteLine($"{op} {left} = {(long)left}"); break; + case "uint32": expected = null; Console.WriteLine($"{op} {left} = {(uint)left}"); break; + case "uint64": expected = null; Console.WriteLine($"{op} {left} = {(ulong)left}"); break; + case "float": expected = null; Console.WriteLine($"{op} {left} = {(float)left}"); break; + case "double": expected = null; Console.WriteLine($"{op} {left} = {(double)left}"); break; + default: UnknownOperator($"{op} {left}"); break; + } + } + else if (args.Length == 4) + { + // NOTE: Decimal unary operators not supported by C#: << >> >>> & | ^ + switch (op) + { + case "+": result = left + right; Console.Write($"{left} {op} {right} = {result}"); break; + case "-": result = left - right; Console.Write($"{left} {op} {right} = {result}"); break; + case "*": result = left * right; Console.Write($"{left} {op} {right} = {result}"); break; + case "/": result = left / right; Console.Write($"{left} {op} {right} = {result}"); break; + case "%": result = left % right; Console.Write($"{left} {op} {right} = {result}"); break; + case "mod": result = left % right; Console.Write($"{left} {op} {right} = {result}"); break; + case "==": expected = null; Console.WriteLine($"{left} {op} {right} = {left == right}"); break; + case "!=": expected = null; Console.WriteLine($"{left} {op} {right} = {left != right}"); break; + case "<": expected = null; Console.WriteLine($"{left} {op} {right} = {left < right}"); break; + case "<=": expected = null; Console.WriteLine($"{left} {op} {right} = {left <= right}"); break; + case ">": expected = null; Console.WriteLine($"{left} {op} {right} = {left > right}"); break; + case ">=": expected = null; Console.WriteLine($"{left} {op} {right} = {left >= right}"); break; + default: UnknownOperator($"{op} {left} {right}"); break; + } + } + else + { + Help(); + } + if (expected != null) + { + Decimal expectedValue = Decimal.Parse(expected); + Console.WriteLine($"\t\t ==> {result} == {expectedValue} = {expectedValue == result}"); + } + } + + private static void UnknownOperator(string message) + { + Console.WriteLine($"ERROR: Unknown operator {message}"); + Environment.Exit(2); + } + + private static void Help() + { + Console.WriteLine("Usage: DecimalCalculator_CS.exe []\n" + + "where\n" + + " operator = unary: + - ++ -- int32 int64 uint32 uint32 float double\n" + + " binary: + - * / % mod == != < <= > >=\n" + + " left = decimal value\n" + + " right = decimal value"); + Environment.Exit(1); + } + } +} diff --git a/test/Decimal/DecimalCalcuator/CS/test_mod.cmd b/test/Decimal/DecimalCalcuator/CS/test_mod.cmd new file mode 100644 index 0000000000..a9ff1693f8 --- /dev/null +++ b/test/Decimal/DecimalCalcuator/CS/test_mod.cmd @@ -0,0 +1,35 @@ +@ECHO OFF +SETLOCAL + +SET C=DecimalCalculator_CS.exe + + +%C% mod 1 2 1 +%C% mod 123 4567 123 +%C% mod 1 -2 1 +%C% mod -1 -2 -1 +%C% mod -1 2 -1 +%C% mod 1.2 3.45 1.2 +%C% mod -1.2 3.45 -1.2 +%C% mod 1.2 -3.45 1.2 +%C% mod -1.2 -3.45 -1.2 +%C% mod .2 .45 0.2 +%C% mod -.2 .45 -0.2 +%C% mod .2 -.45 0.2 +%C% mod -.2 -.45 -0.2 +%C% mod 2 1 0 +%C% mod 4567 123 16 +%C% mod 3.45 1.2 1.05 +%C% mod 2 -1 0 +%C% mod -2 1 0 +%C% mod -2 -1 0 +%C% mod 3.45 -1.2 1.05 +%C% mod -3.45 1.2 -1.05 +%C% mod -3.45 -1.2 -1.05 +%C% mod .45 .2 0.05 +%C% mod .45 -.2 0.05 +%C% mod -.45 .2 -0.05 +%C% mod -.45 -.2 -0.05 + +:TheEnd +ENDLOCAL From 6161589a22bbd82c208beaffccdfccf7fbc2a7f7 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Fri, 25 Apr 2025 11:03:41 -0700 Subject: [PATCH 09/25] Added Python test --- .../DecimalCalcuator/CS/py_test_mod.cmd | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 test/Decimal/DecimalCalcuator/CS/py_test_mod.cmd diff --git a/test/Decimal/DecimalCalcuator/CS/py_test_mod.cmd b/test/Decimal/DecimalCalcuator/CS/py_test_mod.cmd new file mode 100644 index 0000000000..4fe2b969bb --- /dev/null +++ b/test/Decimal/DecimalCalcuator/CS/py_test_mod.cmd @@ -0,0 +1,42 @@ +@ECHO OFF +SETLOCAL + +IF %PYTHON_EXE%x == x GOTO NoPythonExe + +SET C=C:\Python313\python.exe -c + + +%C% "left=1 ; right=2 ; expected=1 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=123 ; right=4567 ; expected=123 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=1 ; right=-2 ; expected=1 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-1 ; right=-2 ; expected=-1 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-1 ; right=2 ; expected=-1 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=1.2 ; right=3.45 ; expected=1.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-1.2 ; right=3.45 ; expected=-1.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=1.2 ; right=-3.45 ; expected=1.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-1.2 ; right=-3.45 ; expected=-1.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=.2 ; right=.45 ; expected=0.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-.2 ; right=.45 ; expected=-0.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=.2 ; right=-.45 ; expected=0.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-.2 ; right=-.45 ; expected=-0.2 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=2 ; right=1 ; expected=0 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=4567 ; right=123 ; expected=16 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=3.45 ; right=1.2 ; expected=1.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=2 ; right=-1 ; expected=0 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-2 ; right=1 ; expected=0 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-2 ; right=-1 ; expected=0 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=3.45 ; right=-1.2 ; expected=1.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-3.45 ; right=1.2 ; expected=-1.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-3.45 ; right=-1.2 ; expected=-1.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=.45 ; right=.2 ; expected=0.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=.45 ; right=-.2 ; expected=0.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-.45 ; right=.2 ; expected=-0.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') +%C% "left=-.45 ; right=-.2 ; expected=-0.05 ; result=left %% right ; print(f'{left} %% {right} = {result}\t\t ==> {result} == {expected}\n') + +GOTO TheEnd + +:NoPythonExe +ECHO ERROR PYTHON_EXE environment variable not set + +:TheEnd +ENDLOCAL From 9204069887a4fd4c9c762a4f867db55237946ad9 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Fri, 25 Apr 2025 11:03:48 -0700 Subject: [PATCH 10/25] Fix a warning --- dev/AppLifecycle/ExtensionContract.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/AppLifecycle/ExtensionContract.h b/dev/AppLifecycle/ExtensionContract.h index a7a2cfb6ae..b60bf5bc30 100644 --- a/dev/AppLifecycle/ExtensionContract.h +++ b/dev/AppLifecycle/ExtensionContract.h @@ -55,7 +55,7 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation // QueryParsed() function would return empty when it's a file contract with unicode characters in file path // Thus following additional check for file contract is needed auto fileContractUri = GenerateEncodedLaunchUri(L"App", c_fileContractId); - if (CompareStringOrdinal(uri.AbsoluteUri().c_str(), fileContractUri.length(), fileContractUri.c_str(), -1, TRUE) == CSTR_EQUAL) + if (CompareStringOrdinal(uri.AbsoluteUri().c_str(), static_cast(fileContractUri.length()), fileContractUri.c_str(), -1, TRUE) == CSTR_EQUAL) { return { ExtendedActivationKind::File, FileActivatedEventArgs::Deserialize(uri) }; } From 7ca9f05f16b2c5a881bc1b2399fc781e2ffa1440 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sat, 26 Apr 2025 22:01:13 -0700 Subject: [PATCH 11/25] Tweaked boolean handling --- dev/Decimal/decimal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index cb4bd0f860..29e05b6526 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -43,7 +43,7 @@ class decimal // VarDecFromBool(VARIANT_TRUE) == -1 // VarDecFromBool(VARIANT_FALSE) == 0 // But decimal(true) would be expected to be 1 (not -1) - // So we intentionally ignore VarDecFromBool() and treat decimal(bool) == 0 or 1 + // So we intentionally ignore VarDecFromBool() and set decimal(bool) == 0 or 1 THROW_IF_FAILED(::VarDecFromUI4(value ? 1 : 0, &m_decimal)); } @@ -179,7 +179,7 @@ class decimal // VarDecFromBool(VARIANT_TRUE) == -1 // VarDecFromBool(VARIANT_FALSE) == 0 // But decimal(true) would be expected to be 1 (not -1) - // So we intentionally ignore VarDecFromBool() and treat decimal(bool) == 0 or 1 + // So we intentionally ignore VarDecFromBool() and set decimal(bool) == 0 or 1 THROW_IF_FAILED(::VarDecFromUI4(value ? 1 : 0, &m_decimal)); return *this; } @@ -282,8 +282,8 @@ class decimal bool to_bool() const { - // Treat all values != 0 as true (good) - return m_decimal.Hi32 | m_decimal.Mid32 | m_decimal.Lo32; + // Treat values != 0 as true + return (m_decimal.Lo64 != 0) | (m_decimal.Hi32 != 0); } char to_char() const From 61c7920668a6c40939a477dfcf692f729945e59b Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sat, 26 Apr 2025 23:11:16 -0700 Subject: [PATCH 12/25] Cleanup interfaces and tests. Expand tests --- dev/Decimal/Decimal.idl | 34 ++- dev/Decimal/M.W.F.Decimal.cpp | 20 +- dev/Decimal/M.W.F.Decimal.h | 3 + dev/Decimal/decimal.h | 103 ++++--- test/Decimal/CPP/DecimalTests.cpp | 289 ++++---------------- test/Decimal/CS/DecimalTest_CS.csproj | 20 +- test/Decimal/CS/DotNetTests.cs | 48 +++- test/Decimal/CS/WinAppSDKTests.cs | 237 +++++++++++++++- test/Decimal/DecimalCalcuator/CS/Program.cs | 28 +- 9 files changed, 474 insertions(+), 308 deletions(-) diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index 6401815262..ff2bafd34f 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -22,7 +22,6 @@ namespace Microsoft.Windows.Foundation runtimeclass Decimal : Windows.Foundation.IStringable { Decimal(); - //Decimal(Decimal value); static Decimal CreateFromBoolean(Boolean value); static Decimal CreateFromInt16(Int16 value); @@ -40,6 +39,7 @@ namespace Microsoft.Windows.Foundation static Decimal CreateFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() static Decimal CreateFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT static Decimal Create(IInspectable value); + static Decimal CreateFromDecimal(Decimal value); static Decimal CreateFromDecimalValue(DecimalValue value); void SetFromBoolean(Boolean value); @@ -58,6 +58,7 @@ namespace Microsoft.Windows.Foundation void SetFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() void SetFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT void Set(IInspectable value); + void SetFromDecimal(Decimal value); void SetFromDecimalValue(DecimalValue value); Boolean ToBoolean(); @@ -78,10 +79,17 @@ namespace Microsoft.Windows.Foundation IInspectable ToObject(); DecimalValue ToDecimalValue(); + /// Return true if (this == value). + Boolean Equals(Decimal value); + + /// Compare this decimal with value. + /// @return 0 if this and value are equal, <0 if this is less than value or >0 if this is greater than value. Int32 Compare(Decimal value); + /// Return a decimal whose value is (-this). Decimal Negate(); + /// Return the absolute value. Decimal Abs(); /// Return the value's integer portion (zero to the right of the decimal point). @@ -90,23 +98,27 @@ namespace Microsoft.Windows.Foundation /// Return the value rounded down to the nearest integer. Decimal Integer(); + /// Return the value rounded to the specific number of decimal places. Decimal Round(Int32 decimalPlaces); + /// Returns a Decimal whose value is (this + value). Decimal Add(Decimal value); Decimal AddAssign(Decimal value); - Decimal Sub(Decimal value); //TODO Subtract() ? - Decimal SubAssign(Decimal value); //TODO Subtract() ? + /// Returns a Decimal whose value is (this - value). + Decimal Sub(Decimal value); //TODO Rename to Subtract() ? + Decimal SubAssign(Decimal value); //TODO Rename to SubtractAssign() ? - Decimal Mul(Decimal value); //TODO Multiply() ? - Decimal MulAssign(Decimal value); //TODO Multiply() ? + /// Returns a Decimal whose value is (this * value). + Decimal Mul(Decimal value); //TODO Rename to Multiply() ? + Decimal MulAssign(Decimal value); //TODO Rename to MultiplyAssign() ? - Decimal Div(Decimal value); //TODO Divide() ? - Decimal DivAssign(Decimal value); //TODO Divide() ? + /// Returns a Decimal whose value is (this / value). + Decimal Div(Decimal value); //TODO Rename to Divide() ? + Decimal DivAssign(Decimal value); //TODO Rename to DivideAssign() ? - Decimal Mod(Decimal value); //TODO Modulo() or Remainder() ? - Decimal ModAssign(Decimal value); //TODO Modulo() or Remainder() ? - Decimal ModVariant(Decimal value); //TODO Remove? - Decimal ModTruncated(Decimal value); //TODO Remove? + /// Returns a Decimal whose value is (this % value). + Decimal Mod(Decimal value); //TODO Rename to Modulo() or Remainder() ? + Decimal ModAssign(Decimal value); //TODO Rename to ModuloAssign() or RemainderAssign() ? } } diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index 66ee58fe08..1d5805db18 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -74,6 +74,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { throw hresult_not_implemented(); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromDecimal(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return winrt::make(to_decimal(value)); + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) { return winrt::make(to_decimal(value)); @@ -147,6 +151,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { throw hresult_not_implemented(); } + void Decimal::SetFromDecimal(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + SetFromDecimalValue(value.ToDecimalValue()); + } void Decimal::SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) { const auto& decimalValue{ *reinterpret_cast(&value) }; @@ -221,6 +229,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { return m_decimal.compare(to_DECIMAL(value.ToDecimalValue())); } + bool Decimal::Equals(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + return m_decimal == to_DECIMAL(value.ToDecimalValue()); + } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Negate() { return winrt::make(-m_decimal); @@ -286,14 +298,6 @@ namespace winrt::Microsoft::Windows::Foundation::implementation m_decimal %= to_decimal(value); return *this; } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModVariant(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - return winrt::make(m_decimal.mod_variant(to_decimal(value))); - } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModTruncated(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - return winrt::make(m_decimal.mod_truncated(to_decimal(value))); - } hstring Decimal::ToString() { return m_decimal.to_hstring(); diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h index 5907f7898c..3a8fff5a02 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/M.W.F.Decimal.h @@ -59,6 +59,7 @@ namespace winrt::Microsoft::Windows::Foundation::implementation static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithThreadLocale(hstring const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromStringWithInvariantLocale(hstring const& value); static winrt::Microsoft::Windows::Foundation::Decimal Create(winrt::Windows::Foundation::IInspectable const& value); + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimal(winrt::Microsoft::Windows::Foundation::Decimal const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); void SetFromBoolean(bool value); void SetFromInt16(int16_t value); @@ -76,6 +77,7 @@ namespace winrt::Microsoft::Windows::Foundation::implementation void SetFromStringWithThreadLocale(hstring const& value); void SetFromStringWithInvariantLocale(hstring const& value); void Set(winrt::Windows::Foundation::IInspectable const& value); + void SetFromDecimal(winrt::Microsoft::Windows::Foundation::Decimal const& value); void SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); bool ToBoolean(); int16_t ToInt16(); @@ -93,6 +95,7 @@ namespace winrt::Microsoft::Windows::Foundation::implementation hstring ToStringWithInvariantLocale(); winrt::Windows::Foundation::IInspectable ToObject(); winrt::Microsoft::Windows::Foundation::DecimalValue ToDecimalValue(); + bool Equals(winrt::Microsoft::Windows::Foundation::Decimal const& value); int32_t Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Negate(); winrt::Microsoft::Windows::Foundation::Decimal Abs(); diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index 29e05b6526..ee2bef95fd 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -9,6 +9,44 @@ #pragma comment(linker, "/defaultlib:oleaut32.lib") #endif +inline int compare(const DECIMAL& left, const DECIMAL& right) +{ + static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); + static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); + static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); + return ::VarDecCmp(const_cast(&left), const_cast(&right)) - 1; +} + +inline bool operator==(const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) == 0; +} + +inline bool operator!=(const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) != 0; +} + +inline bool operator< (const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) < 0; +} + +inline bool operator<=(const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) <= 0; +} + +inline bool operator> (const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) > 0; +} + +inline bool operator>=(const DECIMAL& left, const DECIMAL& right) +{ + return compare(left, right) >= 0; +} + namespace Microsoft::Windows::Foundation { class decimal @@ -429,12 +467,39 @@ class decimal return compare(value.m_decimal); } + bool operator==(const DECIMAL& value) const + { + return compare(value) == 0; + } + + bool operator!=(const DECIMAL& value) const + { + return compare(value) != 0; + } + + bool operator< (const DECIMAL& value) const + { + return compare(value) < 0; + } + + bool operator<=(const DECIMAL& value) const + { + return compare(value) <= 0; + } + + bool operator> (const DECIMAL& value) const + { + return compare(value) > 0; + } + + bool operator>=(const DECIMAL& value) const + { + return compare(value) >= 0; + } + int compare(const DECIMAL& value) const { - static_assert(VARCMP_LT == 0, "VARCMP_LT == 0"); - static_assert(VARCMP_EQ == 1, "VARCMP_EQ == 1"); - static_assert(VARCMP_GT == 2, "VARCMP_GT == 2"); - return ::VarDecCmp(const_cast(&m_decimal), const_cast(&value)) - 1; + return ::compare(m_decimal, value); } decimal operator+() const @@ -549,39 +614,11 @@ class decimal return *this; } - decimal operator%(const decimal& value) const - { - return mod_variant(value); - } - - decimal mod_variant(const decimal& value) const - { - VARIANT left{}; - left.vt = VT_DECIMAL; - left.decVal = m_decimal; - - VARIANT right{}; - right.vt = VT_DECIMAL; - right.decVal = value.m_decimal; - - VARIANT result{}; - THROW_IF_FAILED(::VarMod(&left, &right, &result)); - VARIANT resultAsDecimal{}; - THROW_IF_FAILED(::VariantChangeType(&resultAsDecimal, &result, 0, VT_DECIMAL)); - THROW_HR_IF_MSG(E_UNEXPECTED, resultAsDecimal.vt != VT_DECIMAL, ".vt=%hu", resultAsDecimal.vt); - return Microsoft::Windows::Foundation::decimal{ resultAsDecimal.decVal }; - } - - decimal mod(const decimal& value) const - { - return mod_truncated(value); - } - /// Modulo operation using the Truncated method. /// @note The % operator in C, C#, Rust and other languages use this method. /// @note The result's sign will match the current value's sign. /// @see https://en.wikipedia.org/wiki/Modulo - decimal mod_truncated(const decimal& value) const + decimal operator%(const decimal& value) const { // VarMod() operates on I4 (int32) at best (not even I8 aka int64) // So let's do it the grade school way and matching .NET's Decimal... diff --git a/test/Decimal/CPP/DecimalTests.cpp b/test/Decimal/CPP/DecimalTests.cpp index 9668615485..d9136b2777 100644 --- a/test/Decimal/CPP/DecimalTests.cpp +++ b/test/Decimal/CPP/DecimalTests.cpp @@ -958,6 +958,51 @@ namespace Test::Decimal::Tests VERIFY_IS_TRUE(right >= left); } + TEST_METHOD(compare_decimal) + { + const Microsoft::Windows::Foundation::decimal leftDecimal{ L"-12.345" }; + const DECIMAL left{ leftDecimal.to_decimal() }; + const Microsoft::Windows::Foundation::decimal rightDecimal{ L"12.345" }; + const DECIMAL right{ rightDecimal.to_decimal() }; + VERIFY_ARE_EQUAL(0, leftDecimal.compare(left)); + VERIFY_ARE_EQUAL(0, rightDecimal.compare(right)); + VERIFY_ARE_EQUAL(-1, leftDecimal.compare(right)); + VERIFY_ARE_EQUAL(1, rightDecimal.compare(left)); + + VERIFY_ARE_EQUAL(0, compare(left, left)); + VERIFY_ARE_EQUAL(0, compare(right, right)); + VERIFY_ARE_EQUAL(-1, compare(left, right)); + VERIFY_ARE_EQUAL(1, compare(right, left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + TEST_METHOD(operator_pos) { Microsoft::Windows::Foundation::decimal zero(L"0"); @@ -1406,252 +1451,18 @@ namespace Test::Decimal::Tests }; for (size_t index=0; index < ARRAYSIZE(values); ++index) { - WEX::Logging::Log::Comment(L"----------"); - - const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; - const Microsoft::Windows::Foundation::decimal result{ left.mod(right) }; - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s = %s vs %s", - left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); - - //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s mod %s = %s vs %s", - // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); - } - } - - TEST_METHOD(mod) - { - try - { - Microsoft::Windows::Foundation::decimal data{ 123 }; - Microsoft::Windows::Foundation::decimal zero{}; - const auto result{ data / zero }; - VERIFY_FAIL(L"Success is not expected"); - } - catch (wil::ResultException& e) - { - VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); - } - - struct values - { - PCWSTR left; - PCWSTR right; - PCWSTR result; - } values[]{ - { L"1", L"2", L"1" }, - { L"123", L"4567", L"123" }, - { L"1", L"-2", L"1" }, - { L"-1", L"-2", L"-1" }, - { L"-1", L"2", L"-1" }, - { L"1.2", L"3.45", L"1.2" }, - { L"-1.2", L"3.45", L"-1.2" }, - { L"1.2", L"-3.45", L"1.2" }, - { L"-1.2", L"-3.45", L"-1.2" }, - { L".2", L".45", L"0.2" }, - { L"-.2", L".45", L"-0.2" }, - { L".2", L"-.45", L"0.2" }, - { L"-.2", L"-.45", L"-0.2" }, - - { L"2", L"1", L"0" }, - { L"4567", L"123", L"16" }, - { L"-2", L"1", L"0" }, - { L"-2", L"-1", L"0" }, - { L"2", L"-1", L"0" }, - { L"3.45", L"1.2", L"1.05" }, - { L"3.45", L"-1.2", L"1.05" }, - { L"-3.45", L"1.2", L"-1.05" }, - { L"-3.45", L"-1.2", L"-1.05" }, - { L".45", L".2", L"0.05" }, - { L".45", L"-.2", L"0.05" }, - { L"-.45", L".2", L"-0.05" }, - { L"-.45", L"-.2", L"-0.05" } - }; - for (size_t index=0; index < ARRAYSIZE(values); ++index) - { - WEX::Logging::Log::Comment(L"----------"); - const auto& value{ values[index] }; Microsoft::Windows::Foundation::decimal left{ value.left }; Microsoft::Windows::Foundation::decimal right{ value.right }; Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left % right }; - - Microsoft::Windows::Foundation::decimal zero{ 0 }; - const bool left_is_negative{ left < zero }; - const bool right_is_negative{ right < zero }; - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"sign=%s %d", left_is_negative ? L"-" : L"+", left.compare(zero))); - - Microsoft::Windows::Foundation::decimal one{ 1 }; - - Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; - Microsoft::Windows::Foundation::decimal fix{ quotient.integer() }; - Microsoft::Windows::Foundation::decimal product{ fix * right.abs() }; - //Microsoft::Windows::Foundation::decimal remainder{ left_is_negative ? left + product : left - product }; - Microsoft::Windows::Foundation::decimal remainder{ left - product }; - if (right.abs() == one) { remainder = zero; } - else if (left_is_negative && !right_is_negative) { remainder += product; } - else if (left_is_negative && right_is_negative) { remainder = -remainder; } - else if (!left_is_negative && right_is_negative) { remainder += product; } - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"l=%s r=%s q=%s f=%s p=%s r=%s", - left.to_string().c_str(), right.to_string().c_str(), quotient.to_string().c_str(), fix.to_string().c_str(), product.to_string().c_str(), remainder.to_string().c_str())); - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s\n== %s - (FIX(%s / %s) * %s)\n== %s - (%s * %s)\n== %s - %s\n==> %s <--> %s %s", - left.to_string().c_str(), right.to_string().c_str(), - left.to_string().c_str(), left.abs().to_string().c_str(), right.abs().to_string().c_str(), right.abs().to_string().c_str(), - left.to_string().c_str(), fix.abs().to_string().c_str(), right.abs().to_string().c_str(), - left.to_string().c_str(), product.abs().to_string().c_str(), - remainder.to_string().c_str(), expected.to_string().c_str(), (remainder == expected ? L"" : L"********************"))); - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s %% %s = %s vs %s", + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s %% %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); - //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s %% %s = %s vs %s", - // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); - } - - { - Microsoft::Windows::Foundation::decimal zero{}; - Microsoft::Windows::Foundation::decimal one{ 1 }; - - Microsoft::Windows::Foundation::decimal n_1{ L"1" }; - Microsoft::Windows::Foundation::decimal n_2{ L"2" }; - Microsoft::Windows::Foundation::decimal n_2_div_1{ n_2 / n_1 }; - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_1.to_string().c_str(), n_1.integer().to_string().c_str(), n_1.integer().to_string().c_str())); - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_2.to_string().c_str(), n_2.integer().to_string().c_str(), n_2.integer().to_string().c_str())); - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"%s f=%s i=%s", n_2_div_1.to_string().c_str(), n_2_div_1.integer().to_string().c_str(), n_2_div_1.integer().to_string().c_str())); - - const Microsoft::Windows::Foundation::decimal& left{ n_2 }; - const Microsoft::Windows::Foundation::decimal& right{ n_1 }; - - Microsoft::Windows::Foundation::decimal quotient{ left.abs() / right.abs() }; - Microsoft::Windows::Foundation::decimal fix{ quotient.integer() }; - Microsoft::Windows::Foundation::decimal product{ quotient * fix }; - Microsoft::Windows::Foundation::decimal remainder{ left == right || right == one ? zero : left - product }; - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"l=%s r=%s q=%s f=%s p=%s r=%s", - left.to_string().c_str(), right.to_string().c_str(), quotient.to_string().c_str(), fix.to_string().c_str(), product.to_string().c_str(), remainder.to_string().c_str())); - - } - } - - TEST_METHOD(operator_mod_variant_truncated) - { - try - { - Microsoft::Windows::Foundation::decimal data{ 123 }; - Microsoft::Windows::Foundation::decimal zero{}; - const auto result{ data.mod_variant(zero) }; - VERIFY_FAIL(L"Success is not expected"); - } - catch (wil::ResultException& e) - { - VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); - } - - try - { - Microsoft::Windows::Foundation::decimal data{ 123 }; - Microsoft::Windows::Foundation::decimal zero{}; - const auto result{ data.mod_truncated(zero) }; - VERIFY_FAIL(L"Success is not expected"); - } - catch (wil::ResultException& e) - { - VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); - } - - struct values - { - PCWSTR left; - PCWSTR right; - PCWSTR result; - } values[]{ - { L"1", L"2", L"1" }, - { L"123", L"4567", L"123" }, - { L"1", L"-2", L"1" }, - { L"-1", L"-2", L"-1" }, - { L"-1", L"2", L"-1" }, - { L"1.2", L"3.45", L"1.2" }, - { L"-1.2", L"3.45", L"-1.2" }, - { L"1.2", L"-3.45", L"1.2" }, - { L"-1.2", L"-3.45", L"-1.2" }, - { L".2", L".45", L"0.2" }, - { L"-.2", L".45", L"-0.2" }, - { L".2", L"-.45", L"0.2" }, - { L"-.2", L"-.45", L"-0.2" }, - - { L"2", L"1", L"0" }, - { L"4567", L"123", L"16" }, - { L"3.45", L"1.2", L"1.05" }, - { L"2", L"-1", L"0" }, - { L"-2", L"1", L"0" }, - { L"-2", L"-1", L"0" }, - { L"3.45", L"-1.2", L"1.05" }, - { L"-3.45", L"1.2", L"-1.05" }, - { L"-3.45", L"-1.2", L"-1.05" }, - { L".45", L".2", L"0.05" }, - { L".45", L"-.2", L"0.05" }, - { L"-.45", L".2", L"-0.05" }, - { L"-.45", L"-.2", L"-0.05" } - }; - for (size_t index=0; index < ARRAYSIZE(values); ++index) - { - WEX::Logging::Log::Comment(L"----------"); - - try - { - const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; - Microsoft::Windows::Foundation::decimal result_variant; - try - { - result_variant = left.mod_variant(right); - } - catch (std::exception& e) - { - // As explained in https://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero - // - // ...section [expr.mul] specifically states (for both integer and floating point division, and integer remainder): - // If the second operand of / or % is zero, the behavior is undefined. - // So, it could throw those (or any other) exceptions. It could also format your hard disk and laugh derisively :-) - // - // and - // - // Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley, 1994), - // "low-level events, such as arithmetic overflows and divide by zero, are assumed - // to be handled by a dedicated lower-level mechanism rather than by exceptions. - // This enables C++ to match the behaviour of other languages when it comes to - // arithmetic. It also avoids the problems that occur on heavily pipelined - // architectures where events such as divide by zero are asynchronous."` - // - // Our current implementation shows up as a throw exception of type std::exception or - // derived type so we'll catch that and log what what little we know about what went wrong - WEX::Logging::Log::Comment( - WEX::Common::String().Format(L"%s mod_variant %s == std::exception.what: %hs", - left.to_string().c_str(), right.to_string().c_str(), e.what())); - } - const Microsoft::Windows::Foundation::decimal result_truncated{ left.mod_truncated(right) }; - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L" VARIANT: %s %% %s = %s vs %s", - left.to_string().c_str(), right.to_string().c_str(), result_variant.to_string().c_str(), expected.to_string().c_str())); - - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"TRUNCATED: %s %% %s = %s vs %s", - left.to_string().c_str(), right.to_string().c_str(), result_truncated.to_string().c_str(), expected.to_string().c_str())); - - //VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s mod %s = %s vs %s", - // left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); - } - catch (std::exception& e) - { - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"std::exception.what: %hs", e.what())); - //VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.cod(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); - } + Microsoft::Windows::Foundation::decimal result2{ left }; + result2 %= right; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s %%= %s = %s vs %s", + left.to_string().c_str(), right.to_string().c_str(), result2.to_string().c_str(), expected.to_string().c_str())); } } diff --git a/test/Decimal/CS/DecimalTest_CS.csproj b/test/Decimal/CS/DecimalTest_CS.csproj index 3a923c9cf6..d67992768a 100644 --- a/test/Decimal/CS/DecimalTest_CS.csproj +++ b/test/Decimal/CS/DecimalTest_CS.csproj @@ -1,4 +1,4 @@ - + Exe @@ -24,6 +24,24 @@ pdbonly true + + 1701;1702;1718 + + + 1701;1702;1718 + + + 1701;1702;1718 + + + 1701;1702;1718 + + + 1701;1702;1718 + + + 1701;1702;1718 + diff --git a/test/Decimal/CS/DotNetTests.cs b/test/Decimal/CS/DotNetTests.cs index cb8c4e386f..c510e88c89 100644 --- a/test/Decimal/CS/DotNetTests.cs +++ b/test/Decimal/CS/DotNetTests.cs @@ -31,6 +31,14 @@ public static void Run() compare_string(); operator_neg(); abs(); + fix(); + integer(); + operator_add(); + operator_sub(); + operator_mul(); + operator_div(); + operator_mod(); + round(); } public static void ctor() @@ -554,38 +562,70 @@ public static void abs() public static void fix() { + var zero = Decimal.Parse("0"); + var zero_value = (long)zero; + Verify.AreEqual(0, zero.CompareTo(zero_value)); + + var pos = Decimal.Parse("12.345"); + var pos_fix = Decimal.Parse("12"); + var pos_value = (long)pos; + Verify.AreEqual(0, pos_fix.CompareTo(pos_value)); + + var neg = Decimal.Parse("-12.345"); + var neg_fix = Decimal.Parse("-12"); + var neg_value = (long)neg; + Verify.AreEqual(0, neg_fix.CompareTo(neg_value)); } public static void integer() { + var zero = Decimal.Parse("0"); + var zero_value = (long)zero; + Verify.AreEqual(0, zero.CompareTo(zero_value)); + + var pos = Decimal.Parse("12.345"); + var pos_integer = Decimal.Parse("12"); + var pos_value = (long)pos; + Verify.AreEqual(0, pos_integer.CompareTo(pos_value)); + + var neg = Decimal.Parse("-12.345"); + var neg_integer = Decimal.Parse("-13"); + var neg_value = (long)neg; + if ((neg_value < 0) && (neg_value != neg)) + { + --neg_value; + } + Verify.AreEqual(0, neg_integer.CompareTo(neg_value)); } public static void operator_add() { + // TODO operator_add tests } public static void operator_sub() { + // TODO operator_sub tests } public static void operator_mul() { + // TODO operator_mul tests } public static void operator_div() { + // TODO operator_div tests } public static void operator_mod() { - } - - public static void mod() - { + // TODO operator_mod tests } public static void round() { + // TODO round tests } private static Decimal abs(Decimal value) diff --git a/test/Decimal/CS/WinAppSDKTests.cs b/test/Decimal/CS/WinAppSDKTests.cs index e946cf9851..a3c0f38fe4 100644 --- a/test/Decimal/CS/WinAppSDKTests.cs +++ b/test/Decimal/CS/WinAppSDKTests.cs @@ -6,13 +6,248 @@ class DecimalTests { public static void Run() { + ctor(); + ctor_to_assign_bool(); + ctor_to_assign_int16(); + ctor_to_assign_int32(); + ctor_to_assign_int64(); + ctor_to_assign_uint8(); + ctor_to_assign_uint16(); + ctor_to_assign_uint32(); + ctor_to_assign_uint64(); + ctor_to_assign_float(); + ctor_to_assign_double(); + ctor_to_assign_string(); + ctor_to_assign_string_locale_system(); + ctor_to_assign_string_locale_user(); + ctor_to_assign_string_locale_thread(); + ctor_to_assign_string_locale_invariant(); + compare_int16(); + compare_int32(); + compare_int64(); + compare_uint8(); + compare_uint16(); + compare_uint32(); + compare_uint64(); + compare_float(); + compare_double(); + compare_string(); + compare_string_locale_system(); + compare_string_locale_user(); + compare_string_locale_thread(); + compare_string_locale_invariant(); + operator_neg(); + abs(); + fix(); + integer(); + operator_add(); + operator_sub(); + operator_mul(); + operator_div(); + operator_mod(); + round(); } private static void ctor() { //var decimal = new Microsoft.Windows.Foundation.Decimal(); //var long data = decimal.to_int64(); - //Verify + //Verify.AreEqual(0, dec.CompareTo(data); + } + + public static void ctor_to_assign_bool() + { + // TODO ctor_to_assign_bool tests + } + + public static void ctor_to_assign_int16() + { + // TODO ctor_to_assign_int16 tests + } + + public static void ctor_to_assign_int32() + { + // TODO ctor_to_assign_int32 tests + } + + public static void ctor_to_assign_int64() + { + // TODO ctor_to_assign_int64 tests + } + + public static void ctor_to_assign_uint8() + { + // TODO ctor_to_assign_uint8 tests + } + + public static void ctor_to_assign_uint16() + { + // TODO ctor_to_assign_uint16 tests + } + + public static void ctor_to_assign_uint32() + { + // TODO ctor_to_assign_uint32 tests + } + + public static void ctor_to_assign_uint64() + { + // TODO ctor_to_assign_uint64 tests + } + + public static void ctor_to_assign_float() + { + // TODO ctor_to_assign_float tests + } + + public static void ctor_to_assign_double() + { + // TODO ctor_to_assign_double tests + } + + public static void ctor_to_assign_string() + { + // TODO ctor_to_assign_string tests + } + + public static void ctor_to_assign_string_locale_system() + { + // TODO ctor_to_assign_string_locale_system tests + } + + public static void ctor_to_assign_string_locale_user() + { + // TODO ctor_to_assign_string_locale_user tests + } + + public static void ctor_to_assign_string_locale_thread() + { + // TODO ctor_to_assign_string_locale_thread tests + } + + public static void ctor_to_assign_string_locale_invariant() + { + // TODO ctor_to_assign_string_locale_invariant tests + } + + public static void compare_int16() + { + // TODO compare_int16 tests + } + + public static void compare_int32() + { + // TODO compare_int32 tests + } + + public static void compare_int64() + { + // TODO compare_int64 tests + } + + public static void compare_uint8() + { + // TODO compare_uint8 tests + } + + public static void compare_uint16() + { + // TODO compare_uint16 tests + } + + public static void compare_uint32() + { + // TODO compare_uint32 tests + } + + public static void compare_uint64() + { + // TODO compare_uint64 tests + } + + public static void compare_float() + { + // TODO compare_float tests + } + + public static void compare_double() + { + // TODO compare_double tests + } + + public static void compare_string() + { + // TODO compare_string tests + } + + public static void compare_string_locale_system() + { + // TODO compare_string_locale_system + } + + public static void compare_string_locale_user() + { + // TODO compare_string_locale_user + } + + public static void compare_string_locale_thread() + { + // TODO compare_string_locale_thread + } + + public static void compare_string_locale_invariant() + { + // TODO compare_string_locale_invariant + } + + public static void operator_neg() + { + // TODO operator_neg tests + } + + public static void abs() + { + // TODO abs tests + } + + public static void fix() + { + // TODO fix tests + } + + public static void integer() + { + // TODO integer tests + } + + public static void operator_add() + { + // TODO operator_add tests + } + + public static void operator_sub() + { + // TODO operator_sub tests + } + + public static void operator_mul() + { + // TODO operator_mul tests + } + + public static void operator_div() + { + // TODO operator_div tests + } + + public static void operator_mod() + { + // TODO operator_mod tests + } + + public static void round() + { + // TODO round tests } } } diff --git a/test/Decimal/DecimalCalcuator/CS/Program.cs b/test/Decimal/DecimalCalcuator/CS/Program.cs index 7d5cd2c0b7..954da9f2b6 100644 --- a/test/Decimal/DecimalCalcuator/CS/Program.cs +++ b/test/Decimal/DecimalCalcuator/CS/Program.cs @@ -21,10 +21,10 @@ public static void Main(string[] args) // NOTE: Decimal unary operators not supported by C#: ! ~ switch (op) { - case "+": result = +left; Console.Write($"{op}{left} = {result}"); break; - case "-": result = -left; Console.Write($"{op}{left} = {result}"); break; - case "++": result = ++left; Console.Write($"{op}{left} = {result}"); break; - case "--": result = --left; Console.Write($"{op}{left} = {result}"); break; + case "+": result = +left; Output($"{op}{left} = {result}"); break; + case "-": result = -left; Output($"{op}{left} = {result}"); break; + case "++": result = ++left; Output($"{op}{left} = {result}"); break; + case "--": result = --left; Output($"{op}{left} = {result}"); break; case "int32": expected = null; Console.WriteLine($"{op} {left} = {(int)left}"); break; case "int64": expected = null; Console.WriteLine($"{op} {left} = {(long)left}"); break; case "uint32": expected = null; Console.WriteLine($"{op} {left} = {(uint)left}"); break; @@ -39,12 +39,12 @@ public static void Main(string[] args) // NOTE: Decimal unary operators not supported by C#: << >> >>> & | ^ switch (op) { - case "+": result = left + right; Console.Write($"{left} {op} {right} = {result}"); break; - case "-": result = left - right; Console.Write($"{left} {op} {right} = {result}"); break; - case "*": result = left * right; Console.Write($"{left} {op} {right} = {result}"); break; - case "/": result = left / right; Console.Write($"{left} {op} {right} = {result}"); break; - case "%": result = left % right; Console.Write($"{left} {op} {right} = {result}"); break; - case "mod": result = left % right; Console.Write($"{left} {op} {right} = {result}"); break; + case "+": result = left + right; Output($"{left} {op} {right} = {result}"); break; + case "-": result = left - right; Output($"{left} {op} {right} = {result}"); break; + case "*": result = left * right; Output($"{left} {op} {right} = {result}"); break; + case "/": result = left / right; Output($"{left} {op} {right} = {result}"); break; + case "%": result = left % right; Output($"{left} {op} {right} = {result}"); break; + case "mod": result = left % right; Output($"{left} {op} {right} = {result}"); break; case "==": expected = null; Console.WriteLine($"{left} {op} {right} = {left == right}"); break; case "!=": expected = null; Console.WriteLine($"{left} {op} {right} = {left != right}"); break; case "<": expected = null; Console.WriteLine($"{left} {op} {right} = {left < right}"); break; @@ -61,8 +61,14 @@ public static void Main(string[] args) if (expected != null) { Decimal expectedValue = Decimal.Parse(expected); - Console.WriteLine($"\t\t ==> {result} == {expectedValue} = {expectedValue == result}"); + Console.Write($"==> {result} == {expectedValue} = {expectedValue == result}"); } + Console.WriteLine(); + } + + private static void Output(string evaluation) + { + Console.Write($"{evaluation,-32}"); } private static void UnknownOperator(string message) From 535662509e1ffb9b92bda13cd6ca39fdec12d876 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sat, 26 Apr 2025 23:11:50 -0700 Subject: [PATCH 13/25] Fixed formatting error --- test/Decimal/DecimalCalcuator/CS/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Decimal/DecimalCalcuator/CS/Program.cs b/test/Decimal/DecimalCalcuator/CS/Program.cs index 954da9f2b6..2685a69a22 100644 --- a/test/Decimal/DecimalCalcuator/CS/Program.cs +++ b/test/Decimal/DecimalCalcuator/CS/Program.cs @@ -61,9 +61,8 @@ public static void Main(string[] args) if (expected != null) { Decimal expectedValue = Decimal.Parse(expected); - Console.Write($"==> {result} == {expectedValue} = {expectedValue == result}"); + Console.WriteLine($"==> {result} == {expectedValue} = {expectedValue == result}"); } - Console.WriteLine(); } private static void Output(string evaluation) From 5e052ccb2e1580f3b1ba7a875a539ba4f28aab39 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 27 Apr 2025 00:42:31 -0700 Subject: [PATCH 14/25] More tests and fixes --- WindowsAppRuntime.sln | 41 +- dev/Decimal/{ => CPP}/Decimal.idl | 1 + dev/Decimal/{ => CPP}/Decimal.vcxitems | 2 +- .../{ => CPP}/Decimal.vcxitems.filters | 0 dev/Decimal/{ => CPP}/DecimalTelemetry.h | 0 dev/Decimal/{ => CPP}/M.W.F.Decimal.cpp | 4 + dev/Decimal/{ => CPP}/M.W.F.Decimal.h | 1 + dev/Decimal/{ => CPP}/decimal.h | 0 dev/Decimal/{ => CPP}/pch.h | 0 .../Microsoft.Windows.Foundation/WDecimal.cs | 290 +++++ .../WindowsAppRuntime_DLL.vcxproj | 2 +- test/Decimal/CPP/Test.testdef | 2 +- test/Decimal/WinRT/DecimalTest_WinRT.cpp | 1118 +++++++++++++++++ test/Decimal/WinRT/DecimalTest_WinRT.vcxproj | 167 +++ .../WinRT/DecimalTest_WinRT.vcxproj.filters | 33 + test/Decimal/WinRT/Test.testdef | 11 + test/Decimal/WinRT/packages.config | 9 + test/Decimal/WinRT/pch.cpp | 6 + test/Decimal/WinRT/pch.h | 26 + .../appxmanifest.xml | 6 + 20 files changed, 1711 insertions(+), 8 deletions(-) rename dev/Decimal/{ => CPP}/Decimal.idl (98%) rename dev/Decimal/{ => CPP}/Decimal.vcxitems (92%) rename dev/Decimal/{ => CPP}/Decimal.vcxitems.filters (100%) rename dev/Decimal/{ => CPP}/DecimalTelemetry.h (100%) rename dev/Decimal/{ => CPP}/M.W.F.Decimal.cpp (98%) rename dev/Decimal/{ => CPP}/M.W.F.Decimal.h (99%) rename dev/Decimal/{ => CPP}/decimal.h (100%) rename dev/Decimal/{ => CPP}/pch.h (100%) create mode 100644 dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs create mode 100644 test/Decimal/WinRT/DecimalTest_WinRT.cpp create mode 100644 test/Decimal/WinRT/DecimalTest_WinRT.vcxproj create mode 100644 test/Decimal/WinRT/DecimalTest_WinRT.vcxproj.filters create mode 100644 test/Decimal/WinRT/Test.testdef create mode 100644 test/Decimal/WinRT/packages.config create mode 100644 test/Decimal/WinRT/pch.cpp create mode 100644 test/Decimal/WinRT/pch.h diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 69a9c1b759..c091ba3927 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -689,8 +689,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{02EA EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{5012149E-F09F-4F18-A03C-FFE597203821}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Foundation.Projection", "dev\Projections\CS\Microsoft.Windows.Foundation\Microsoft.Windows.Foundation.Projection.csproj", "{8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53}" @@ -720,6 +718,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS", "CS", "{6FE937DC-8AEE- EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecimalCalculator_CS", "test\Decimal\DecimalCalcuator\CS\DecimalCalculator_CS.csproj", "{5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WinRT", "WinRT", "{022E355A-AB24-48EE-9CC0-965BEFDF5E8C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTest_WinRT", "test\Decimal\WinRT\DecimalTest_WinRT.vcxproj", "{E9C055BB-6AE4-497A-A354-D07841E68976}" + ProjectSection(ProjectDependencies) = postProject + {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} = {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} + {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.WindowsAppRuntime.Decimal.Net", "Microsoft.WindowsAppRuntime.Decimal.Net", "{235FA29D-5A17-4EFF-9326-4C126B7511CA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\CPP\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2486,6 +2498,22 @@ Global {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x64.Build.0 = Release|x64 {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x86.ActiveCfg = Release|x86 {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646}.Release|x86.Build.0 = Release|x86 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|Any CPU.ActiveCfg = Debug|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|Any CPU.Build.0 = Debug|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|ARM64.Build.0 = Debug|ARM64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|x64.ActiveCfg = Debug|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|x64.Build.0 = Debug|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|x86.ActiveCfg = Debug|Win32 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Debug|x86.Build.0 = Debug|Win32 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|Any CPU.ActiveCfg = Release|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|Any CPU.Build.0 = Release|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|ARM64.ActiveCfg = Release|ARM64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|ARM64.Build.0 = Release|ARM64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|x64.ActiveCfg = Release|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|x64.Build.0 = Release|x64 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|x86.ActiveCfg = Release|Win32 + {E9C055BB-6AE4-497A-A354-D07841E68976}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2696,7 +2724,6 @@ Global {85C86306-46D1-4563-8303-0A79DF923586} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {5012149E-F09F-4F18-A03C-FFE597203821} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} - {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {5012149E-F09F-4F18-A03C-FFE597203821} {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} = {716C26A0-E6B0-4981-8412-D14A4D410531} {7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {AB515C38-1A93-40FE-917B-1998DCEB811C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} @@ -2706,6 +2733,11 @@ Global {F4F96552-D5B3-4075-A335-ACE45CA6369D} = {A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3} {6FE937DC-8AEE-4191-B6BA-51A32DE27ABE} = {A7A0250E-A0B6-4499-9A41-8EFDCC1D9FD3} {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646} = {6FE937DC-8AEE-4191-B6BA-51A32DE27ABE} + {022E355A-AB24-48EE-9CC0-965BEFDF5E8C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {E9C055BB-6AE4-497A-A354-D07841E68976} = {022E355A-AB24-48EE-9CC0-965BEFDF5E8C} + {26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6} = {5012149E-F09F-4F18-A03C-FFE597203821} + {235FA29D-5A17-4EFF-9326-4C126B7511CA} = {5012149E-F09F-4F18-A03C-FFE597203821} + {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} @@ -2738,7 +2770,6 @@ Global dev\ApplicationData\ApplicationData.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\BackgroundTask\BackgroundTaskBuilder\BackgroundTaskBuilder.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Common\Common.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 - dev\Decimal\Decimal.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\DynamicDependency\API\DynamicDependency.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Licensing\Licensing.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\PackageManager\API\PackageManager.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 @@ -2751,7 +2782,7 @@ Global dev\AccessControl\AccessControl.vcxitems*{c91bcb93-9ed1-4acd-85f3-26f9f6ac52e3}*SharedItemsImports = 9 test\inc\inc.vcxitems*{d5667df6-a151-4081-abc7-b93e8e5604ce}*SharedItemsImports = 4 dev\Deployment\Deployment.vcxitems*{db38fb4d-d04f-4c1d-93e0-f8ae259c5fd6}*SharedItemsImports = 9 - dev\Decimal\Decimal.vcxitems*{dc453de3-18fd-43e7-8103-20763c8b97c8}*SharedItemsImports = 9 + dev\Decimal\CPP\Decimal.vcxitems*{dc453de3-18fd-43e7-8103-20763c8b97c8}*SharedItemsImports = 9 dev\EnvironmentManager\ChangeTracker\ChangeTracker.vcxitems*{e15c3465-9d45-495d-92ce-b91ef45e8623}*SharedItemsImports = 9 dev\AppLifecycle\AppLifecycle.vcxitems*{e3a522a3-6635-4a42-bded-1af46a15f63c}*SharedItemsImports = 9 dev\VersionInfo\VersionInfo.vcxitems*{e3edec7f-a24e-4766-bb1d-6bdfba157c51}*SharedItemsImports = 9 diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/CPP/Decimal.idl similarity index 98% rename from dev/Decimal/Decimal.idl rename to dev/Decimal/CPP/Decimal.idl index ff2bafd34f..cc91df7e01 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/CPP/Decimal.idl @@ -77,6 +77,7 @@ namespace Microsoft.Windows.Foundation String ToStringWithThreadLocale(); // LCID=GetThreadLocale() String ToStringWithInvariantLocale(); // LCID=LOCALE_INVARIANT IInspectable ToObject(); + Decimal ToDecimal(); //TODO: Rename to Copy(value) or Clone(value) ? DecimalValue ToDecimalValue(); /// Return true if (this == value). diff --git a/dev/Decimal/Decimal.vcxitems b/dev/Decimal/CPP/Decimal.vcxitems similarity index 92% rename from dev/Decimal/Decimal.vcxitems rename to dev/Decimal/CPP/Decimal.vcxitems index 19d36c5aca..afdc278ba1 100644 --- a/dev/Decimal/Decimal.vcxitems +++ b/dev/Decimal/CPP/Decimal.vcxitems @@ -26,6 +26,6 @@ - + diff --git a/dev/Decimal/Decimal.vcxitems.filters b/dev/Decimal/CPP/Decimal.vcxitems.filters similarity index 100% rename from dev/Decimal/Decimal.vcxitems.filters rename to dev/Decimal/CPP/Decimal.vcxitems.filters diff --git a/dev/Decimal/DecimalTelemetry.h b/dev/Decimal/CPP/DecimalTelemetry.h similarity index 100% rename from dev/Decimal/DecimalTelemetry.h rename to dev/Decimal/CPP/DecimalTelemetry.h diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/CPP/M.W.F.Decimal.cpp similarity index 98% rename from dev/Decimal/M.W.F.Decimal.cpp rename to dev/Decimal/CPP/M.W.F.Decimal.cpp index 1d5805db18..36801a82d6 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/CPP/M.W.F.Decimal.cpp @@ -220,6 +220,10 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { throw hresult_not_implemented(); } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::ToDecimal() + { + return winrt::make(m_decimal); + } winrt::Microsoft::Windows::Foundation::DecimalValue Decimal::ToDecimalValue() { const auto& decimal{ m_decimal.to_decimal() }; diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/CPP/M.W.F.Decimal.h similarity index 99% rename from dev/Decimal/M.W.F.Decimal.h rename to dev/Decimal/CPP/M.W.F.Decimal.h index 3a8fff5a02..05a4462600 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/CPP/M.W.F.Decimal.h @@ -94,6 +94,7 @@ namespace winrt::Microsoft::Windows::Foundation::implementation hstring ToStringWithThreadLocale(); hstring ToStringWithInvariantLocale(); winrt::Windows::Foundation::IInspectable ToObject(); + winrt::Microsoft::Windows::Foundation::Decimal ToDecimal(); winrt::Microsoft::Windows::Foundation::DecimalValue ToDecimalValue(); bool Equals(winrt::Microsoft::Windows::Foundation::Decimal const& value); int32_t Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value); diff --git a/dev/Decimal/decimal.h b/dev/Decimal/CPP/decimal.h similarity index 100% rename from dev/Decimal/decimal.h rename to dev/Decimal/CPP/decimal.h diff --git a/dev/Decimal/pch.h b/dev/Decimal/CPP/pch.h similarity index 100% rename from dev/Decimal/pch.h rename to dev/Decimal/CPP/pch.h diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs b/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs new file mode 100644 index 0000000000..55a5cf31e9 --- /dev/null +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs @@ -0,0 +1,290 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// +// Exclude this file from StyleCop analysis. This file isn't generated but is added to projects. +// DO NOT MODIFY. Changes to this file may cause incorrect behavior and will be lost on updates. +// + +using System.Runtime.InteropServices; + +namespace Microsoft.Windows.ApplicationModel.DynamicDependency +{ + // The version of an MSIX package. This is logically `Major.Minor.Build.Revision` and can be expressed as... + // * individual `ushort` values (uint16) + // * an unsigned `ulong` value (uint64) + // * a dot-string notation ("major.minor.build.revision") + [StructLayout(LayoutKind.Sequential)] + public struct PackageVersion + { + // NOTE: MUST match memory layout of PACKAGE_VERSION in appmodel.h + public ushort Revision; + public ushort Build; + public ushort Minor; + public ushort Major; + + // Create an instance with the value `major.0.0.0`. + public PackageVersion(ushort major) : + this(major, 0, 0, 0) + { + } + + // Create an instance with the value `major.minor.0.0`. + public PackageVersion(ushort major, ushort minor) : + this(major, minor, 0, 0) + { + } + + // Create an instance with the value `major.minor.build.0`. + public PackageVersion(ushort major, ushort minor, ushort build) : + this(major, minor, build, 0) + { + } + + // Create an instance with the value `major.minor.build.revision`. + public PackageVersion(ushort major, ushort minor, ushort build, ushort revision) + { + Major = major; + Minor = minor; + Build = build; + Revision = revision; + } + + // Create an instance from a version as a uint64. + public PackageVersion(ulong version) : + this((ushort)(version >> 48), (ushort)(version >> 32), (ushort)(version >> 16), (ushort)version) + { + } + + // Return the version as a uint64. + public ulong ToVersion() + { + return (((ulong)Major) << 48) | (((ulong)Minor) << 32) | (((ulong)Build) << 16) | ((ulong)Revision); + } + + // Return the string as a formatted value "major.minor.build.revision". + public override string ToString() + { + return $"{Major}.{Minor}.{Build}.{Revision}"; + } + }; + + internal static class NativeMethods + { + [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", EntryPoint = "MddBootstrapInitialize2", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)] + internal static extern void MddBootstrapInitialize2_Throw(uint majorMinorVersion, string versionTag, PackageVersion packageVersion, Bootstrap.InitializeOptions options); + + [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + internal static extern int MddBootstrapInitialize2(uint majorMinorVersion, string versionTag, PackageVersion packageVersion, Bootstrap.InitializeOptions options); + + [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", ExactSpelling = true)] + internal static extern void MddBootstrapShutdown(); + } + + // The Windows App SDK bootstrap initialization API. + public class Bootstrap + { + /// Options for Bootstrap initialization APIs. + public enum InitializeOptions : int + { + /// Default behavior + None = 0, + + /// If not successful call DebugBreak() + OnError_DebugBreak = 0x0001, + + /// If not successful call DebugBreak() if a debugger is attached to the process + OnError_DebugBreak_IfDebuggerAttached = 0x0002, + + /// If not successful perform a fail-fast + OnError_FailFast = 0x0004, + + /// If a compatible Windows App Runtime framework package is not found show UI + OnNoMatch_ShowUI = 0x0008, + + /// Do nothing (do not error) if the process has package identity + OnPackageIdentity_NOOP = 0x0010, + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `Initialize(majorMinorVersion, null, new PackageVersion(), InitializeOptions.None)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @see Initialize(uint, string) + /// @see Initialize(uint, string, PackageVersion) + /// @see Initialize(uint, string, PackageVersion, InitializeOptions) + /// @see Shutdown() + public static void Initialize(uint majorMinorVersion) + { + Initialize(majorMinorVersion, null); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `Initialize(majorMinorVersion, versionTag, new PackageVersion(), InitializeOptions.None)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @see Initialize(uint) + /// @see Initialize(uint, string, PackageVersion) + /// @see Initialize(uint, string, PackageVersion, InitializeOptions) + /// @see Shutdown() + public static void Initialize(uint majorMinorVersion, string versionTag) + { + Initialize(majorMinorVersion, versionTag, new PackageVersion()); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `Initialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @param minVersion the minimum version to use. + /// @see Initialize(uint) + /// @see Initialize(uint, string) + /// @see Initialize(uint, string, PackageVersion, InitializeOptions) + /// @see Shutdown() + public static void Initialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion) + { + NativeMethods.MddBootstrapInitialize2_Throw(majorMinorVersion, versionTag, minVersion, InitializeOptions.None); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @param minVersion the minimum version to use. + /// @param options optional behavior. + /// @see Initialize(uint) + /// @see Initialize(uint, string) + /// @see Initialize(uint, string, PackageVersion) + /// @see Shutdown() + public static void Initialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, InitializeOptions options) + { + NativeMethods.MddBootstrapInitialize2_Throw(majorMinorVersion, versionTag, minVersion, options); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// Failure returns false with the failure HRESULT in the hresult parameter. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `TryInitialize(majorMinorVersion, null, new PackageVersion(), InitializeOptions.None, hresult)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @retval true if successful, otherwise false is returned. + /// @see TryInitialize(uint, string, out int) + /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions, out int) + /// @see Shutdown() + public static bool TryInitialize(uint majorMinorVersion, out int hresult) + { + return TryInitialize(majorMinorVersion, null, out hresult); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// Failure returns false with the failure HRESULT in the hresult parameter. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `TryInitialize(majorMinorVersion, versionTag, new PackageVersion(), InitializeOptions.None, hresult)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @retval true if successful, otherwise false is returned. + /// @see TryInitialize(uint, out int) + /// @see TryInitialize(uint, string, PackageVersion, out int) + /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions, out int) + /// @see Shutdown() + public static bool TryInitialize(uint majorMinorVersion, string versionTag, out int hresult) + { + var minVersion = new PackageVersion(); + return TryInitialize(majorMinorVersion, versionTag, minVersion, out hresult); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// Failure returns false with the failure HRESULT in the hresult parameter. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// This is equivalent to `TryInitialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None, hresult)`. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @param minVersion the minimum version to use. + /// @param options optional behavior. + /// @param hresult the error code if an error occurred. + /// @retval true if successful, otherwise false is returned. + /// @see TryInitialize(uint, out int) + /// @see TryInitialize(uint, string, out int) + /// @see TryInitialize(uint, string, PackageVersion, out int) + /// @see Shutdown() + public static bool TryInitialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, out int hresult) + { + return TryInitialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None, out hresult); + } + + /// Initialize the calling process to use Windows App SDK's framework package. + /// Failure returns false with the failure HRESULT in the hresult parameter. + /// + /// Find a Windows App SDK framework package meeting the criteria and make it available + /// for use by the current process. If multiple packages meet the criteria the best + /// candidate is selected. + /// + /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). + /// @param versionTag version tag (if any), e.g. "preview1". + /// @param minVersion the minimum version to use. + /// @param options optional behavior. + /// @param hresult the error code if an error occurred. + /// @retval true if successful, otherwise false is returned. + /// @see TryInitialize(uint, out int) + /// @see TryInitialize(uint, string, out int) + /// @see TryInitialize(uint, string, PackageVersion, out int) + /// @see Shutdown() + public static bool TryInitialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, InitializeOptions options, out int hresult) + { + hresult = NativeMethods.MddBootstrapInitialize2(majorMinorVersion, versionTag, minVersion, options); + return hresult >= 0; + } + + /// Undo the changes made by Initialize(). + /// + /// @warning Packages made available via `Initialize()` and + /// the Dynamic Dependencies API should not be used after this call. + /// @see Initialize(uint) + /// @see Initialize(uint, string) + /// @see Initialize(uint, string, PackageVersion) + /// @see Initialize(uint, string, PackageVersion, InitializeOptions options) + /// @see TryInitialize(uint, out int) + /// @see TryInitialize(uint, string, out int) + /// @see TryInitialize(uint, string, PackageVersion, out int) + /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions options, out int) + public static void Shutdown() + { + NativeMethods.MddBootstrapShutdown(); + } + } +} diff --git a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj index a0b5a2c924..060ebb4be2 100644 --- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj +++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj @@ -106,7 +106,7 @@ - + diff --git a/test/Decimal/CPP/Test.testdef b/test/Decimal/CPP/Test.testdef index dc7f2ef914..579b2370ab 100644 --- a/test/Decimal/CPP/Test.testdef +++ b/test/Decimal/CPP/Test.testdef @@ -1,7 +1,7 @@ { "Tests": [ { - "Description": "DecimalTests tests for feature Decimal", + "Description": "C++ decimal tests", "Filename": "DecimalTests.dll", "Parameters": "", "Architectures": ["x86", "x64", "arm64"], diff --git a/test/Decimal/WinRT/DecimalTest_WinRT.cpp b/test/Decimal/WinRT/DecimalTest_WinRT.cpp new file mode 100644 index 0000000000..b0617b6eef --- /dev/null +++ b/test/Decimal/WinRT/DecimalTest_WinRT.cpp @@ -0,0 +1,1118 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include "pch.h" + +#include + +namespace TD = ::Test::Diagnostics; +namespace TB = ::Test::Bootstrap; +namespace TP = ::Test::Packages; +namespace TD = ::Test::Diagnostics; + +namespace WEX::TestExecution +{ + // Teach TAEF how to format a winrt::Microsoft::Windows::Foundation::Decimal + template <> + class VerifyOutputTraits + { + public: + static WEX::Common::NoThrowString ToString(winrt::Microsoft::Windows::Foundation::Decimal const& value) + { + const auto s{ value.ToString() }; + return WEX::Common::NoThrowString().Format(L"\"%s\"", s.c_str()); + } + }; + + // Teach TAEF how to compare a winrt::Microsoft::Windows::Foundation::Decimal + template <> + class VerifyCompareTraits + { + public: + static bool AreEqual(winrt::Microsoft::Windows::Foundation::Decimal const& expected, winrt::Microsoft::Windows::Foundation::Decimal const& actual) + { + return expected.Compare(actual) == 0; + } + + static bool AreSame(winrt::Microsoft::Windows::Foundation::Decimal const& expected, winrt::Microsoft::Windows::Foundation::Decimal const& actual) + { + return &expected == &actual; + } + + static bool IsLessThan(winrt::Microsoft::Windows::Foundation::Decimal const& expectedLess, winrt::Microsoft::Windows::Foundation::Decimal const& expectedGreater) + { + return expectedLess.Compare(expectedGreater) < 0; + } + + static bool IsGreaterThan(winrt::Microsoft::Windows::Foundation::Decimal const& expectedGreater, winrt::Microsoft::Windows::Foundation::Decimal const& expectedLess) + { + return expectedGreater.Compare(expectedLess) > 0; + } + + static bool IsNull(winrt::Microsoft::Windows::Foundation::Decimal const& object) + { + return !!object; + } + }; +} + +namespace Test::Decimal::Tests +{ + class DecimalTest_WinRT + { + public: + BEGIN_TEST_CLASS(DecimalTest_WinRT) + TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") + TEST_CLASS_PROPERTY(L"RunAs", L"RestrictedUser") + END_TEST_CLASS() + + TEST_CLASS_SETUP(ClassSetup) + { + ::TD::DumpExecutionContext(); + ::TB::Setup(TB::Packages::Framework); + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + ::TB::Cleanup(); + return true; + } + + TEST_METHOD(ctor) + { + const std::int64_t data{}; + winrt::Microsoft::Windows::Foundation::Decimal decimal; + const auto value{ decimal.ToInt64() }; + VERIFY_ARE_EQUAL(data, value); + } + + TEST_METHOD(create_to_set_decimal) + { + const std::int32_t dataValue{ -1234567890 }; + winrt::Microsoft::Windows::Foundation::Decimal data(winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(dataValue)); + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromDecimal(data) }; + const auto to{ object.ToDecimal() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromDecimal(data); + const auto to2{ object.ToDecimal() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_bool) + { + const bool data{ true }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromBoolean(data) }; + const auto to{ object.ToBoolean() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromBoolean(data); + const auto to2{ object.ToBoolean() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_int16) + { + const std::int16_t data{ -32109}; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt16(data) }; + const auto to{ object.ToInt16() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromInt16(data); + const auto to2{ object.ToInt16() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_int32) + { + const std::int32_t data{ -1234567890 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(data) }; + const auto to{ object.ToInt32() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromInt32(data); + const auto to2{ object.ToInt32() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_int64) + { + const std::int64_t data{ -1234567890123456789 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt64(data) }; + const auto to{ object.ToInt64() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromInt64(data); + const auto to2{ object.ToInt64() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_uint8) + { + const std::uint8_t data{ 123 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt8(data) }; + const auto to{ object.ToUInt8() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromUInt8(data); + const auto to2{ object.ToUInt16() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_uint16) + { + const std::uint16_t data{ 32109 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt16(data) }; + const auto to{ object.ToUInt16() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromUInt16(data); + const auto to2{ object.ToUInt16() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_uint32) + { + const std::uint32_t data{ 1234567890 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt32(data) }; + const auto to{ object.ToUInt32() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromUInt32(data); + const auto to2{ object.ToUInt32() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_uint64) + { + const std::uint64_t data{ 0xFEDCBA0987654321 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt64(data) }; + const auto to{ object.ToUInt64() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromUInt64(data); + const auto to2{ object.ToUInt64() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_single) + { + const float data{ -1.25 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromSingle(data) }; + const auto to{ object.ToSingle() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromSingle(data); + const auto to2{ object.ToSingle() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_double) + { + const double data{ -1.25 }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromDouble(data) }; + const auto to{ object.ToDouble() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromDouble(data); + const auto to2{ object.ToDouble() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_string) + { + const std::wstring data{ L"-12.345" }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(data) }; + const auto to{ object.ToString() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromString(data); + const auto to2{ object.ToString() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_string_locale_system_default) + { + const winrt::hstring data{ L"-12.345" }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromStringWithSystemDefaultLocale(data) }; + const auto to{ object.ToStringWithSystemDefaultLocale() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromStringWithSystemDefaultLocale(data); + const auto to2{ object.ToStringWithSystemDefaultLocale() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_string_locale_user_default) + { + const winrt::hstring data{ L"-12.345" }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromStringWithUserDefaultLocale(data) }; + const auto to{ object.ToStringWithUserDefaultLocale() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromStringWithUserDefaultLocale(data); + const auto to2{ object.ToStringWithUserDefaultLocale() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_string_locale_thread) + { + const winrt::hstring data{ L"-12.345" }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromStringWithThreadLocale(data) }; + const auto to{ object.ToStringWithThreadLocale() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromStringWithThreadLocale(data); + const auto to2{ object.ToStringWithThreadLocale() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(create_to_set_string_locale_invariant) + { + const winrt::hstring data{ L"-12.345" }; + winrt::Microsoft::Windows::Foundation::Decimal object{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromStringWithInvariantLocale(data) }; + const auto to{ object.ToStringWithInvariantLocale() }; + VERIFY_ARE_EQUAL(data, to); + + winrt::Microsoft::Windows::Foundation::Decimal object2; + object2.SetFromStringWithInvariantLocale(data); + const auto to2{ object.ToStringWithInvariantLocale() }; + VERIFY_ARE_EQUAL(data, to2); + } + + TEST_METHOD(compare_bool) + { + winrt::Microsoft::Windows::Foundation::Decimal decimal_false{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromBoolean(false) }; + winrt::Microsoft::Windows::Foundation::Decimal decimal_true{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromBoolean(true) }; + VERIFY_ARE_EQUAL(0, decimal_false.Compare(decimal_false)); + VERIFY_ARE_EQUAL(0, decimal_true.Compare(decimal_true)); + VERIFY_ARE_EQUAL(-1, decimal_false.Compare(decimal_true)); + VERIFY_ARE_EQUAL(1, decimal_true.Compare(decimal_false)); + + VERIFY_IS_TRUE(decimal_true == decimal_true); + VERIFY_IS_FALSE(decimal_true != decimal_true); + VERIFY_IS_FALSE(decimal_true < decimal_true); + VERIFY_IS_TRUE(decimal_true <= decimal_true); + VERIFY_IS_FALSE(decimal_true > decimal_true); + VERIFY_IS_TRUE(decimal_true >= decimal_true); + } + + TEST_METHOD(compare_int16) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt16(static_cast(-32109)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt16(static_cast(32109)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_int32) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(static_cast(-1234567890)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(static_cast(1234567890)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_int64) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt64(static_cast(-1234567890123456789)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt64(static_cast(1234567890123456789)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_uint8) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt8(static_cast(123)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt8(static_cast(234)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_uint16) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt16(static_cast(32109)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt16(static_cast(65432)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_uint32) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt32(static_cast(1234567890)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt32(static_cast(4019283756)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_uint64) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt64(static_cast(0x1234567890ABCDEF)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromUInt64(static_cast(0xFEDCBA0987654321)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_float) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromSingle(static_cast(-1.25)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromSingle(static_cast(1.25)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_double) + { + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromDouble(static_cast(-1.25)) }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromDouble(static_cast(1.25)) }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_string) + { + const winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"-12.345") }; + const winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"12.345") }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(compare_decimal) + { + const winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"-12.345") }; + const winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"12.345") }; + VERIFY_ARE_EQUAL(0, left.Compare(left)); + VERIFY_ARE_EQUAL(0, right.Compare(right)); + VERIFY_ARE_EQUAL(-1, left.Compare(right)); + VERIFY_ARE_EQUAL(1, right.Compare(left)); + + VERIFY_IS_TRUE(left == left); + VERIFY_IS_FALSE(left != left); + VERIFY_IS_FALSE(left < left); + VERIFY_IS_TRUE(left <= left); + VERIFY_IS_FALSE(left > left); + VERIFY_IS_TRUE(left >= left); + + VERIFY_IS_TRUE(right == right); + VERIFY_IS_FALSE(right != right); + VERIFY_IS_FALSE(right < right); + VERIFY_IS_TRUE(right <= right); + VERIFY_IS_FALSE(right > right); + VERIFY_IS_TRUE(right >= right); + + VERIFY_IS_FALSE(left == right); + VERIFY_IS_TRUE(left != right); + VERIFY_IS_TRUE(left < right); + VERIFY_IS_TRUE(left <= right); + VERIFY_IS_FALSE(left > right); + VERIFY_IS_FALSE(left >= right); + + VERIFY_IS_FALSE(right == left); + VERIFY_IS_TRUE(right != left); + VERIFY_IS_FALSE(right < left); + VERIFY_IS_FALSE(right <= left); + VERIFY_IS_TRUE(right > left); + VERIFY_IS_TRUE(right >= left); + } + + TEST_METHOD(negate) + { + winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; + winrt::Microsoft::Windows::Foundation::Decimal pos{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal neg{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12.345" }) }; + + const auto zero_value{ zero.Negate() }; + VERIFY_IS_TRUE(zero_value == zero); + VERIFY_IS_TRUE(zero_value != pos); + VERIFY_IS_TRUE(zero_value != neg); + VERIFY_IS_TRUE(zero_value < pos); + VERIFY_IS_TRUE(zero_value > neg); + + const auto pos_value{ neg.Negate() }; + VERIFY_IS_TRUE(pos_value != zero); + VERIFY_IS_TRUE(pos_value == pos); + VERIFY_IS_TRUE(pos_value != neg); + VERIFY_IS_TRUE(pos_value > zero); + VERIFY_IS_TRUE(pos_value > neg); + + const auto neg_value{ pos.Negate() }; + VERIFY_IS_TRUE(neg_value != zero); + VERIFY_IS_TRUE(neg_value != pos); + VERIFY_IS_TRUE(neg_value == neg); + VERIFY_IS_TRUE(neg_value < zero); + VERIFY_IS_TRUE(neg_value < pos); + } + + TEST_METHOD(abs) + { + winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; + winrt::Microsoft::Windows::Foundation::Decimal pos{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal neg{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12.345" }) }; + + const auto zero_value{ zero.Abs() }; + VERIFY_IS_TRUE(zero_value == zero); + VERIFY_IS_TRUE(zero_value != pos); + VERIFY_IS_TRUE(zero_value != neg); + VERIFY_IS_TRUE(zero_value < pos); + VERIFY_IS_TRUE(zero_value > neg); + + const auto pos_value{ pos.Abs() }; + VERIFY_IS_TRUE(pos_value != zero); + VERIFY_IS_TRUE(pos_value == pos); + VERIFY_IS_TRUE(pos_value != neg); + VERIFY_IS_TRUE(pos_value > zero); + VERIFY_IS_TRUE(pos_value > neg); + + const auto neg_value{ neg.Abs() }; + VERIFY_IS_TRUE(neg_value != zero); + VERIFY_IS_TRUE(neg_value == pos); + VERIFY_IS_TRUE(neg_value != neg); + VERIFY_IS_TRUE(neg_value > zero); + VERIFY_IS_TRUE(neg_value == pos); + } + + TEST_METHOD(fix) + { + winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; + const auto value{ zero.Fix() }; + VERIFY_IS_TRUE(value == zero); + + winrt::Microsoft::Windows::Foundation::Decimal pos{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal pos_fix{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12" }) }; + const auto pos_value{ pos.Fix() }; + VERIFY_IS_TRUE(pos_value == pos_fix); + + winrt::Microsoft::Windows::Foundation::Decimal neg{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal neg_fix{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12" }) }; + const auto neg_value{ neg.Fix() }; + VERIFY_IS_TRUE(neg_value == neg_fix); + } + + TEST_METHOD(integer) + { + winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; + const auto value{ zero.Integer() }; + VERIFY_IS_TRUE(value == zero); + + winrt::Microsoft::Windows::Foundation::Decimal pos{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal pos_integer{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12" }) }; + const auto pos_value{ pos.Integer() }; + VERIFY_IS_TRUE(pos_value == pos_integer); + + winrt::Microsoft::Windows::Foundation::Decimal neg{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12.345" }) }; + winrt::Microsoft::Windows::Foundation::Decimal neg_integer{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-13" }) }; + const auto neg_value{ neg.Integer() }; + VERIFY_IS_TRUE(neg_value == neg_integer); + } + + TEST_METHOD(operator_add) + { + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"3" }, + { L"123", L"4567", L"4690" }, + { L"1", L"-2", L"-1" }, + { L"-1", L"-2", L"-3" }, + { L"-1", L"2", L"1" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"4.65" }, + { L"-1.2", L"3.45", L"2.25" }, + { L"1.2", L"-3.45", L"-2.25" }, + { L"-1.2", L"-3.45", L"-4.65" }, + { L".2", L".45", L".65" }, + { L"-.2", L".45", L".25" }, + { L".2", L"-.45", L"-.25" }, + { L"-.2", L"-.45", L"-.65" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const winrt::hstring leftString{ value.left }; + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(leftString) }; + const winrt::hstring rightString{ value.right }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(rightString) }; + const winrt::hstring expectedString{ value.result }; + winrt::Microsoft::Windows::Foundation::Decimal expected{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(expectedString) }; + const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Add(right) }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Add %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); + + winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; + result2.AddAssign(right); + VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s AddAssign %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); + } + } + + TEST_METHOD(operator_subtract) + { + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"-1" }, + { L"123", L"4567", L"-4444" }, + { L"1", L"-2", L"3" }, + { L"-1", L"-2", L"1" }, + { L"-1", L"2", L"-3" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"-2.25" }, + { L"-1.2", L"3.45", L"-4.65" }, + { L"1.2", L"-3.45", L"4.65" }, + { L"-1.2", L"-3.45", L"2.25" }, + { L".2", L".45", L"-.25" }, + { L"-.2", L".45", L"-.65" }, + { L".2", L"-.45", L".65" }, + { L"-.2", L"-.45", L".25" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const winrt::hstring leftString{ value.left }; + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(leftString) }; + const winrt::hstring rightString{ value.right }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(rightString) }; + const winrt::hstring expectedString{ value.result }; + winrt::Microsoft::Windows::Foundation::Decimal expected{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(expectedString) }; + const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Sub(right) }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Sub %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); + + winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; + result2.SubAssign(right); + VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s SubAssign %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); + } + } + + TEST_METHOD(operator_multiply) + { + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"0", L"0", L"0" }, + { L"1", L"2", L"2" }, + { L"123", L"4567", L"561741" }, + { L"1", L"-2", L"-2" }, + { L"-1", L"-2", L"2" }, + { L"-1", L"2", L"-2" }, + { L"-0", L"-0", L"0" }, + { L"-0", L"0", L"0" }, + { L"0", L"-0", L"0" }, + { L"1.2", L"3.45", L"4.140" }, + { L"-1.2", L"3.45", L"-4.140" }, + { L"1.2", L"-3.45", L"-4.140" }, + { L"-1.2", L"-3.45", L"4.140" }, + { L".2", L".45", L"0.090" }, + { L"-.2", L".45", L"-0.090" }, + { L".2", L"-.45", L"-0.090" }, + { L"-.2", L"-.45", L"0.090" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const winrt::hstring leftString{ value.left }; + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(leftString) }; + const winrt::hstring rightString{ value.right }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(rightString) }; + const winrt::hstring expectedString{ value.result }; + winrt::Microsoft::Windows::Foundation::Decimal expected{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(expectedString) }; + const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Mul(right) }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Mul %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); + + winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; + result2.MulAssign(right); + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s MulAssign %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); + } + } + + TEST_METHOD(operator_divide) + { + try + { + winrt::Microsoft::Windows::Foundation::Decimal data{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(123) }; + winrt::Microsoft::Windows::Foundation::Decimal zero{}; + const auto result{ data.Div(zero) }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"0.5" }, + { L"123", L"4567", L"0.0269323407050580249616816291" }, + { L"1", L"-2", L"-0.5" }, + { L"-1", L"-2", L"0.5" }, + { L"-1", L"2", L"-0.5" }, + { L"1.2", L"3.45", L"0.3478260869565217391304347826" }, + { L"-1.2", L"3.45", L"-0.3478260869565217391304347826" }, + { L"1.2", L"-3.45", L"-0.3478260869565217391304347826" }, + { L"-1.2", L"-3.45", L"0.3478260869565217391304347826" }, + { L".2", L".45", L"0.4444444444444444444444444444" }, + { L"-.2", L".45", L"-0.4444444444444444444444444444" }, + { L".2", L"-.45", L"-0.4444444444444444444444444444" }, + { L"-.2", L"-.45", L"0.4444444444444444444444444444" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const winrt::hstring leftString{ value.left }; + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(leftString) }; + const winrt::hstring rightString{ value.right }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(rightString) }; + const winrt::hstring expectedString{ value.result }; + winrt::Microsoft::Windows::Foundation::Decimal expected{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(expectedString) }; + const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Div(right) }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Div %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); + + winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; + result2.DivAssign(right); + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s DivAssign %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); + } + } + + TEST_METHOD(operator_mod) + { + try + { + winrt::Microsoft::Windows::Foundation::Decimal data{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromInt32(123) }; + winrt::Microsoft::Windows::Foundation::Decimal zero{}; + const auto result{ data.Mod(zero) }; + VERIFY_FAIL(L"Success is not expected"); + } + catch (wil::ResultException& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); + } + + struct values + { + PCWSTR left; + PCWSTR right; + PCWSTR result; + } values[]{ + { L"1", L"2", L"1" }, + { L"123", L"4567", L"123" }, + { L"1", L"-2", L"1" }, + { L"-1", L"-2", L"-1" }, + { L"-1", L"2", L"-1" }, + { L"1.2", L"3.45", L"1.2" }, + { L"-1.2", L"3.45", L"-1.2" }, + { L"1.2", L"-3.45", L"1.2" }, + { L"-1.2", L"-3.45", L"-1.2" }, + { L".2", L".45", L"0.2" }, + { L"-.2", L".45", L"-0.2" }, + { L".2", L"-.45", L"0.2" }, + { L"-.2", L"-.45", L"-0.2" }, + + { L"2", L"1", L"0" }, + { L"4567", L"123", L"16" }, + { L"3.45", L"1.2", L"1.05" }, + { L"2", L"-1", L"0" }, + { L"-2", L"1", L"0" }, + { L"-2", L"-1", L"0" }, + { L"3.45", L"-1.2", L"1.05" }, + { L"-3.45", L"1.2", L"-1.05" }, + { L"-3.45", L"-1.2", L"-1.05" }, + { L".45", L".2", L"0.05" }, + { L".45", L"-.2", L"0.05" }, + { L"-.45", L".2", L"-0.05" }, + { L"-.45", L"-.2", L"-0.05" } + }; + for (size_t index=0; index < ARRAYSIZE(values); ++index) + { + const auto& value{ values[index] }; + const winrt::hstring leftString{ value.left }; + winrt::Microsoft::Windows::Foundation::Decimal left{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(leftString) }; + const winrt::hstring rightString{ value.right }; + winrt::Microsoft::Windows::Foundation::Decimal right{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(rightString) }; + const winrt::hstring expectedString{ value.result }; + winrt::Microsoft::Windows::Foundation::Decimal expected{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(expectedString) }; + const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Mod(right) }; + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Mod %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); + + winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; + result2.ModAssign(right); + VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s ModAssign %s = %s vs %s", + left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); + } + } + + TEST_METHOD(operator_round) + { + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.888") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_neg1_888{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"-1.888") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_1_25{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.25") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_neg1_25{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"-1.25") }; + + const winrt::Microsoft::Windows::Foundation::Decimal n_2{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"2") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_1_9{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.9") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_1_89{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.89") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_neg1_9{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.9") }; + const winrt::Microsoft::Windows::Foundation::Decimal n_neg1_89{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(L"1.89") }; + + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888_round_0{ n_1_888.Round(0) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.Round(0) = %s vs %s", + n_1_888.ToString().c_str(), n_1_888_round_0.ToString().c_str(), n_2.ToString().c_str())); + + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888_round_1{ n_1_888.Round(1) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.Round(0) = %s vs %s", + n_1_888.ToString().c_str(), n_1_888_round_1.ToString().c_str(), n_1_9.ToString().c_str())); + + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888_round_2{ n_1_888.Round(2) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.Round(0) = %s vs %s", + n_1_888.ToString().c_str(), n_1_888_round_2.ToString().c_str(), n_1_89.ToString().c_str())); + + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888_round_3{ n_1_888.Round(3) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.Round(0) = %s vs %s", + n_1_888.ToString().c_str(), n_1_888_round_3.ToString().c_str(), n_1_888.ToString().c_str())); + + const winrt::Microsoft::Windows::Foundation::Decimal n_1_888_round_4{ n_1_888.Round(4) }; + VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.Round(0) = %s vs %s", + n_1_888.ToString().c_str(), n_1_888_round_4.ToString().c_str(), n_1_888.ToString().c_str())); + } + }; +} diff --git a/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj b/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj new file mode 100644 index 0000000000..318a5e480c --- /dev/null +++ b/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj @@ -0,0 +1,167 @@ + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 16.0 + {E9C055BB-6AE4-497a-A354-D07841E68976} + Win32Proj + DecimalTest_WinRT + 10.0 + NativeUnitTestProject + DecimalTest_WinRT + + + DynamicLibrary + false + v143 + Unicode + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + Use + true + pch.h + $(RepoRoot)\test\inc;$(RepoRoot)\dev\common;$(VCInstallDir)UnitTest\include;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)\..\WindowsAppRuntime_BootstrapDLL;%(AdditionalIncludeDirectories) + $(RepoRoot);%(AdditionalIncludeDirectories) + + + Windows + onecore.lib;onecoreuap.lib;Microsoft.WindowsAppRuntime.lib;wex.common.lib;wex.logger.lib;te.common.lib;%(AdditionalDependencies) + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories);$(OutDir)\..\WindowsAppRuntime_DLL + Microsoft.WindowsAppRuntime.Bootstrap.dll;%(DelayLoadDLLs) + Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs) + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + WIN32;%(PreprocessorDefinitions) + + + + + Create + + + + + + + + + + + + $(OutDir)\..\WindowsAppRuntime_DLL\Microsoft.Windows.Foundation.winmd + true + + + + + $(OutDir)\..\WindowsAppRuntime_DLL\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd + true + + + + + + + + {f76b776e-86f5-48c5-8fc7-d2795ecc9746} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + diff --git a/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj.filters b/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj.filters new file mode 100644 index 0000000000..0cb73aeaad --- /dev/null +++ b/test/Decimal/WinRT/DecimalTest_WinRT.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + + + + diff --git a/test/Decimal/WinRT/Test.testdef b/test/Decimal/WinRT/Test.testdef new file mode 100644 index 0000000000..1958bbc7c3 --- /dev/null +++ b/test/Decimal/WinRT/Test.testdef @@ -0,0 +1,11 @@ +{ + "Tests": [ + { + "Description": "WinRT Decimal tests", + "Filename": "DecimalTest_WinRT.dll", + "Parameters": "", + "Architectures": ["x86", "x64", "arm64"], + "Status": "Enabled" + } + ] +} diff --git a/test/Decimal/WinRT/packages.config b/test/Decimal/WinRT/packages.config new file mode 100644 index 0000000000..0c13ff7b9c --- /dev/null +++ b/test/Decimal/WinRT/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/Decimal/WinRT/pch.cpp b/test/Decimal/WinRT/pch.cpp new file mode 100644 index 0000000000..f59e66e263 --- /dev/null +++ b/test/Decimal/WinRT/pch.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" diff --git a/test/Decimal/WinRT/pch.h b/test/Decimal/WinRT/pch.h new file mode 100644 index 0000000000..1d9596445a --- /dev/null +++ b/test/Decimal/WinRT/pch.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#ifndef PCH_H +#define PCH_H + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#endif //PCH_H diff --git a/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml b/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml index 7666d7f656..ddd0772a2a 100644 --- a/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml +++ b/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml @@ -116,6 +116,12 @@ + + + Microsoft.WindowsAppRuntime.dll + + + Microsoft.WindowsAppRuntime.dll From cfc26274dbf638d4616529870cf10b3c09a2f0cd Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 27 Apr 2025 01:16:13 -0700 Subject: [PATCH 15/25] more fixups --- WindowsAppRuntime.sln | 12 +- dev/Decimal/{CPP => }/Decimal.idl | 0 dev/Decimal/{CPP => }/Decimal.vcxitems | 2 +- .../{CPP => }/Decimal.vcxitems.filters | 0 dev/Decimal/{CPP => }/DecimalTelemetry.h | 0 dev/Decimal/{CPP => }/M.W.F.Decimal.cpp | 0 dev/Decimal/{CPP => }/M.W.F.Decimal.h | 0 dev/Decimal/{CPP => }/decimal.h | 0 dev/Decimal/{CPP => }/pch.h | 0 ...osoft.Windows.Foundation.Projection.csproj | 6 + .../Microsoft.Windows.Foundation/WDecimal.cs | 284 ++---------------- .../WindowsAppRuntime_DLL.vcxproj | 2 +- test/Decimal/DecimalCalcuator/CS/Program.cs | 8 +- 13 files changed, 34 insertions(+), 280 deletions(-) rename dev/Decimal/{CPP => }/Decimal.idl (100%) rename dev/Decimal/{CPP => }/Decimal.vcxitems (92%) rename dev/Decimal/{CPP => }/Decimal.vcxitems.filters (100%) rename dev/Decimal/{CPP => }/DecimalTelemetry.h (100%) rename dev/Decimal/{CPP => }/M.W.F.Decimal.cpp (100%) rename dev/Decimal/{CPP => }/M.W.F.Decimal.h (100%) rename dev/Decimal/{CPP => }/decimal.h (100%) rename dev/Decimal/{CPP => }/pch.h (100%) diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index c091ba3927..5b99583a96 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -726,11 +726,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTest_WinRT", "test\D {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.WindowsAppRuntime.Decimal.Net", "Microsoft.WindowsAppRuntime.Decimal.Net", "{235FA29D-5A17-4EFF-9326-4C126B7511CA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\CPP\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -2735,9 +2731,7 @@ Global {5B07A0BE-62CD-C63A-5B0C-5CA48A98A646} = {6FE937DC-8AEE-4191-B6BA-51A32DE27ABE} {022E355A-AB24-48EE-9CC0-965BEFDF5E8C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {E9C055BB-6AE4-497A-A354-D07841E68976} = {022E355A-AB24-48EE-9CC0-965BEFDF5E8C} - {26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6} = {5012149E-F09F-4F18-A03C-FFE597203821} - {235FA29D-5A17-4EFF-9326-4C126B7511CA} = {5012149E-F09F-4F18-A03C-FFE597203821} - {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {26127BDD-A9F3-49BF-A3ED-2EAE3177FFD6} + {DC453DE3-18FD-43E7-8103-20763C8B97C8} = {5012149E-F09F-4F18-A03C-FFE597203821} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} @@ -2782,7 +2776,7 @@ Global dev\AccessControl\AccessControl.vcxitems*{c91bcb93-9ed1-4acd-85f3-26f9f6ac52e3}*SharedItemsImports = 9 test\inc\inc.vcxitems*{d5667df6-a151-4081-abc7-b93e8e5604ce}*SharedItemsImports = 4 dev\Deployment\Deployment.vcxitems*{db38fb4d-d04f-4c1d-93e0-f8ae259c5fd6}*SharedItemsImports = 9 - dev\Decimal\CPP\Decimal.vcxitems*{dc453de3-18fd-43e7-8103-20763c8b97c8}*SharedItemsImports = 9 + dev\Decimal\Decimal.vcxitems*{dc453de3-18fd-43e7-8103-20763c8b97c8}*SharedItemsImports = 9 dev\EnvironmentManager\ChangeTracker\ChangeTracker.vcxitems*{e15c3465-9d45-495d-92ce-b91ef45e8623}*SharedItemsImports = 9 dev\AppLifecycle\AppLifecycle.vcxitems*{e3a522a3-6635-4a42-bded-1af46a15f63c}*SharedItemsImports = 9 dev\VersionInfo\VersionInfo.vcxitems*{e3edec7f-a24e-4766-bb1d-6bdfba157c51}*SharedItemsImports = 9 diff --git a/dev/Decimal/CPP/Decimal.idl b/dev/Decimal/Decimal.idl similarity index 100% rename from dev/Decimal/CPP/Decimal.idl rename to dev/Decimal/Decimal.idl diff --git a/dev/Decimal/CPP/Decimal.vcxitems b/dev/Decimal/Decimal.vcxitems similarity index 92% rename from dev/Decimal/CPP/Decimal.vcxitems rename to dev/Decimal/Decimal.vcxitems index afdc278ba1..19d36c5aca 100644 --- a/dev/Decimal/CPP/Decimal.vcxitems +++ b/dev/Decimal/Decimal.vcxitems @@ -26,6 +26,6 @@ - + diff --git a/dev/Decimal/CPP/Decimal.vcxitems.filters b/dev/Decimal/Decimal.vcxitems.filters similarity index 100% rename from dev/Decimal/CPP/Decimal.vcxitems.filters rename to dev/Decimal/Decimal.vcxitems.filters diff --git a/dev/Decimal/CPP/DecimalTelemetry.h b/dev/Decimal/DecimalTelemetry.h similarity index 100% rename from dev/Decimal/CPP/DecimalTelemetry.h rename to dev/Decimal/DecimalTelemetry.h diff --git a/dev/Decimal/CPP/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp similarity index 100% rename from dev/Decimal/CPP/M.W.F.Decimal.cpp rename to dev/Decimal/M.W.F.Decimal.cpp diff --git a/dev/Decimal/CPP/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h similarity index 100% rename from dev/Decimal/CPP/M.W.F.Decimal.h rename to dev/Decimal/M.W.F.Decimal.h diff --git a/dev/Decimal/CPP/decimal.h b/dev/Decimal/decimal.h similarity index 100% rename from dev/Decimal/CPP/decimal.h rename to dev/Decimal/decimal.h diff --git a/dev/Decimal/CPP/pch.h b/dev/Decimal/pch.h similarity index 100% rename from dev/Decimal/CPP/pch.h rename to dev/Decimal/pch.h diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj b/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj index 25d6902147..af2923c8eb 100644 --- a/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/Microsoft.Windows.Foundation.Projection.csproj @@ -49,4 +49,10 @@ + + + $(OutDir)..\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Foundation.winmd + true + + diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs b/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs index 55a5cf31e9..99fccf8c64 100644 --- a/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs @@ -1,290 +1,44 @@ -// Copyright (c) Microsoft Corporation and Contributors. +// Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. -// -// Exclude this file from StyleCop analysis. This file isn't generated but is added to projects. -// DO NOT MODIFY. Changes to this file may cause incorrect behavior and will be lost on updates. -// +using Microsoft.Windows.Foundation; -using System.Runtime.InteropServices; - -namespace Microsoft.Windows.ApplicationModel.DynamicDependency +namespace Microsoft.Windows.Foundation { - // The version of an MSIX package. This is logically `Major.Minor.Build.Revision` and can be expressed as... - // * individual `ushort` values (uint16) - // * an unsigned `ulong` value (uint64) - // * a dot-string notation ("major.minor.build.revision") - [StructLayout(LayoutKind.Sequential)] - public struct PackageVersion + public class WDecimal { - // NOTE: MUST match memory layout of PACKAGE_VERSION in appmodel.h - public ushort Revision; - public ushort Build; - public ushort Minor; - public ushort Major; - - // Create an instance with the value `major.0.0.0`. - public PackageVersion(ushort major) : - this(major, 0, 0, 0) - { - } - - // Create an instance with the value `major.minor.0.0`. - public PackageVersion(ushort major, ushort minor) : - this(major, minor, 0, 0) - { - } - - // Create an instance with the value `major.minor.build.0`. - public PackageVersion(ushort major, ushort minor, ushort build) : - this(major, minor, build, 0) - { - } - - // Create an instance with the value `major.minor.build.revision`. - public PackageVersion(ushort major, ushort minor, ushort build, ushort revision) + public WDecimal() { - Major = major; - Minor = minor; - Build = build; - Revision = revision; } - // Create an instance from a version as a uint64. - public PackageVersion(ulong version) : - this((ushort)(version >> 48), (ushort)(version >> 32), (ushort)(version >> 16), (ushort)version) + public WDecimal(WDecimal value) { + m_value = value.m_value.ToDecimal(); } - // Return the version as a uint64. - public ulong ToVersion() + public WDecimal(Microsoft.Windows.Foundation.Decimal value) { - return (((ulong)Major) << 48) | (((ulong)Minor) << 32) | (((ulong)Build) << 16) | ((ulong)Revision); + m_value = value; } - // Return the string as a formatted value "major.minor.build.revision". - public override string ToString() + public static WDecimal operator +(WDecimal left, WDecimal right) { - return $"{Major}.{Minor}.{Build}.{Revision}"; + return new WDecimal(left.m_value.Add(right.m_value)); } - }; - internal static class NativeMethods - { - [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", EntryPoint = "MddBootstrapInitialize2", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)] - internal static extern void MddBootstrapInitialize2_Throw(uint majorMinorVersion, string versionTag, PackageVersion packageVersion, Bootstrap.InitializeOptions options); - - [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern int MddBootstrapInitialize2(uint majorMinorVersion, string versionTag, PackageVersion packageVersion, Bootstrap.InitializeOptions options); - - [DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", ExactSpelling = true)] - internal static extern void MddBootstrapShutdown(); + private Microsoft.Windows.Foundation.Decimal m_value = new Microsoft.Windows.Foundation.Decimal(); } - // The Windows App SDK bootstrap initialization API. - public class Bootstrap + public static class DecimalExtensions { - /// Options for Bootstrap initialization APIs. - public enum InitializeOptions : int - { - /// Default behavior - None = 0, - - /// If not successful call DebugBreak() - OnError_DebugBreak = 0x0001, - - /// If not successful call DebugBreak() if a debugger is attached to the process - OnError_DebugBreak_IfDebuggerAttached = 0x0002, - - /// If not successful perform a fail-fast - OnError_FailFast = 0x0004, - - /// If a compatible Windows App Runtime framework package is not found show UI - OnNoMatch_ShowUI = 0x0008, - - /// Do nothing (do not error) if the process has package identity - OnPackageIdentity_NOOP = 0x0010, - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `Initialize(majorMinorVersion, null, new PackageVersion(), InitializeOptions.None)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @see Initialize(uint, string) - /// @see Initialize(uint, string, PackageVersion) - /// @see Initialize(uint, string, PackageVersion, InitializeOptions) - /// @see Shutdown() - public static void Initialize(uint majorMinorVersion) - { - Initialize(majorMinorVersion, null); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `Initialize(majorMinorVersion, versionTag, new PackageVersion(), InitializeOptions.None)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @see Initialize(uint) - /// @see Initialize(uint, string, PackageVersion) - /// @see Initialize(uint, string, PackageVersion, InitializeOptions) - /// @see Shutdown() - public static void Initialize(uint majorMinorVersion, string versionTag) - { - Initialize(majorMinorVersion, versionTag, new PackageVersion()); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `Initialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @param minVersion the minimum version to use. - /// @see Initialize(uint) - /// @see Initialize(uint, string) - /// @see Initialize(uint, string, PackageVersion, InitializeOptions) - /// @see Shutdown() - public static void Initialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion) - { - NativeMethods.MddBootstrapInitialize2_Throw(majorMinorVersion, versionTag, minVersion, InitializeOptions.None); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @param minVersion the minimum version to use. - /// @param options optional behavior. - /// @see Initialize(uint) - /// @see Initialize(uint, string) - /// @see Initialize(uint, string, PackageVersion) - /// @see Shutdown() - public static void Initialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, InitializeOptions options) - { - NativeMethods.MddBootstrapInitialize2_Throw(majorMinorVersion, versionTag, minVersion, options); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// Failure returns false with the failure HRESULT in the hresult parameter. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `TryInitialize(majorMinorVersion, null, new PackageVersion(), InitializeOptions.None, hresult)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @retval true if successful, otherwise false is returned. - /// @see TryInitialize(uint, string, out int) - /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions, out int) - /// @see Shutdown() - public static bool TryInitialize(uint majorMinorVersion, out int hresult) - { - return TryInitialize(majorMinorVersion, null, out hresult); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// Failure returns false with the failure HRESULT in the hresult parameter. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `TryInitialize(majorMinorVersion, versionTag, new PackageVersion(), InitializeOptions.None, hresult)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @retval true if successful, otherwise false is returned. - /// @see TryInitialize(uint, out int) - /// @see TryInitialize(uint, string, PackageVersion, out int) - /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions, out int) - /// @see Shutdown() - public static bool TryInitialize(uint majorMinorVersion, string versionTag, out int hresult) - { - var minVersion = new PackageVersion(); - return TryInitialize(majorMinorVersion, versionTag, minVersion, out hresult); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// Failure returns false with the failure HRESULT in the hresult parameter. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// This is equivalent to `TryInitialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None, hresult)`. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @param minVersion the minimum version to use. - /// @param options optional behavior. - /// @param hresult the error code if an error occurred. - /// @retval true if successful, otherwise false is returned. - /// @see TryInitialize(uint, out int) - /// @see TryInitialize(uint, string, out int) - /// @see TryInitialize(uint, string, PackageVersion, out int) - /// @see Shutdown() - public static bool TryInitialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, out int hresult) - { - return TryInitialize(majorMinorVersion, versionTag, minVersion, InitializeOptions.None, out hresult); - } - - /// Initialize the calling process to use Windows App SDK's framework package. - /// Failure returns false with the failure HRESULT in the hresult parameter. - /// - /// Find a Windows App SDK framework package meeting the criteria and make it available - /// for use by the current process. If multiple packages meet the criteria the best - /// candidate is selected. - /// - /// @param majorMinorVersion major and minor version of Windows App SDK's framework package, encoded as `0xMMMMNNNN` where M=Major, N=Minor (e.g. 1.2 == 0x00010002). - /// @param versionTag version tag (if any), e.g. "preview1". - /// @param minVersion the minimum version to use. - /// @param options optional behavior. - /// @param hresult the error code if an error occurred. - /// @retval true if successful, otherwise false is returned. - /// @see TryInitialize(uint, out int) - /// @see TryInitialize(uint, string, out int) - /// @see TryInitialize(uint, string, PackageVersion, out int) - /// @see Shutdown() - public static bool TryInitialize(uint majorMinorVersion, string versionTag, PackageVersion minVersion, InitializeOptions options, out int hresult) - { - hresult = NativeMethods.MddBootstrapInitialize2(majorMinorVersion, versionTag, minVersion, options); - return hresult >= 0; - } + //TODO public static Microsoft.Windows.Foundation.Decimal operator +(this Microsoft.Windows.Foundation.Decimal left, Microsoft.Windows.Foundation.Decimal right) + //TODO { + //TODO return left.m_value.Add(right.m_value); + //TODO } - /// Undo the changes made by Initialize(). - /// - /// @warning Packages made available via `Initialize()` and - /// the Dynamic Dependencies API should not be used after this call. - /// @see Initialize(uint) - /// @see Initialize(uint, string) - /// @see Initialize(uint, string, PackageVersion) - /// @see Initialize(uint, string, PackageVersion, InitializeOptions options) - /// @see TryInitialize(uint, out int) - /// @see TryInitialize(uint, string, out int) - /// @see TryInitialize(uint, string, PackageVersion, out int) - /// @see TryInitialize(uint, string, PackageVersion, InitializeOptions options, out int) - public static void Shutdown() + public static Microsoft.Windows.Foundation.Decimal Add(this Microsoft.Windows.Foundation.Decimal left, System.Decimal right) { - NativeMethods.MddBootstrapShutdown(); + return left.Add(right); } } } diff --git a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj index 060ebb4be2..a0b5a2c924 100644 --- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj +++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj @@ -106,7 +106,7 @@ - + diff --git a/test/Decimal/DecimalCalcuator/CS/Program.cs b/test/Decimal/DecimalCalcuator/CS/Program.cs index 2685a69a22..7819fda240 100644 --- a/test/Decimal/DecimalCalcuator/CS/Program.cs +++ b/test/Decimal/DecimalCalcuator/CS/Program.cs @@ -12,10 +12,10 @@ public static void Main(string[] args) } string op = args[0]; - Decimal left = Decimal.Parse(args[1]); - Decimal right = (args.Length >= 3 ? Decimal.Parse(args[2]) : new Decimal(0)); + System.Decimal left = System.Decimal.Parse(args[1]); + System.Decimal right = (args.Length >= 3 ? System.Decimal.Parse(args[2]) : new System.Decimal(0)); string expected = (args.Length >= 4 ? args[3] : null); - Decimal result = new Decimal(0); + System.Decimal result = new System.Decimal(0); if (args.Length == 3) { // NOTE: Decimal unary operators not supported by C#: ! ~ @@ -60,7 +60,7 @@ public static void Main(string[] args) } if (expected != null) { - Decimal expectedValue = Decimal.Parse(expected); + System.Decimal expectedValue = System.Decimal.Parse(expected); Console.WriteLine($"==> {result} == {expectedValue} = {expectedValue == result}"); } } From 07c68d717fb85290b0b22ed11ef63432ebbf6a0c Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 00:50:12 -0700 Subject: [PATCH 16/25] Add scale, sign and max* properties. Fix tests. Add experimental spec. Add decimalcppwinrt.h with C++ enhancements beyond what C++/WinRT projection provides (e.g. operator==). --- WindowsAppRuntime.sln | 1 + dev/Decimal/Decimal.idl | 22 +- dev/Decimal/Decimal.vcxitems | 1 + dev/Decimal/M.W.F.Decimal.cpp | 54 +++-- dev/Decimal/M.W.F.Decimal.h | 38 +--- dev/Decimal/decimal.h | 48 +++- dev/Decimal/decimalcppwinrt.h | 114 ++++++++++ specs/decimal/decimal.md | 38 ++++ test/Decimal/CPP/DecimalTests.cpp | 268 ++++++++++++++--------- test/Decimal/WinRT/DecimalTest_WinRT.cpp | 95 +++++--- 10 files changed, 486 insertions(+), 193 deletions(-) create mode 100644 dev/Decimal/decimalcppwinrt.h create mode 100644 specs/decimal/decimal.md diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 5b99583a96..f9e02d090e 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -2764,6 +2764,7 @@ Global dev\ApplicationData\ApplicationData.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\BackgroundTask\BackgroundTaskBuilder\BackgroundTaskBuilder.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Common\Common.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 + dev\Decimal\Decimal.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\DynamicDependency\API\DynamicDependency.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\Licensing\Licensing.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 dev\PackageManager\API\PackageManager.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index cc91df7e01..92db9a41fe 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -87,6 +87,23 @@ namespace Microsoft.Windows.Foundation /// @return 0 if this and value are equal, <0 if this is less than value or >0 if this is greater than value. Int32 Compare(Decimal value); + /// Return the scaling factor of the value (the number of decimal digits). + /// @return the scaling factor, ranging from 0 to max_scale(). + UInt32 Scale { get; }; + + /// Return the sign of the value. + /// @return 0 if this os zero, <0 if this is less than zero or >0 if this is greater than zero. + Int32 Sign { get; }; + + /// Return the maximum scaling factor + static UInt32 MaxScale{ get; }; + + /// Return the maximum value (79,228,162,514,264,337,593,543,950,335). + static Decimal MaxValue{ get; }; + + /// Return the minimum value (-79,228,162,514,264,337,593,543,950,335). + static Decimal MinValue{ get; }; + /// Return a decimal whose value is (-this). Decimal Negate(); @@ -104,22 +121,17 @@ namespace Microsoft.Windows.Foundation /// Returns a Decimal whose value is (this + value). Decimal Add(Decimal value); - Decimal AddAssign(Decimal value); /// Returns a Decimal whose value is (this - value). Decimal Sub(Decimal value); //TODO Rename to Subtract() ? - Decimal SubAssign(Decimal value); //TODO Rename to SubtractAssign() ? /// Returns a Decimal whose value is (this * value). Decimal Mul(Decimal value); //TODO Rename to Multiply() ? - Decimal MulAssign(Decimal value); //TODO Rename to MultiplyAssign() ? /// Returns a Decimal whose value is (this / value). Decimal Div(Decimal value); //TODO Rename to Divide() ? - Decimal DivAssign(Decimal value); //TODO Rename to DivideAssign() ? /// Returns a Decimal whose value is (this % value). Decimal Mod(Decimal value); //TODO Rename to Modulo() or Remainder() ? - Decimal ModAssign(Decimal value); //TODO Rename to ModuloAssign() or RemainderAssign() ? } } diff --git a/dev/Decimal/Decimal.vcxitems b/dev/Decimal/Decimal.vcxitems index 19d36c5aca..54e8d4ec1f 100644 --- a/dev/Decimal/Decimal.vcxitems +++ b/dev/Decimal/Decimal.vcxitems @@ -26,6 +26,7 @@ + diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index 36801a82d6..6041e76b5a 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -82,6 +82,20 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { return winrt::make(to_decimal(value)); } + uint32_t Decimal::MaxScale() + { + return ::Microsoft::Windows::Foundation::decimal::max_scale(); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::MaxValue() + { + const auto value{ ::Microsoft::Windows::Foundation::decimal::max_value() }; + return winrt::make(value); + } + winrt::Microsoft::Windows::Foundation::Decimal Decimal::MinValue() + { + const auto value{ ::Microsoft::Windows::Foundation::decimal::min_value() }; + return winrt::make(value); + } void Decimal::SetFromBoolean(bool value) { m_decimal = value; @@ -226,16 +240,23 @@ namespace winrt::Microsoft::Windows::Foundation::implementation } winrt::Microsoft::Windows::Foundation::DecimalValue Decimal::ToDecimalValue() { - const auto& decimal{ m_decimal.to_decimal() }; - return *reinterpret_cast(&decimal); + return to_DecimalValue(m_decimal); } int32_t Decimal::Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value) { - return m_decimal.compare(to_DECIMAL(value.ToDecimalValue())); + return m_decimal.compare(to_DECIMAL(value)); } bool Decimal::Equals(winrt::Microsoft::Windows::Foundation::Decimal const& value) { - return m_decimal == to_DECIMAL(value.ToDecimalValue()); + return m_decimal == to_DECIMAL(value); + } + uint32_t Decimal::Scale() + { + return m_decimal.scale(); + } + int32_t Decimal::Sign() + { + return m_decimal.sign(); } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Negate() { @@ -261,47 +282,22 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { return winrt::make(m_decimal + to_decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::AddAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - m_decimal += to_decimal(value); - return *this; - } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal - to_decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::SubAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - m_decimal -= to_decimal(value); - return *this; - } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal * to_decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::MulAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - m_decimal *= to_decimal(value); - return *this; - } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Div(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal / to_decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::DivAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - m_decimal /= to_decimal(value); - return *this; - } winrt::Microsoft::Windows::Foundation::Decimal Decimal::Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value) { return winrt::make(m_decimal % to_decimal(value)); } - winrt::Microsoft::Windows::Foundation::Decimal Decimal::ModAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - m_decimal %= to_decimal(value); - return *this; - } hstring Decimal::ToString() { return m_decimal.to_hstring(); diff --git a/dev/Decimal/M.W.F.Decimal.h b/dev/Decimal/M.W.F.Decimal.h index 05a4462600..61b047095c 100644 --- a/dev/Decimal/M.W.F.Decimal.h +++ b/dev/Decimal/M.W.F.Decimal.h @@ -6,29 +6,10 @@ #include "Microsoft.Windows.Foundation.Decimal.g.h" #include +#include namespace winrt::Microsoft::Windows::Foundation::implementation { - inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) - { - return *reinterpret_cast(&value); - } - - inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) - { - return ::Microsoft::Windows::Foundation::decimal{ to_DECIMAL(value) }; - } - - inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::Decimal const& value) - { - return to_decimal(value.ToDecimalValue()); - } - - inline winrt::Microsoft::Windows::Foundation::DecimalValue to_DecimalValue(::Microsoft::Windows::Foundation::decimal const& value) - { - return *reinterpret_cast(&value.to_decimal()); - } - struct Decimal : DecimalT { Decimal() = default; @@ -43,6 +24,11 @@ namespace winrt::Microsoft::Windows::Foundation::implementation { } + Decimal(DECIMAL const& value) : + m_decimal(value) + { + } + static winrt::Microsoft::Windows::Foundation::Decimal CreateFromBoolean(bool value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromInt16(int16_t value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromInt32(int32_t value); @@ -61,6 +47,9 @@ namespace winrt::Microsoft::Windows::Foundation::implementation static winrt::Microsoft::Windows::Foundation::Decimal Create(winrt::Windows::Foundation::IInspectable const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimal(winrt::Microsoft::Windows::Foundation::Decimal const& value); static winrt::Microsoft::Windows::Foundation::Decimal CreateFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value); + static uint32_t MaxScale(); + static winrt::Microsoft::Windows::Foundation::Decimal MaxValue(); + static winrt::Microsoft::Windows::Foundation::Decimal MinValue(); void SetFromBoolean(bool value); void SetFromInt16(int16_t value); void SetFromInt32(int32_t value); @@ -98,23 +87,18 @@ namespace winrt::Microsoft::Windows::Foundation::implementation winrt::Microsoft::Windows::Foundation::DecimalValue ToDecimalValue(); bool Equals(winrt::Microsoft::Windows::Foundation::Decimal const& value); int32_t Compare(winrt::Microsoft::Windows::Foundation::Decimal const& value); + uint32_t Scale(); + int32_t Sign(); winrt::Microsoft::Windows::Foundation::Decimal Negate(); winrt::Microsoft::Windows::Foundation::Decimal Abs(); winrt::Microsoft::Windows::Foundation::Decimal Fix(); winrt::Microsoft::Windows::Foundation::Decimal Integer(); winrt::Microsoft::Windows::Foundation::Decimal Round(int32_t decimalPlaces); winrt::Microsoft::Windows::Foundation::Decimal Add(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal AddAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Sub(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal SubAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Mul(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal MulAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Div(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal DivAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); winrt::Microsoft::Windows::Foundation::Decimal Mod(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal ModAssign(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal ModVariant(winrt::Microsoft::Windows::Foundation::Decimal const& value); - winrt::Microsoft::Windows::Foundation::Decimal ModTruncated(winrt::Microsoft::Windows::Foundation::Decimal const& value); hstring ToString(); private: diff --git a/dev/Decimal/decimal.h b/dev/Decimal/decimal.h index ee2bef95fd..2d1557ca1c 100644 --- a/dev/Decimal/decimal.h +++ b/dev/Decimal/decimal.h @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. -#pragma once +#ifndef DECIMAL_H +#define DECIMAL_H #include @@ -66,7 +67,7 @@ class decimal value.m_decimal = DECIMAL{}; } - decimal(const DECIMAL& value) : + constexpr decimal(const DECIMAL& value) : m_decimal(value) { } @@ -321,7 +322,7 @@ class decimal bool to_bool() const { // Treat values != 0 as true - return (m_decimal.Lo64 != 0) | (m_decimal.Hi32 != 0); + return (m_decimal.Lo64 != 0) || (m_decimal.Hi32 != 0); } char to_char() const @@ -502,6 +503,45 @@ class decimal return ::compare(m_decimal, value); } + /// Return the scaling factor of the value (the number of decimal digits). + /// @return the scaling factor, ranging from 0 to max_scale(). + std::uint32_t scale() const + { + return m_decimal.scale; + } + + /// Return the sign of the value. + /// @return 0 if this os zero, <0 if this is less than zero or >0 if this is greater than zero. + std::int32_t sign() const + { + return ((m_decimal.Lo64 == 0) && (m_decimal.Hi32 == 0)) ? 0 : (m_decimal.sign != 0 ? -1 : 1); + } + + /// Return the maximum scaling factor + static constexpr std::uint32_t max_scale() + { + return 28; + } + + /// Return the maximum value (79,228,162,514,264,337,593,543,950,335). + static constexpr decimal max_value() + { + DECIMAL value{}; + value.Lo64 = 0xFFFFFFFFFFFFFFFFllu; + value.Hi32 = 0xFFFFFFFFu; + return decimal{ value }; + } + + /// Return the minimum value (-79,228,162,514,264,337,593,543,950,335). + static constexpr decimal min_value() + { + DECIMAL value{}; + value.Lo64 = 0xFFFFFFFFFFFFFFFFllu; + value.Hi32 = 0xFFFFFFFFu; + value.sign = DECIMAL_NEG; + return decimal{ value }; + } + decimal operator+() const { return *this; @@ -659,3 +699,5 @@ class decimal DECIMAL m_decimal{}; }; } + +#endif // DECIMAL_H diff --git a/dev/Decimal/decimalcppwinrt.h b/dev/Decimal/decimalcppwinrt.h new file mode 100644 index 0000000000..5ca4760a26 --- /dev/null +++ b/dev/Decimal/decimalcppwinrt.h @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include + +#if defined(WINRT_Microsoft_Windows_Foundation_H) && !defined(__WINDOWSAPPSDK_WIMRT_M_W_F_DECIMAL_) +#define __WINDOWSAPPSDK_WIMRT_M_W_F_DECIMAL_ + +//---------------------------------------------------------------------- +// WinRT Decimal operators + +inline bool operator==( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) == 0; +} + +inline bool operator!=( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) != 0; +} + +inline bool operator<( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) < 0; +} + +inline bool operator<=( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) <= 0; +} + +inline bool operator>( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) > 0; +} + +inline bool operator>=( + winrt::Microsoft::Windows::Foundation::Decimal const& left, + winrt::Microsoft::Windows::Foundation::Decimal const& right) +{ + return left.Compare(right) >= 0; +} + +//---------------------------------------------------------------------- +// Conversion functions + +namespace winrt::Microsoft::Windows::Foundation +{ +/// Return value as DECIMAL. +inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) +{ + return *reinterpret_cast(&value); +} + +/// Return value as DECIMAL. +inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::Decimal const& value) +{ + return to_DECIMAL(value.ToDecimalValue()); +} + +/// Return value as a WinRT DecimalValue structure. +inline winrt::Microsoft::Windows::Foundation::DecimalValue to_DecimalValue(DECIMAL const& value) +{ + return *reinterpret_cast(&value); +} + +/// Return value as a WinRT Decimal object. +inline winrt::Microsoft::Windows::Foundation::Decimal to_Decimal(DECIMAL const& value) +{ + return winrt::Microsoft::Windows::Foundation::Decimal::CreateFromDecimalValue(to_DecimalValue(value)); +} + +#if defined(DECIMAL_H) && !defined(__WINDOWSAPPSDK_DECIMAL_) +#define __WINDOWSAPPSDK_DECIMAL_ + +/// Return value as a WinRT DecimalValue structure. +inline winrt::Microsoft::Windows::Foundation::DecimalValue to_DecimalValue(::Microsoft::Windows::Foundation::decimal const& value) +{ + return to_DecimalValue(value.to_decimal()); +} + +/// Return value as a WinRT decimal object. +inline winrt::Microsoft::Windows::Foundation::Decimal to_Decimal(::Microsoft::Windows::Foundation::decimal const& value) +{ + return to_Decimal(value.to_decimal()); +} + +/// Return value as a C++ decimal object. +inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::Decimal const& value) +{ + return ::Microsoft::Windows::Foundation::decimal{ to_DECIMAL(value) }; +} + +/// Return value as a C++ decimal object. +inline ::Microsoft::Windows::Foundation::decimal to_decimal(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) +{ + return ::Microsoft::Windows::Foundation::decimal{ to_DECIMAL(value) }; +} + +#endif // defined(DECIMAL_H) && !defined(__WINDOWSAPPSDK_DECIMAL_) + +} + +#endif // defined(WINRT_Microsoft_Windows_Foundation_H) && !defined(__WINDOWSAPPSDK_WIMRT_M_W_F_DECIMAL_) diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md new file mode 100644 index 0000000000..cf224681ec --- /dev/null +++ b/specs/decimal/decimal.md @@ -0,0 +1,38 @@ +# 1. Decimal + +This feature provides a WinRT decimal data type comparable to .NET's [System.Decimal](https://learn.microsoft.com/dotnet/api/system.decimal). + +# 2. TODO + +THIS FEATURE IS CURRENTLY EXPERIMENTAL. + +Potential future changes + +1. C++ class + 1. Add floor() - round towards +infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.floor + 2. Add ceil() - round towards -infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.ceiling + 1. Rename integer() to ceil() ? + 3. Add round towards zero + 4. decimal zero{}; decimal neg{ -zero }; neg.sign() < 0 because DECIMAL.sign = 0x80. Treat -0 the same as +0 (prevent -0 from being set?) +2. winrt::Microsoft::Windows::Foundation::Decimal + 1. Rename ToDecimal() -- Copy(value) or Clone(value) + 2. Rename Sub() to Subtract() + 3. Rename Mul() to Multiply() + 4. Rename Div() to Divide() + 5. Rename Mod() to Modulo() or Remainder() +3. decimalcppwinrt.h + 1. Add operator+ + 2. Add operator- + 3. Add operator++ + 4. Add operator-- + 5. Add operator + - * / % + 6. Add operator += -= *= /= %= + 7. Add ctor(type) where type = bool / [u]int8/16/32/64 / float / double ? + 8. Add operator=(type) where type = bool / [u]int8/16/32/64 / float / double ? +4. Microsoft.Windows.Foundation.Projection + 1. Delete WDecimal.cs + 2. Add WinRT<->C# conversion functions + 1. System.Decimal ToSystemDecimal(Microsoft.Windows.Foundation.Decimal from) + 1. System.Decimal ToSystemDecimal(Microsoft.Windows.Foundation.DecimalValue from) + 1. Microsoft.Windows.Foundation.Decimal ToDecimal(System.Decimal from) + 1. Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(System.Decimal from) diff --git a/test/Decimal/CPP/DecimalTests.cpp b/test/Decimal/CPP/DecimalTests.cpp index d9136b2777..942d5d8e27 100644 --- a/test/Decimal/CPP/DecimalTests.cpp +++ b/test/Decimal/CPP/DecimalTests.cpp @@ -102,7 +102,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_decimal) { const Microsoft::Windows::Foundation::decimal data{ -1234567890 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_decimal() }; VERIFY_ARE_EQUAL(data, to); @@ -115,7 +115,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_bool) { const bool data{ true }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_bool() }; VERIFY_ARE_EQUAL(data, to); @@ -128,7 +128,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_char) { const char data{ -123 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_char() }; VERIFY_ARE_EQUAL(data, to); @@ -141,7 +141,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_int16) { const std::int16_t data{ -32109}; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_int16() }; VERIFY_ARE_EQUAL(data, to); @@ -154,7 +154,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_int32) { const std::int32_t data{ -1234567890 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_int32() }; VERIFY_ARE_EQUAL(data, to); @@ -167,7 +167,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_int64) { const std::int64_t data{ -1234567890123456789 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_int64() }; VERIFY_ARE_EQUAL(data, to); @@ -180,7 +180,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_uint8) { const std::uint8_t data{ 123 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_uint8() }; VERIFY_ARE_EQUAL(data, to); @@ -193,7 +193,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_uint16) { const std::uint16_t data{ 32109 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_uint16() }; VERIFY_ARE_EQUAL(data, to); @@ -206,7 +206,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_uint32) { const std::uint32_t data{ 1234567890 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_uint32() }; VERIFY_ARE_EQUAL(data, to); @@ -219,7 +219,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_uint64) { const std::uint64_t data{ 0xFEDCBA0987654321 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_uint64() }; VERIFY_ARE_EQUAL(data, to); @@ -232,7 +232,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_float) { const float data{ -1.25 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_float() }; VERIFY_ARE_EQUAL(data, to); @@ -245,7 +245,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_double) { const double data{ -1.25 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_double() }; VERIFY_ARE_EQUAL(data, to); @@ -258,7 +258,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_long) { const long data{ -1234567890 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_long() }; VERIFY_ARE_EQUAL(data, to); @@ -271,7 +271,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_ulong) { const unsigned long data{ 1234567890 }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_ulong() }; VERIFY_ARE_EQUAL(data, to); @@ -284,7 +284,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_pcwstr) { PCWSTR data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_string() }; VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str())); @@ -297,7 +297,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_pcwstr_lcid) { PCWSTR data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); + const Microsoft::Windows::Foundation::decimal object(data, GetSystemDefaultLCID()); const auto to{ object.to_string(GetSystemDefaultLCID()) }; VERIFY_ARE_EQUAL(0, wcscmp(data, to.c_str())); @@ -310,7 +310,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_string) { const std::wstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_string() }; VERIFY_ARE_EQUAL(data, to); @@ -323,7 +323,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_string_lcid_system_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); const auto to{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; VERIFY_ARE_EQUAL(data, to); @@ -336,7 +336,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_string_lcid_user_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); const auto to{ object.to_hstring(LOCALE_USER_DEFAULT) }; VERIFY_ARE_EQUAL(data, to); @@ -349,7 +349,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_string_lcid_thread) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); + const Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); const auto to{ object.to_hstring(GetThreadLocale()) }; VERIFY_ARE_EQUAL(data, to); @@ -362,7 +362,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_string_lcid_invariant) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); const auto to{ object.to_hstring(LOCALE_INVARIANT) }; VERIFY_ARE_EQUAL(data, to); @@ -376,7 +376,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_hstring) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data); + const Microsoft::Windows::Foundation::decimal object(data); const auto to{ object.to_hstring() }; VERIFY_ARE_EQUAL(data, to); @@ -391,7 +391,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_hstring_lcid_system_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_SYSTEM_DEFAULT); const auto to{ object.to_hstring(LOCALE_SYSTEM_DEFAULT) }; VERIFY_ARE_EQUAL(data, to); @@ -406,7 +406,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_hstring_lcid_user_default) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_USER_DEFAULT); const auto to{ object.to_hstring(LOCALE_USER_DEFAULT) }; VERIFY_ARE_EQUAL(data, to); @@ -421,7 +421,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_hstring_lcid_thread) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); + const Microsoft::Windows::Foundation::decimal object(data, GetThreadLocale()); const auto to{ object.to_hstring(GetThreadLocale()) }; VERIFY_ARE_EQUAL(data, to); @@ -436,7 +436,7 @@ namespace Test::Decimal::Tests TEST_METHOD(ctor_to_assign_hstring_lcid_invariant) { const winrt::hstring data{ L"-12.345" }; - Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); + const Microsoft::Windows::Foundation::decimal object(data, LOCALE_INVARIANT); const auto to{ object.to_hstring(LOCALE_INVARIANT) }; VERIFY_ARE_EQUAL(data, to); @@ -449,8 +449,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_bool) { - Microsoft::Windows::Foundation::decimal decimal_false(false); - Microsoft::Windows::Foundation::decimal decimal_true(true); + const Microsoft::Windows::Foundation::decimal decimal_false(false); + const Microsoft::Windows::Foundation::decimal decimal_true(true); VERIFY_ARE_EQUAL(0, decimal_false.compare(decimal_false)); VERIFY_ARE_EQUAL(0, decimal_true.compare(decimal_true)); VERIFY_ARE_EQUAL(-1, decimal_false.compare(decimal_true)); @@ -466,8 +466,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_char) { - Microsoft::Windows::Foundation::decimal left(static_cast(-123)); - Microsoft::Windows::Foundation::decimal right(static_cast(123)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-123)); + const Microsoft::Windows::Foundation::decimal right(static_cast(123)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -504,8 +504,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_int16) { - Microsoft::Windows::Foundation::decimal left(static_cast(-32109)); - Microsoft::Windows::Foundation::decimal right(static_cast(32109)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-32109)); + const Microsoft::Windows::Foundation::decimal right(static_cast(32109)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -542,8 +542,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_int32) { - Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); - Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); + const Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -580,8 +580,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_int64) { - Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890123456789)); - Microsoft::Windows::Foundation::decimal right(static_cast(1234567890123456789)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890123456789)); + const Microsoft::Windows::Foundation::decimal right(static_cast(1234567890123456789)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -618,8 +618,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_uint8) { - Microsoft::Windows::Foundation::decimal left(static_cast(123)); - Microsoft::Windows::Foundation::decimal right(static_cast(234)); + const Microsoft::Windows::Foundation::decimal left(static_cast(123)); + const Microsoft::Windows::Foundation::decimal right(static_cast(234)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -656,8 +656,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_uint16) { - Microsoft::Windows::Foundation::decimal left(static_cast(32109)); - Microsoft::Windows::Foundation::decimal right(static_cast(65432)); + const Microsoft::Windows::Foundation::decimal left(static_cast(32109)); + const Microsoft::Windows::Foundation::decimal right(static_cast(65432)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -694,8 +694,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_uint32) { - Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); - Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); + const Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); + const Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -732,8 +732,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_uint64) { - Microsoft::Windows::Foundation::decimal left(static_cast(0x1234567890ABCDEF)); - Microsoft::Windows::Foundation::decimal right(static_cast(0xFEDCBA0987654321)); + const Microsoft::Windows::Foundation::decimal left(static_cast(0x1234567890ABCDEF)); + const Microsoft::Windows::Foundation::decimal right(static_cast(0xFEDCBA0987654321)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -770,8 +770,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_float) { - Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); - Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); + const Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -808,8 +808,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_double) { - Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); - Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-1.25)); + const Microsoft::Windows::Foundation::decimal right(static_cast(1.25)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -846,8 +846,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_long) { - Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); - Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); + const Microsoft::Windows::Foundation::decimal left(static_cast(-1234567890)); + const Microsoft::Windows::Foundation::decimal right(static_cast(1234567890)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -884,8 +884,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_ulong) { - Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); - Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); + const Microsoft::Windows::Foundation::decimal left(static_cast(1234567890)); + const Microsoft::Windows::Foundation::decimal right(static_cast(4019283756)); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -922,8 +922,8 @@ namespace Test::Decimal::Tests TEST_METHOD(compare_string) { - Microsoft::Windows::Foundation::decimal left(L"-12.345"); - Microsoft::Windows::Foundation::decimal right(L"12.345"); + const Microsoft::Windows::Foundation::decimal left(L"-12.345"); + const Microsoft::Windows::Foundation::decimal right(L"12.345"); VERIFY_ARE_EQUAL(0, left.compare(left)); VERIFY_ARE_EQUAL(0, right.compare(right)); VERIFY_ARE_EQUAL(-1, left.compare(right)); @@ -1005,9 +1005,9 @@ namespace Test::Decimal::Tests TEST_METHOD(operator_pos) { - Microsoft::Windows::Foundation::decimal zero(L"0"); - Microsoft::Windows::Foundation::decimal pos(L"12.345"); - Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + const Microsoft::Windows::Foundation::decimal zero(L"0"); + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); const auto zero_value{ +zero }; VERIFY_IS_TRUE(zero_value == zero); @@ -1031,11 +1031,71 @@ namespace Test::Decimal::Tests VERIFY_IS_TRUE(neg_value < pos); } + TEST_METHOD(scale) + { + const Microsoft::Windows::Foundation::decimal n_0{ L"79228162514264337593543950335" }; + VERIFY_ARE_EQUAL(0u, n_0.scale()); + + const Microsoft::Windows::Foundation::decimal n_1{ L"7922816251426433759354395033.5" }; + VERIFY_ARE_EQUAL(1u, n_1.scale()); + + const Microsoft::Windows::Foundation::decimal n_2{ L"792281625142643375935439503.35" }; + VERIFY_ARE_EQUAL(2u, n_2.scale()); + + const Microsoft::Windows::Foundation::decimal n_27{ L"79.228162514264337593543950335" }; + VERIFY_ARE_EQUAL(27u, n_27.scale()); + + const Microsoft::Windows::Foundation::decimal n_28{ L"7.9228162514264337593543950335" }; + VERIFY_ARE_EQUAL(28u, n_28.scale()); + + const Microsoft::Windows::Foundation::decimal neg_n_0{ L"-79228162514264337593543950335" }; + VERIFY_ARE_EQUAL(0u, neg_n_0.scale()); + + const Microsoft::Windows::Foundation::decimal neg_n_1{ L"-7922816251426433759354395033.5" }; + VERIFY_ARE_EQUAL(1u, neg_n_1.scale()); + + const Microsoft::Windows::Foundation::decimal neg_n_2{ L"-792281625142643375935439503.35" }; + VERIFY_ARE_EQUAL(2u, neg_n_2.scale()); + + const Microsoft::Windows::Foundation::decimal neg_n_27{ L"-79.228162514264337593543950335" }; + VERIFY_ARE_EQUAL(27u, neg_n_27.scale()); + + const Microsoft::Windows::Foundation::decimal neg_n_28{ L"-7.9228162514264337593543950335" }; + VERIFY_ARE_EQUAL(28u, neg_n_28.scale()); + } + + TEST_METHOD(sign) + { + const Microsoft::Windows::Foundation::decimal zero(L"0"); + VERIFY_ARE_EQUAL(0, zero.sign()); + + const Microsoft::Windows::Foundation::decimal neg_zero(L"-0"); + VERIFY_ARE_EQUAL(0, neg_zero.sign()); + VERIFY_ARE_EQUAL(zero, neg_zero); + + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + VERIFY_ARE_EQUAL(1, pos.sign()); + + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + VERIFY_ARE_EQUAL(-1, neg.sign()); + } + + TEST_METHOD(min_max) + { + VERIFY_ARE_EQUAL(28u, Microsoft::Windows::Foundation::decimal::max_scale()); + + const Microsoft::Windows::Foundation::decimal max_decimal(L"79228162514264337593543950335"); + VERIFY_ARE_EQUAL(max_decimal, Microsoft::Windows::Foundation::decimal::max_value()); + + const Microsoft::Windows::Foundation::decimal min_decimal(L"-79228162514264337593543950335"); + VERIFY_ARE_EQUAL(min_decimal, Microsoft::Windows::Foundation::decimal::min_value()); + } + TEST_METHOD(operator_neg) { - Microsoft::Windows::Foundation::decimal zero(L"0"); - Microsoft::Windows::Foundation::decimal pos(L"12.345"); - Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + const Microsoft::Windows::Foundation::decimal zero(L"0"); + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); const auto zero_value{ -zero }; VERIFY_IS_TRUE(zero_value == zero); @@ -1061,9 +1121,9 @@ namespace Test::Decimal::Tests TEST_METHOD(abs) { - Microsoft::Windows::Foundation::decimal zero(L"0"); - Microsoft::Windows::Foundation::decimal pos(L"12.345"); - Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + const Microsoft::Windows::Foundation::decimal zero(L"0"); + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); const auto zero_value{ zero.abs() }; VERIFY_IS_TRUE(zero_value == zero); @@ -1089,34 +1149,34 @@ namespace Test::Decimal::Tests TEST_METHOD(fix) { - Microsoft::Windows::Foundation::decimal zero(L"0"); + const Microsoft::Windows::Foundation::decimal zero(L"0"); const auto value{ zero.fix() }; VERIFY_IS_TRUE(value == zero); - Microsoft::Windows::Foundation::decimal pos(L"12.345"); - Microsoft::Windows::Foundation::decimal pos_fix(L"12"); + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + const Microsoft::Windows::Foundation::decimal pos_fix(L"12"); const auto pos_value{ pos.fix() }; VERIFY_IS_TRUE(pos_value == pos_fix); - Microsoft::Windows::Foundation::decimal neg(L"-12.345"); - Microsoft::Windows::Foundation::decimal neg_fix(L"-12"); + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + const Microsoft::Windows::Foundation::decimal neg_fix(L"-12"); const auto neg_value{ neg.fix() }; VERIFY_IS_TRUE(neg_value == neg_fix); } TEST_METHOD(integer) { - Microsoft::Windows::Foundation::decimal zero(L"0"); + const Microsoft::Windows::Foundation::decimal zero(L"0"); const auto value{ zero.integer() }; VERIFY_IS_TRUE(value == zero); - Microsoft::Windows::Foundation::decimal pos(L"12.345"); - Microsoft::Windows::Foundation::decimal pos_integer(L"12"); + const Microsoft::Windows::Foundation::decimal pos(L"12.345"); + const Microsoft::Windows::Foundation::decimal pos_integer(L"12"); const auto pos_value{ pos.integer() }; VERIFY_IS_TRUE(pos_value == pos_integer); - Microsoft::Windows::Foundation::decimal neg(L"-12.345"); - Microsoft::Windows::Foundation::decimal neg_integer(L"-13"); + const Microsoft::Windows::Foundation::decimal neg(L"-12.345"); + const Microsoft::Windows::Foundation::decimal neg_integer(L"-13"); const auto neg_value{ neg.integer() }; VERIFY_IS_TRUE(neg_value == neg_integer); } @@ -1250,9 +1310,9 @@ namespace Test::Decimal::Tests for (size_t index=0; index < ARRAYSIZE(values); ++index) { const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal left{ value.left }; + const Microsoft::Windows::Foundation::decimal right{ value.right }; + const Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left + right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s + %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); @@ -1293,9 +1353,9 @@ namespace Test::Decimal::Tests for (size_t index=0; index < ARRAYSIZE(values); ++index) { const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal left{ value.left }; + const Microsoft::Windows::Foundation::decimal right{ value.right }; + const Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left - right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s - %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); @@ -1336,9 +1396,9 @@ namespace Test::Decimal::Tests for (size_t index=0; index < ARRAYSIZE(values); ++index) { const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal left{ value.left }; + const Microsoft::Windows::Foundation::decimal right{ value.right }; + const Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left * right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s * %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); @@ -1387,9 +1447,9 @@ namespace Test::Decimal::Tests for (size_t index=0; index < ARRAYSIZE(values); ++index) { const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal left{ value.left }; + const Microsoft::Windows::Foundation::decimal right{ value.right }; + const Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left / right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s / %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); @@ -1405,8 +1465,8 @@ namespace Test::Decimal::Tests { try { - Microsoft::Windows::Foundation::decimal data{ 123 }; - Microsoft::Windows::Foundation::decimal zero{}; + const Microsoft::Windows::Foundation::decimal data{ 123 }; + const Microsoft::Windows::Foundation::decimal zero{}; const auto result{ data % zero }; VERIFY_FAIL(L"Success is not expected"); } @@ -1452,9 +1512,9 @@ namespace Test::Decimal::Tests for (size_t index=0; index < ARRAYSIZE(values); ++index) { const auto& value{ values[index] }; - Microsoft::Windows::Foundation::decimal left{ value.left }; - Microsoft::Windows::Foundation::decimal right{ value.right }; - Microsoft::Windows::Foundation::decimal expected{ value.result }; + const Microsoft::Windows::Foundation::decimal left{ value.left }; + const Microsoft::Windows::Foundation::decimal right{ value.right }; + const Microsoft::Windows::Foundation::decimal expected{ value.result }; const Microsoft::Windows::Foundation::decimal result{ left % right }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s %% %s = %s vs %s", left.to_string().c_str(), right.to_string().c_str(), result.to_string().c_str(), expected.to_string().c_str())); @@ -1468,34 +1528,34 @@ namespace Test::Decimal::Tests TEST_METHOD(operator_round) { - Microsoft::Windows::Foundation::decimal n_1_888{ L"1.888" }; - Microsoft::Windows::Foundation::decimal n_neg1_888{ L"-1.888" }; - Microsoft::Windows::Foundation::decimal n_1_25{ L"1.25" }; - Microsoft::Windows::Foundation::decimal n_neg1_25{ L"-1.25" }; + const Microsoft::Windows::Foundation::decimal n_1_888{ L"1.888" }; + const Microsoft::Windows::Foundation::decimal n_neg1_888{ L"-1.888" }; + const Microsoft::Windows::Foundation::decimal n_1_25{ L"1.25" }; + const Microsoft::Windows::Foundation::decimal n_neg1_25{ L"-1.25" }; - Microsoft::Windows::Foundation::decimal n_2{ L"2" }; - Microsoft::Windows::Foundation::decimal n_1_9{ L"1.9" }; - Microsoft::Windows::Foundation::decimal n_1_89{ L"1.89" }; - Microsoft::Windows::Foundation::decimal n_neg1_9{ L"1.9" }; - Microsoft::Windows::Foundation::decimal n_neg1_89{ L"1.89" }; + const Microsoft::Windows::Foundation::decimal n_2{ L"2" }; + const Microsoft::Windows::Foundation::decimal n_1_9{ L"1.9" }; + const Microsoft::Windows::Foundation::decimal n_1_89{ L"1.89" }; + const Microsoft::Windows::Foundation::decimal n_neg1_9{ L"1.9" }; + const Microsoft::Windows::Foundation::decimal n_neg1_89{ L"1.89" }; - Microsoft::Windows::Foundation::decimal n_1_888_round_0{ n_1_888.round(0) }; + const Microsoft::Windows::Foundation::decimal n_1_888_round_0{ n_1_888.round(0) }; VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", n_1_888.to_string().c_str(), n_1_888_round_0.to_string().c_str(), n_2.to_string().c_str())); - Microsoft::Windows::Foundation::decimal n_1_888_round_1{ n_1_888.round(1) }; + const Microsoft::Windows::Foundation::decimal n_1_888_round_1{ n_1_888.round(1) }; VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", n_1_888.to_string().c_str(), n_1_888_round_1.to_string().c_str(), n_1_9.to_string().c_str())); - Microsoft::Windows::Foundation::decimal n_1_888_round_2{ n_1_888.round(2) }; + const Microsoft::Windows::Foundation::decimal n_1_888_round_2{ n_1_888.round(2) }; VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", n_1_888.to_string().c_str(), n_1_888_round_2.to_string().c_str(), n_1_89.to_string().c_str())); - Microsoft::Windows::Foundation::decimal n_1_888_round_3{ n_1_888.round(3) }; + const Microsoft::Windows::Foundation::decimal n_1_888_round_3{ n_1_888.round(3) }; VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", n_1_888.to_string().c_str(), n_1_888_round_3.to_string().c_str(), n_1_888.to_string().c_str())); - Microsoft::Windows::Foundation::decimal n_1_888_round_4{ n_1_888.round(4) }; + const Microsoft::Windows::Foundation::decimal n_1_888_round_4{ n_1_888.round(4) }; VERIFY_ARE_EQUAL(n_2, n_1_888_round_0, WEX::Common::String().Format(L"%s.round(0) = %s vs %s", n_1_888.to_string().c_str(), n_1_888_round_4.to_string().c_str(), n_1_888.to_string().c_str())); } diff --git a/test/Decimal/WinRT/DecimalTest_WinRT.cpp b/test/Decimal/WinRT/DecimalTest_WinRT.cpp index b0617b6eef..7fe0057bbc 100644 --- a/test/Decimal/WinRT/DecimalTest_WinRT.cpp +++ b/test/Decimal/WinRT/DecimalTest_WinRT.cpp @@ -5,6 +5,8 @@ #include +#include + namespace TD = ::Test::Diagnostics; namespace TB = ::Test::Bootstrap; namespace TP = ::Test::Packages; @@ -731,6 +733,66 @@ namespace Test::Decimal::Tests VERIFY_IS_TRUE(right >= left); } + TEST_METHOD(scale) + { + const auto n_0{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"79228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(0u, n_0.Scale()); + + const auto n_1{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"7922816251426433759354395033.5" }) }; + VERIFY_ARE_EQUAL(1u, n_1.Scale()); + + const auto n_2{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"792281625142643375935439503.35" }) }; + VERIFY_ARE_EQUAL(2u, n_2.Scale()); + + const auto n_27{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"79.228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(27u, n_27.Scale()); + + const auto n_28{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"7.9228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(28u, n_28.Scale()); + + const auto neg_n_0{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-79228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(0u, neg_n_0.Scale()); + + const auto neg_n_1{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-7922816251426433759354395033.5" }) }; + VERIFY_ARE_EQUAL(1u, neg_n_1.Scale()); + + const auto neg_n_2{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-792281625142643375935439503.35" }) }; + VERIFY_ARE_EQUAL(2u, neg_n_2.Scale()); + + const auto neg_n_27{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-79.228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(27u, neg_n_27.Scale()); + + const auto neg_n_28{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-7.9228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(28u, neg_n_28.Scale()); + } + + TEST_METHOD(sign) + { + const winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; + VERIFY_ARE_EQUAL(0, zero.Sign()); + + const winrt::Microsoft::Windows::Foundation::Decimal neg_zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-0" }) }; + VERIFY_ARE_EQUAL(0, neg_zero.Sign()); + VERIFY_ARE_EQUAL(zero, neg_zero); + + const winrt::Microsoft::Windows::Foundation::Decimal pos{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"12.345" }) }; + VERIFY_ARE_EQUAL(1, pos.Sign()); + + const winrt::Microsoft::Windows::Foundation::Decimal neg{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-12.345" }) }; + VERIFY_ARE_EQUAL(-1, neg.Sign()); + } + + TEST_METHOD(min_max) + { + VERIFY_ARE_EQUAL(28u, winrt::Microsoft::Windows::Foundation::Decimal::MaxScale()); + + const winrt::Microsoft::Windows::Foundation::Decimal max_decimal{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"79228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(max_decimal, winrt::Microsoft::Windows::Foundation::Decimal::MaxValue()); + + const winrt::Microsoft::Windows::Foundation::Decimal min_decimal{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"-79228162514264337593543950335" }) }; + VERIFY_ARE_EQUAL(min_decimal, winrt::Microsoft::Windows::Foundation::Decimal::MinValue()); + } + TEST_METHOD(negate) { winrt::Microsoft::Windows::Foundation::Decimal zero{ winrt::Microsoft::Windows::Foundation::Decimal::CreateFromString(winrt::hstring{ L"0" }) }; @@ -859,11 +921,6 @@ namespace Test::Decimal::Tests const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Add(right) }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Add %s = %s vs %s", left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); - - winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; - result2.AddAssign(right); - VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s AddAssign %s = %s vs %s", - left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); } } @@ -905,11 +962,6 @@ namespace Test::Decimal::Tests const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Sub(right) }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Sub %s = %s vs %s", left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); - - winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; - result2.SubAssign(right); - VERIFY_ARE_EQUAL(expected, result2, WEX::Common::String().Format(L"%s SubAssign %s = %s vs %s", - left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); } } @@ -951,11 +1003,6 @@ namespace Test::Decimal::Tests const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Mul(right) }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Mul %s = %s vs %s", left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); - - winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; - result2.MulAssign(right); - VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s MulAssign %s = %s vs %s", - left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); } } @@ -972,6 +1019,10 @@ namespace Test::Decimal::Tests { VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); } + catch (winrt::hresult_error& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.code(), WEX::Common::String().Format(L"0x%X %hs", e.code(), e.message().c_str())); + } struct values { @@ -1005,11 +1056,6 @@ namespace Test::Decimal::Tests const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Div(right) }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Div %s = %s vs %s", left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); - - winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; - result2.DivAssign(right); - VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s DivAssign %s = %s vs %s", - left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); } } @@ -1026,6 +1072,10 @@ namespace Test::Decimal::Tests { VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.GetErrorCode(), WEX::Common::String().Format(L"0x%X %hs", e.GetErrorCode(), e.what())); } + catch (winrt::hresult_error& e) + { + VERIFY_ARE_EQUAL(DISP_E_DIVBYZERO, e.code(), WEX::Common::String().Format(L"0x%X %hs", e.code(), e.message().c_str())); + } struct values { @@ -1073,11 +1123,6 @@ namespace Test::Decimal::Tests const winrt::Microsoft::Windows::Foundation::Decimal result{ left.Mod(right) }; VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s Mod %s = %s vs %s", left.ToString().c_str(), right.ToString().c_str(), result.ToString().c_str(), expected.ToString().c_str())); - - winrt::Microsoft::Windows::Foundation::Decimal result2{ left }; - result2.ModAssign(right); - VERIFY_ARE_EQUAL(expected, result, WEX::Common::String().Format(L"%s ModAssign %s = %s vs %s", - left.ToString().c_str(), right.ToString().c_str(), result2.ToString().c_str(), expected.ToString().c_str())); } } From ec71c88c5fcd309e42a7ea2f1c41a50f8a6f0573 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 00:54:09 -0700 Subject: [PATCH 17/25] Updated spec --- specs/decimal/decimal.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md index cf224681ec..d95459cf20 100644 --- a/specs/decimal/decimal.md +++ b/specs/decimal/decimal.md @@ -20,6 +20,7 @@ Potential future changes 3. Rename Mul() to Multiply() 4. Rename Div() to Divide() 5. Rename Mod() to Modulo() or Remainder() + 6. Implement IInspectable methods -- Create(IInspectable), Set(IInspectable), ToObject() 3. decimalcppwinrt.h 1. Add operator+ 2. Add operator- From 9c07098ef52a4656e5fb5eb5ebb28a7474864612 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 00:56:03 -0700 Subject: [PATCH 18/25] Add [Feature_Decimal] --- dev/Decimal/Decimal.idl | 2 ++ specs/decimal/decimal.md | 1 + 2 files changed, 3 insertions(+) diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index 92db9a41fe..8e81cada61 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -8,6 +8,7 @@ namespace Microsoft.Windows.Foundation [contractversion(2)] apicontract DecimalContract{}; + [feature(Feature_Decimal)] [contract(DecimalContract, 1)] struct DecimalValue { @@ -18,6 +19,7 @@ namespace Microsoft.Windows.Foundation UInt64 Lo64; }; + [feature(Feature_Decimal)] [contract(DecimalContract, 1)] runtimeclass Decimal : Windows.Foundation.IStringable { diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md index d95459cf20..bd69cbc941 100644 --- a/specs/decimal/decimal.md +++ b/specs/decimal/decimal.md @@ -21,6 +21,7 @@ Potential future changes 4. Rename Div() to Divide() 5. Rename Mod() to Modulo() or Remainder() 6. Implement IInspectable methods -- Create(IInspectable), Set(IInspectable), ToObject() + 7. Add experimental checks in ctor + static methods 3. decimalcppwinrt.h 1. Add operator+ 2. Add operator- From 6380ba3458d6f1237c2476ca3115047abab3e325 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 10:27:59 -0700 Subject: [PATCH 19/25] Cleanup C# support --- WindowsAppRuntime.sln | 2 + .../Microsoft.Windows.Foundation/WDecimal.cs | 44 ------------------- specs/decimal/decimal.md | 17 ++++--- test/Decimal/CS/DotNetTests.cs | 20 +++++++++ 4 files changed, 32 insertions(+), 51 deletions(-) delete mode 100644 dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index f9e02d090e..42b614bbc4 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -722,8 +722,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WinRT", "WinRT", "{022E355A EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecimalTest_WinRT", "test\Decimal\WinRT\DecimalTest_WinRT.vcxproj", "{E9C055BB-6AE4-497A-A354-D07841E68976}" ProjectSection(ProjectDependencies) = postProject + {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} = {8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA} {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} = {9C1A6C58-52D6-4514-9120-5C339C5DF4BE} {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} + {D6574FD6-8D13-4412-9FCB-308D44063CDA} = {D6574FD6-8D13-4412-9FCB-308D44063CDA} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Decimal", "dev\Decimal\Decimal.vcxitems", "{DC453DE3-18FD-43E7-8103-20763C8B97C8}" diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs b/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs deleted file mode 100644 index 99fccf8c64..0000000000 --- a/dev/Projections/CS/Microsoft.Windows.Foundation/WDecimal.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation and Contributors. -// Licensed under the MIT License. - -using Microsoft.Windows.Foundation; - -namespace Microsoft.Windows.Foundation -{ - public class WDecimal - { - public WDecimal() - { - } - - public WDecimal(WDecimal value) - { - m_value = value.m_value.ToDecimal(); - } - - public WDecimal(Microsoft.Windows.Foundation.Decimal value) - { - m_value = value; - } - - public static WDecimal operator +(WDecimal left, WDecimal right) - { - return new WDecimal(left.m_value.Add(right.m_value)); - } - - private Microsoft.Windows.Foundation.Decimal m_value = new Microsoft.Windows.Foundation.Decimal(); - } - - public static class DecimalExtensions - { - //TODO public static Microsoft.Windows.Foundation.Decimal operator +(this Microsoft.Windows.Foundation.Decimal left, Microsoft.Windows.Foundation.Decimal right) - //TODO { - //TODO return left.m_value.Add(right.m_value); - //TODO } - - public static Microsoft.Windows.Foundation.Decimal Add(this Microsoft.Windows.Foundation.Decimal left, System.Decimal right) - { - return left.Add(right); - } - } -} diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md index bd69cbc941..f11af10ef7 100644 --- a/specs/decimal/decimal.md +++ b/specs/decimal/decimal.md @@ -12,7 +12,7 @@ Potential future changes 1. Add floor() - round towards +infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.floor 2. Add ceil() - round towards -infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.ceiling 1. Rename integer() to ceil() ? - 3. Add round towards zero + 3. Add floor-ceil-variant() - round towards zero 4. decimal zero{}; decimal neg{ -zero }; neg.sign() < 0 because DECIMAL.sign = 0x80. Treat -0 the same as +0 (prevent -0 from being set?) 2. winrt::Microsoft::Windows::Foundation::Decimal 1. Rename ToDecimal() -- Copy(value) or Clone(value) @@ -32,9 +32,12 @@ Potential future changes 7. Add ctor(type) where type = bool / [u]int8/16/32/64 / float / double ? 8. Add operator=(type) where type = bool / [u]int8/16/32/64 / float / double ? 4. Microsoft.Windows.Foundation.Projection - 1. Delete WDecimal.cs - 2. Add WinRT<->C# conversion functions - 1. System.Decimal ToSystemDecimal(Microsoft.Windows.Foundation.Decimal from) - 1. System.Decimal ToSystemDecimal(Microsoft.Windows.Foundation.DecimalValue from) - 1. Microsoft.Windows.Foundation.Decimal ToDecimal(System.Decimal from) - 1. Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(System.Decimal from) + 1. Add more WinRT<->C# conversion functions + 1. Constructors +5. C# Tests + 1. TAEF for C# ? + 2. Port test\inc\WindowsAppRuntime.Test.Package.h to C# + 3. Port test\inc\WindowsAppRuntime.Test.Bootstrap.h to C# + 4. Register framework package + 5. Bootstrap.Initialize() + 6. Implement remaining tests diff --git a/test/Decimal/CS/DotNetTests.cs b/test/Decimal/CS/DotNetTests.cs index c510e88c89..c54a262635 100644 --- a/test/Decimal/CS/DotNetTests.cs +++ b/test/Decimal/CS/DotNetTests.cs @@ -633,5 +633,25 @@ private static Decimal abs(Decimal value) var zero = new Decimal(0); return value.CompareTo(zero) < 0 ? -value : value; } + + public static void ToDecimal() + { + // TODO ToDecimal tests + } + + public static void ToDecimalValue() + { + // TODO ToDecimalValue tests + } + + public static void FromDecimal() + { + // TODO FromDecimal tests + } + + public static void FromDecimalValue() + { + // TODO FromDecimalValue tests + } } } From 2aa66ca7d4bb9c17bd40a1506299e8b257650c0b Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 10:28:18 -0700 Subject: [PATCH 20/25] Decimal C# enhancements --- .../DecimalExtensions.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs b/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs new file mode 100644 index 0000000000..c23430f045 --- /dev/null +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; + +namespace Microsoft.Windows.Foundation +{ + public static class DecimalExtensions + { + /// Return a WinRT Decimal object. + public static Microsoft.Windows.Foundation.Decimal ToDecimal(this System.Decimal d) + { + return Microsoft.Windows.Foundation.Decimal.CreateFromDecimalValue(ToDecimalValue(d)); + } + + /// Return a WinRT DecimalValue structure.. + public static Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(this System.Decimal d) + { + // decimal.GetBits() returns a binary representation of a Decimal. The return value is an + // integer array with four elements. Elements 0, 1, and 2 contain the low, + // middle, and high 32 bits of the 96-bit integer part of the Decimal. + // Element 3 contains the scale factor and sign of the Decimal: bits 0-15 + // (the lower word) are unused; bits 16-23 contain a value between 0 and + // 28, indicating the power of 10 to divide the 96-bit integer part by to + // produce the Decimal value; bits 24-30 are unused; and finally bit 31 + // indicates the sign of the Decimal value, 0 meaning positive and 1 + // meaning negative. + // [0] = (int)d.Low; + // [1] = (int)d.Mid; + // [2] = (int)d.High; + // [3] = d._flags; + // where d._flags is 2 bytes reserved, 1 byte sign, 1 byte scale + // + // @see https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Private.CoreLib/src/System/Decimal.cs#L581C13-L581C80 + + int[] bits = System.Decimal.GetBits(d); + + var decimalValue = new Microsoft.Windows.Foundation.DecimalValue(); + decimalValue.Sign = (byte)((bits[3] & 0x80000000) >> 24); + decimalValue.Scale = (byte)((bits[3] & 0x00FF0000) >> 16); + decimalValue.Hi32 = (uint)bits[2]; + ulong low32 = (ulong)bits[0]; + ulong mid32 = (ulong)bits[1]; + decimalValue.Lo64 = ((low32 << 32) | mid32); + return decimalValue; + } + + /// Return a C# Decimal object. + public static System.Decimal FromDecimalValue(this System.Decimal d, Microsoft.Windows.Foundation.DecimalValue value) + { + int low32 = (int)(value.Lo64 & 0x00000000FFFFFFFF); + int mid32 = (int)((value.Lo64 >> 32) & 0x00000000FFFFFFFF); + return new System.Decimal(low32, mid32, (int)value.Hi32, value.Sign != 0, value.Scale); + } + + /// Return a C# Decimal object. + public static System.Decimal FromDecimal(this System.Decimal d, Microsoft.Windows.Foundation.Decimal value) + { + return FromDecimalValue(d, value.ToDecimalValue()); + } + } +} From 3eb71fa64d422d5b45a63af4712f9bc24b4403e2 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 12:25:12 -0700 Subject: [PATCH 21/25] Add missing Copyright headers. Fix tools\VerifyCopyrightHeaders.ps1 to not search under root\Packages (for some reason the `Where...-notmatch $exclude` is performing a case-sensntive comparison when docs say it should be csae-insensitive. A little brute-force fix to prevent the pain --- test/Decimal/CS/DotNetTests.cs | 3 +++ test/Decimal/CS/Program.cs | 3 +++ test/Decimal/CS/Verify.cs | 3 +++ test/Decimal/CS/WinAppSDKTests.cs | 3 +++ test/Decimal/DecimalCalcuator/CS/Program.cs | 3 +++ tools/VerifyCopyrightHeaders.ps1 | 2 +- 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/test/Decimal/CS/DotNetTests.cs b/test/Decimal/CS/DotNetTests.cs index c54a262635..cefbdb8964 100644 --- a/test/Decimal/CS/DotNetTests.cs +++ b/test/Decimal/CS/DotNetTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + using System; using Test; diff --git a/test/Decimal/CS/Program.cs b/test/Decimal/CS/Program.cs index 2ec1d2cbc0..eb0b536b24 100644 --- a/test/Decimal/CS/Program.cs +++ b/test/Decimal/CS/Program.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + using System; using Test.DotNet; using Test.WinAppSDK; diff --git a/test/Decimal/CS/Verify.cs b/test/Decimal/CS/Verify.cs index daab6502e4..b54d5dbd50 100644 --- a/test/Decimal/CS/Verify.cs +++ b/test/Decimal/CS/Verify.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + using System; using System.Diagnostics; diff --git a/test/Decimal/CS/WinAppSDKTests.cs b/test/Decimal/CS/WinAppSDKTests.cs index a3c0f38fe4..ef5dcb3a3d 100644 --- a/test/Decimal/CS/WinAppSDKTests.cs +++ b/test/Decimal/CS/WinAppSDKTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + using System; namespace Test.WinAppSDK diff --git a/test/Decimal/DecimalCalcuator/CS/Program.cs b/test/Decimal/DecimalCalcuator/CS/Program.cs index 7819fda240..51ea956a55 100644 --- a/test/Decimal/DecimalCalcuator/CS/Program.cs +++ b/test/Decimal/DecimalCalcuator/CS/Program.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + using System; namespace Microsoft.Windows.Foundation diff --git a/tools/VerifyCopyrightHeaders.ps1 b/tools/VerifyCopyrightHeaders.ps1 index a974ecabdd..a9e42048ae 100644 --- a/tools/VerifyCopyrightHeaders.ps1 +++ b/tools/VerifyCopyrightHeaders.ps1 @@ -22,7 +22,7 @@ $copyrightHeaderText = ( ) $include = ('*.cs', '*.cpp', '*.h', '*.idl', '*.xaml') -$exclude = [RegEx]'\\dev\\Detours\\|\\BuildOutput\\|\\obj\\|\\localpackages\\|\\packages\\|\\specs\\|\\temp\\|\\Debug\\|\\Release\\|\\ItemTemplates\\|\\ProjectTemplates\\|\\WindowsAppSDKAggregator\\' +$exclude = [RegEx]'\\dev\\Detours\\|\\BuildOutput\\|\\obj\\|\\localpackages\\|\\packages\\|\\Packages\\|\\specs\\|\\temp\\|\\Debug\\|\\Release\\|\\ItemTemplates\\|\\ProjectTemplates\\|\\WindowsAppSDKAggregator\\' $files = dir $PSScriptRoot\..\* -recurse -include $include | Where FullName -notmatch $exclude $errorCount = 0 From cee6ff8cd795280b4ae4413eabbc38c7e2bbcb5e Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 16:34:43 -0700 Subject: [PATCH 22/25] Incorporated feedback --- dev/Decimal/M.W.F.Decimal.cpp | 3 +-- dev/Decimal/decimalcppwinrt.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dev/Decimal/M.W.F.Decimal.cpp b/dev/Decimal/M.W.F.Decimal.cpp index 6041e76b5a..a1c8da8562 100644 --- a/dev/Decimal/M.W.F.Decimal.cpp +++ b/dev/Decimal/M.W.F.Decimal.cpp @@ -171,8 +171,7 @@ namespace winrt::Microsoft::Windows::Foundation::implementation } void Decimal::SetFromDecimalValue(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) { - const auto& decimalValue{ *reinterpret_cast(&value) }; - m_decimal = decimalValue; + m_decimal = std::bit_cast(value); } bool Decimal::ToBoolean() { diff --git a/dev/Decimal/decimalcppwinrt.h b/dev/Decimal/decimalcppwinrt.h index 5ca4760a26..ee3dcfda12 100644 --- a/dev/Decimal/decimalcppwinrt.h +++ b/dev/Decimal/decimalcppwinrt.h @@ -59,7 +59,7 @@ namespace winrt::Microsoft::Windows::Foundation /// Return value as DECIMAL. inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::DecimalValue const& value) { - return *reinterpret_cast(&value); + return std::bit_cast(value); } /// Return value as DECIMAL. @@ -71,7 +71,7 @@ inline DECIMAL to_DECIMAL(winrt::Microsoft::Windows::Foundation::Decimal const& /// Return value as a WinRT DecimalValue structure. inline winrt::Microsoft::Windows::Foundation::DecimalValue to_DecimalValue(DECIMAL const& value) { - return *reinterpret_cast(&value); + return std::bit_cast(value); } /// Return value as a WinRT Decimal object. From 55dff0d8b834ce95a67ccf02554f6f2e5dc4ee91 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 17:26:53 -0700 Subject: [PATCH 23/25] Incorporate feedback --- .../DecimalExtensions.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs b/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs index 34f2cbe328..b842aa92a1 100644 --- a/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs +++ b/dev/Projections/CS/Microsoft.Windows.Foundation/DecimalExtensions.cs @@ -11,13 +11,13 @@ namespace Microsoft.Windows.Foundation public static class DecimalExtensions { /// Return a WinRT Decimal object. - public static Microsoft.Windows.Foundation.Decimal ToDecimal(this System.Decimal d) + public static Microsoft.Windows.Foundation.Decimal ToDecimal(this decimal d) { return Microsoft.Windows.Foundation.Decimal.CreateFromDecimalValue(ToDecimalValue(d)); } /// Return a WinRT DecimalValue structure.. - public static Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(this System.Decimal d) + public static Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(this decimal d) { // decimal.GetBits() returns a binary representation of a Decimal. The return value is an // integer array with four elements. Elements 0, 1, and 2 contain the low, @@ -36,7 +36,8 @@ public static Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(this Syst // // @see https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Private.CoreLib/src/System/Decimal.cs#L581C13-L581C80 - int[] bits = System.Decimal.GetBits(d); + Span bits = stackalloc int[4]; + decimal.GetBits(d, bits); var decimalValue = new Microsoft.Windows.Foundation.DecimalValue(); decimalValue.Sign = (byte)((bits[3] & 0x80000000) >> 24); @@ -49,15 +50,15 @@ public static Microsoft.Windows.Foundation.DecimalValue ToDecimalValue(this Syst } /// Return a C# Decimal object. - public static System.Decimal FromDecimalValue(this System.Decimal d, Microsoft.Windows.Foundation.DecimalValue value) + public static decimal FromDecimalValue(this decimal d, Microsoft.Windows.Foundation.DecimalValue value) { int low32 = (int)(value.Lo64 & 0x00000000FFFFFFFF); int mid32 = (int)((value.Lo64 >> 32) & 0x00000000FFFFFFFF); - return new System.Decimal(low32, mid32, (int)value.Hi32, value.Sign != 0, value.Scale); + return new decimal(low32, mid32, (int)value.Hi32, value.Sign != 0, value.Scale); } /// Return a C# Decimal object. - public static System.Decimal FromDecimal(this System.Decimal d, Microsoft.Windows.Foundation.Decimal value) + public static decimal FromDecimal(this decimal d, Microsoft.Windows.Foundation.Decimal value) { return FromDecimalValue(d, value.ToDecimalValue()); } From 3e2b54394d52bf6895e25955169bb525f3446d25 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 18:23:21 -0700 Subject: [PATCH 24/25] Expanded spec. Not ready for review yet --- dev/Decimal/Decimal.idl | 14 +-- specs/decimal/decimal.md | 264 +++++++++++++++++++++++++++++++++++---- 2 files changed, 248 insertions(+), 30 deletions(-) diff --git a/dev/Decimal/Decimal.idl b/dev/Decimal/Decimal.idl index 8e81cada61..f0e44b3f02 100644 --- a/dev/Decimal/Decimal.idl +++ b/dev/Decimal/Decimal.idl @@ -5,7 +5,7 @@ namespace Microsoft.Windows.Foundation { - [contractversion(2)] + [contractversion(1)] apicontract DecimalContract{}; [feature(Feature_Decimal)] @@ -13,8 +13,8 @@ namespace Microsoft.Windows.Foundation struct DecimalValue { UInt16 Reserved; - UInt8 Scale; - UInt8 Sign; + UInt8 Scale; // Allowed values: 0-28 + UInt8 Sign; // Allowed values: 0x80 = negative, 0x00 = zero or positive UInt32 Hi32; UInt64 Lo64; }; @@ -125,15 +125,15 @@ namespace Microsoft.Windows.Foundation Decimal Add(Decimal value); /// Returns a Decimal whose value is (this - value). - Decimal Sub(Decimal value); //TODO Rename to Subtract() ? + Decimal Sub(Decimal value); /// Returns a Decimal whose value is (this * value). - Decimal Mul(Decimal value); //TODO Rename to Multiply() ? + Decimal Mul(Decimal value); /// Returns a Decimal whose value is (this / value). - Decimal Div(Decimal value); //TODO Rename to Divide() ? + Decimal Div(Decimal value); /// Returns a Decimal whose value is (this % value). - Decimal Mod(Decimal value); //TODO Rename to Modulo() or Remainder() ? + Decimal Mod(Decimal value); } } diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md index f11af10ef7..e7d67fb72d 100644 --- a/specs/decimal/decimal.md +++ b/specs/decimal/decimal.md @@ -1,39 +1,257 @@ # 1. Decimal -This feature provides a WinRT decimal data type comparable to .NET's [System.Decimal](https://learn.microsoft.com/dotnet/api/system.decimal). +THIS FEATURE IS CURRENTLY EXPERIMENTAL. -# 2. TODO +This feature provides a common decimal representation and aids for use within and across programming languages. -THIS FEATURE IS CURRENTLY EXPERIMENTAL. +Some languages have a native decimal data type, e.g. [Decimal struct in C#](https://learn.microsoft.com/dotnet/api/system.decimal) +and [decimal in Python](https://docs.python.org/3/library/decimal.html). These are recommended for +use in their languages. Windows App SDK provides supplemental aids for interoperability with the +common data type. -Potential future changes +Other languages have no native decimal data type e.g. C++, Rust and Javascript. Windows App SDK +provides language native support for some languages including interoperability with the common data +type: -1. C++ class +* C++ -- `Microsoft::Windows::Foundation::decimal` + +Windows App SDK provides a decimal WinRT runtimeclass `Microsoft.Windows.Foundation.Decimal` as a +fallback for languages without a native decimal data type (whether provided by the language or +Windows App SDK). This is fully functional but has performance overhead relative to language native +data types which are commonly stack allocated and offer better language integration. The WinRT type +is recommended when your language has no native type or other comparable solution. + +# 2. Common Decimal Representation + +The [DECIMAL structure](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) +is the common decimal format, stored as a 96-bit (12-byte) unsigned integer scaled by a variable +power of 10. The power of 10 scaling factor specifies the number of digits to the right of the +decimal point, and ranges from 0 to 28. This is expressed in WinRT as the following structure: + +```c# (but really midl3) + struct DecimalValue + { + UInt16 Reserved; + Byte Scale; // Allowed values: 0-28 + Byte Sign; // Allowed values: 0x80 = negative, 0x00 = zero or positive + UInt32 Hi32; + UInt64 Lo64; + } +``` + +This matches the memory layout and use of the [Win32 DECIMAL structure](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) +and the [C# Decimal struct](https://learn.microsoft.com/dotnet/api/system.decimal). This data +structure may be re-expressed in each language using language-specific constructs e.g. WinRT defines +the `DecimalValue` structure as the Win32 `DECIMAL` definition syntax is incompatible with WinRT IDL. + +# 3. WinRT API + +Windows App SDK provides a `Decimal` WinRT runtimeclass in addition to the `DecimalValue` structure. + +```c# (but really MIDL3) +namespace Microsoft.Windows.Foundation +{ + [contractversion(1)] + apicontract DecimalContract{}; + + [feature(Feature_Decimal)] + [contract(DecimalContract, 1)] + struct DecimalValue + { + UInt16 Reserved; + UInt8 Scale; // Allowed values: 0-28 + UInt8 Sign; // Allowed values: 0x80 = negative, 0x00 = zero or positive + UInt32 Hi32; + UInt64 Lo64; + }; + + [feature(Feature_Decimal)] + [contract(DecimalContract, 1)] + runtimeclass Decimal : Windows.Foundation.IStringable + { + Decimal(); + + static Decimal CreateFromBoolean(Boolean value); + static Decimal CreateFromInt16(Int16 value); + static Decimal CreateFromInt32(Int32 value); + static Decimal CreateFromInt64(Int64 value); + static Decimal CreateFromUInt8(UInt8 value); + static Decimal CreateFromUInt16(UInt16 value); + static Decimal CreateFromUInt32(UInt32 value); + static Decimal CreateFromUInt64(UInt64 value); + static Decimal CreateFromSingle(Single value); + static Decimal CreateFromDouble(Double value); + static Decimal CreateFromString(String value); // LCID=LOCALE_INVARIANT + static Decimal CreateFromStringWithSystemDefaultLocale(String value); // LCID=GetSystemDefaultLCID() + static Decimal CreateFromStringWithUserDefaultLocale(String value); // LCID=GetUserDefaultLCID() + static Decimal CreateFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() + static Decimal CreateFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT + static Decimal Create(IInspectable value); + static Decimal CreateFromDecimal(Decimal value); + static Decimal CreateFromDecimalValue(DecimalValue value); + + void SetFromBoolean(Boolean value); + void SetFromInt16(Int16 value); + void SetFromInt32(Int32 value); + void SetFromInt64(Int64 value); + void SetFromUInt8(UInt8 value); + void SetFromUInt16(UInt16 value); + void SetFromUInt32(UInt32 value); + void SetFromUInt64(UInt64 value); + void SetFromSingle(Single value); + void SetFromDouble(Double value); + void SetFromString(String value); // LCID=LOCALE_INVARIANT + void SetFromStringWithSystemDefaultLocale(String value); // LCID=GetSystemDefaultLCID() + void SetFromStringWithUserDefaultLocale(String value); // LCID=GetUserDefaultLCID() + void SetFromStringWithThreadLocale(String value); // LCID=GetThreadLocale() + void SetFromStringWithInvariantLocale(String value); // LCID=LOCALE_INVARIANT + void Set(IInspectable value); + void SetFromDecimal(Decimal value); + void SetFromDecimalValue(DecimalValue value); + + Boolean ToBoolean(); + Int16 ToInt16(); + Int32 ToInt32(); + Int64 ToInt64(); + UInt8 ToUInt8(); + UInt16 ToUInt16(); + UInt32 ToUInt32(); + UInt64 ToUInt64(); + Single ToSingle(); + Double ToDouble(); + //String ToString(); inherited from IStringable // LCID=LOCALE_INVARIANT + String ToStringWithSystemDefaultLocale(); // LCID=GetSystemDefaultLCID() + String ToStringWithUserDefaultLocale(); // LCID=GetUserDefaultLCID() + String ToStringWithThreadLocale(); // LCID=GetThreadLocale() + String ToStringWithInvariantLocale(); // LCID=LOCALE_INVARIANT + IInspectable ToObject(); + Decimal ToDecimal(); //TODO: Rename to Copy(value) or Clone(value) ? + DecimalValue ToDecimalValue(); + + /// Return true if (this == value). + Boolean Equals(Decimal value); + + /// Compare this decimal with value. + /// @return 0 if this and value are equal, <0 if this is less than value or >0 if this is greater than value. + Int32 Compare(Decimal value); + + /// Return the scaling factor of the value (the number of decimal digits). + /// @return the scaling factor, ranging from 0 to max_scale(). + UInt32 Scale { get; }; + + /// Return the sign of the value. + /// @return 0 if this os zero, <0 if this is less than zero or >0 if this is greater than zero. + Int32 Sign { get; }; + + /// Return the maximum scaling factor + static UInt32 MaxScale{ get; }; + + /// Return the maximum value (79,228,162,514,264,337,593,543,950,335). + static Decimal MaxValue{ get; }; + + /// Return the minimum value (-79,228,162,514,264,337,593,543,950,335). + static Decimal MinValue{ get; }; + + /// Return a decimal whose value is (-this). + Decimal Negate(); + + /// Return the absolute value. + Decimal Abs(); + + /// Return the value's integer portion (zero to the right of the decimal point). + Decimal Fix(); + + /// Return the value rounded down to the nearest integer. + Decimal Integer(); + + /// Return the value rounded to the specific number of decimal places. + Decimal Round(Int32 decimalPlaces); + + /// Returns a Decimal whose value is (this + value). + Decimal Add(Decimal value); + + /// Returns a Decimal whose value is (this - value). + Decimal Sub(Decimal value); + + /// Returns a Decimal whose value is (this * value). + Decimal Mul(Decimal value); + + /// Returns a Decimal whose value is (this / value). + Decimal Div(Decimal value); + + /// Returns a Decimal whose value is (this % value). + Decimal Mod(Decimal value); + } +} +``` + +# 4. C++ API + +Windows App SDK provides a native language decimal data type for C++ as the +`Microsoft::Windows::Foundation::decimal` class in `decimal.h`. This class has the following features: + +* Constructor and assignment (operator=) overloads to define a decimal object from various data types +* to_xxx() methods converting a decimal object's value to various data types +* Relational operations: `compare()` `==` `!=` `<` `<=` `>` `>=` +* Unary operations: + - ++ -- +* Binary operations: + += - -= * *= / /= % %= +* Properties: `sign()` `scale()` +* Mathematical operations: `abs()` `fix()` `integer()` `round()` +* Constants: `max_scale()` `max_value()` `min_value()` + +Errors are expressed via thrown exceptions e.g. `decimal{1} / decimal{0}` will throw a divide-by-zero exception + +## 4.1. Microsoft.Windows.Foundation (C++) + +TODO insert header filename(s) and API here + +# 6. Open Issues + +# 6.1. API Review + +Potential changes for API Review consideration: + +1. String conversions - How to handle + 1. VarDecFromStr() and VarBStrFromDec() support localization via LCID. WinRT doesn't. + 1. Support LCID for localization? + 1. C++ has to/from string with taking (value, LCID) with default LCID=LOCALE_INVARIANT + 2. WinRT has pre-canned variants: + 1. ToStringWithSystemDefaultLocale(); // LCID=GetSystemDefaultLCID() + 2. ToStringWithUserDefaultLocale(); // LCID=GetUserDefaultLCID() + 3. ToStringWithThreadLocale(); // LCID=GetThreadLocale() + 4. ToStringWithInvariantLocale(); // LCID=LOCALE_INVARIANT + 5. ToString() == ToStringWithInvariantLocale() + 2. Use alternative ??? for localization? + 1. ??? <-> LCID conversion APIs? + 2. Rewrite VarDecFromStr() and VBstrFromDec() as equivalents using ??? +2. C++ class 1. Add floor() - round towards +infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.floor 2. Add ceil() - round towards -infinity. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.ceiling 1. Rename integer() to ceil() ? 3. Add floor-ceil-variant() - round towards zero - 4. decimal zero{}; decimal neg{ -zero }; neg.sign() < 0 because DECIMAL.sign = 0x80. Treat -0 the same as +0 (prevent -0 from being set?) +3. winrt::Microsoft::Windows::Foundation::Decimal + 1. Rename ToDecimal() to Copy(value) or Clone(value) + 2. Add Floor() + 3. Rename Integer() to Ceil() + 4. Add Floor-Ceil-Variant() for rounds towards zero + 5. Rename Sub() to Subtract() + 6. Rename Mul() to Multiply() + 7. Rename Div() to Divide() + 8. Rename Mod() to Remainder() + +# 6.2. TODO + +Punchlist to reach Stable: + +1. C++ class + 1. BUG? decimal zero{}; decimal neg{ -zero }; neg.sign() < 0 because DECIMAL.sign = 0x80. Treat -0 the same as +0 (prevent -0 from being set?) 2. winrt::Microsoft::Windows::Foundation::Decimal - 1. Rename ToDecimal() -- Copy(value) or Clone(value) - 2. Rename Sub() to Subtract() - 3. Rename Mul() to Multiply() - 4. Rename Div() to Divide() - 5. Rename Mod() to Modulo() or Remainder() - 6. Implement IInspectable methods -- Create(IInspectable), Set(IInspectable), ToObject() - 7. Add experimental checks in ctor + static methods + 1. Implement IInspectable methods -- Create(IInspectable), Set(IInspectable), ToObject() + 2. Add experimental checks in ctor + static methods 3. decimalcppwinrt.h - 1. Add operator+ - 2. Add operator- - 3. Add operator++ - 4. Add operator-- - 5. Add operator + - * / % - 6. Add operator += -= *= /= %= - 7. Add ctor(type) where type = bool / [u]int8/16/32/64 / float / double ? - 8. Add operator=(type) where type = bool / [u]int8/16/32/64 / float / double ? + 1. Merge into decimal.h 4. Microsoft.Windows.Foundation.Projection - 1. Add more WinRT<->C# conversion functions - 1. Constructors + 1. --none-- 5. C# Tests 1. TAEF for C# ? 2. Port test\inc\WindowsAppRuntime.Test.Package.h to C# From 40c79cfb412e827c7fae68bbab6c462804e5ee65 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Mon, 28 Apr 2025 18:27:11 -0700 Subject: [PATCH 25/25] Fixed Markdown --- specs/decimal/decimal.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/specs/decimal/decimal.md b/specs/decimal/decimal.md index e7d67fb72d..cf72dfeaff 100644 --- a/specs/decimal/decimal.md +++ b/specs/decimal/decimal.md @@ -23,10 +23,10 @@ is recommended when your language has no native type or other comparable solutio # 2. Common Decimal Representation -The [DECIMAL structure](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) -is the common decimal format, stored as a 96-bit (12-byte) unsigned integer scaled by a variable -power of 10. The power of 10 scaling factor specifies the number of digits to the right of the -decimal point, and ranges from 0 to 28. This is expressed in WinRT as the following structure: +The Win32 [DECIMAL](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) +structure is the common decimal format, stored as a 96-bit (12-byte) unsigned integer scaled by a +variable power of 10. The power of 10 scaling factor specifies the number of digits to the right of +the decimal point, and ranges from 0 to 28. This is expressed in WinRT as the following structure: ```c# (but really midl3) struct DecimalValue @@ -39,10 +39,11 @@ decimal point, and ranges from 0 to 28. This is expressed in WinRT as the follow } ``` -This matches the memory layout and use of the [Win32 DECIMAL structure](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) -and the [C# Decimal struct](https://learn.microsoft.com/dotnet/api/system.decimal). This data -structure may be re-expressed in each language using language-specific constructs e.g. WinRT defines -the `DecimalValue` structure as the Win32 `DECIMAL` definition syntax is incompatible with WinRT IDL. +This matches the memory layout and use of the Win32 [DECIMAL](https://learn.microsoft.com/windows/win32/api/wtypes/ns-wtypes-decimal-r1) +structure and the [C# Decimal struct](https://learn.microsoft.com/dotnet/api/system.decimal). This +data structure may be re-expressed in each language using language-specific constructs e.g. WinRT +defines the `DecimalValue` structure as the Win32 `DECIMAL` definition syntax is incompatible with +WinRT IDL. # 3. WinRT API