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