-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create unit tests for Calculator plugin (#6356)
* Refactored logic and made it unit testable * Changes after code review * Added to build steps, and modified bracket to new class with unittest. Validates complexer cases now. Co-authored-by: p-storm <paul.de.man@gmail.com>
- Loading branch information
Showing
11 changed files
with
519 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/modules/launcher/Plugins/Microsoft.Plugin.Calculator.UnitTest/BracketHelperTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using NUnit.Framework; | ||
|
||
namespace Microsoft.Plugin.Calculator.UnitTests | ||
{ | ||
[TestFixture] | ||
public class BracketHelperTests | ||
{ | ||
[TestCase(null)] | ||
[TestCase("")] | ||
[TestCase("\t \r\n")] | ||
[TestCase("none")] | ||
[TestCase("()")] | ||
[TestCase("(())")] | ||
[TestCase("()()")] | ||
[TestCase("(()())")] | ||
[TestCase("([][])")] | ||
[TestCase("([(()[])[](([]()))])")] | ||
public void IsBracketComplete_TestValid_WhenCalled(string input) | ||
{ | ||
// Arrange | ||
|
||
// Act | ||
var result = BracketHelper.IsBracketComplete(input); | ||
|
||
// Assert | ||
Assert.IsTrue(result); | ||
} | ||
|
||
[TestCase("((((", "only opening brackets")] | ||
[TestCase("]]]", "only closing brackets")] | ||
[TestCase("([)(])", "inner bracket mismatch")] | ||
[TestCase(")(", "opening and closing reversed")] | ||
[TestCase("(]", "mismatch in bracket type")] | ||
public void IsBracketComplete_TestInvalid_WhenCalled(string input, string invalidReason) | ||
{ | ||
// Arrange | ||
|
||
// Act | ||
var result = BracketHelper.IsBracketComplete(input); | ||
|
||
// Assert | ||
Assert.IsFalse(result, invalidReason); | ||
} | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
...es/launcher/Plugins/Microsoft.Plugin.Calculator.UnitTest/ExtendedCalculatorParserTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Globalization; | ||
using NUnit.Framework; | ||
|
||
namespace Microsoft.Plugin.Calculator.UnitTests | ||
{ | ||
[TestFixture] | ||
public class ExtendedCalculatorParserTests | ||
{ | ||
[TestCase(null)] | ||
[TestCase("")] | ||
[TestCase(" ")] | ||
public void InputValid_ThrowError_WhenCalledNullOrEmpty(string input) | ||
{ | ||
// Act | ||
Assert.Catch<ArgumentNullException>(() => CalculateHelper.InputValid(input)); | ||
} | ||
|
||
[TestCase(null)] | ||
[TestCase("")] | ||
[TestCase(" ")] | ||
public void Interpret_ThrowError_WhenCalledNullOrEmpty(string input) | ||
{ | ||
// Arrange | ||
var engine = new CalculateEngine(); | ||
|
||
// Act | ||
Assert.Catch<ArgumentNullException>(() => engine.Interpret(input)); | ||
} | ||
|
||
[TestCase("42")] | ||
[TestCase("test")] | ||
public void Interpret_NoResult_WhenCalled(string input) | ||
{ | ||
// Arrange | ||
var engine = new CalculateEngine(); | ||
|
||
// Act | ||
var result = engine.Interpret(input); | ||
|
||
// Assert | ||
Assert.AreEqual(default(CalculateResult), result); | ||
} | ||
|
||
[TestCase("2 * 2", 4D)] | ||
[TestCase("-2 ^ 2", 4D)] | ||
[TestCase("-(2 ^ 2)", -4D)] | ||
[TestCase("2 * pi", 6.28318530717959D)] | ||
[TestCase("round(2 * pi)", 6D)] | ||
[TestCase("1 == 2", default(double))] | ||
[TestCase("pi * ( sin ( cos ( 2)))", -1.26995475603563D)] | ||
[TestCase("5.6/2", 2.8D)] | ||
[TestCase("123 * 4.56", 560.88D)] | ||
[TestCase("1 - 9.0 / 10", 0.1D)] | ||
[TestCase("0.5 * ((2*-395.2)+198.2)", -296.1D)] | ||
[TestCase("2+2.11", 4.11D)] | ||
public void Interpret_NoErrors_WhenCalled(string input, decimal expectedResult) | ||
{ | ||
// Arrange | ||
var engine = new CalculateEngine(); | ||
|
||
// Act | ||
var result = engine.Interpret(input, CultureInfo.InvariantCulture); | ||
|
||
// Assert | ||
Assert.IsNotNull(result); | ||
Assert.AreEqual(expectedResult, result.Result); | ||
} | ||
|
||
[TestCase("0.100000000000000000000", 0.00776627963145224D)] // BUG: Because data structure | ||
[TestCase("0.200000000000000000000000", 0.000000400752841041379D)] // BUG: Because data structure | ||
[TestCase("123 456", 56088D)] // BUG: Framework accepts ' ' as multiplication | ||
public void Interpret_QuirkOutput_WhenCalled(string input, decimal expectedResult) | ||
{ | ||
// Arrange | ||
var engine = new CalculateEngine(); | ||
|
||
// Act | ||
var result = engine.Interpret(input, CultureInfo.InvariantCulture); | ||
|
||
// Assert | ||
Assert.IsNotNull(result); | ||
Assert.AreEqual(expectedResult, result.Result); | ||
} | ||
|
||
[TestCase("4.5/3", 1.5D, "nl-NL")] | ||
[TestCase("4.5/3", 1.5D, "en-EN")] | ||
[TestCase("4.5/3", 1.5D, "de-DE")] | ||
public void Interpret_DifferentCulture_WhenCalled(string input, decimal expectedResult, string cultureName) | ||
{ | ||
// Arrange | ||
var cultureInfo = CultureInfo.GetCultureInfo(cultureName); | ||
var engine = new CalculateEngine(); | ||
|
||
// Act | ||
var result = engine.Interpret(input, cultureInfo); | ||
|
||
// Assert | ||
Assert.IsNotNull(result); | ||
Assert.AreEqual(expectedResult, result.Result); | ||
} | ||
|
||
[TestCase("ceil(2 * (pi ^ 2))", true)] | ||
[TestCase("((1 * 2)", false)] | ||
[TestCase("(1 * 2)))", false)] | ||
[TestCase("abcde", false)] | ||
[TestCase("plot( 2 * 3)", true)] | ||
public void InputValid_TestValid_WhenCalled(string input, bool valid) | ||
{ | ||
// Arrange | ||
|
||
// Act | ||
var result = CalculateHelper.InputValid(input); | ||
|
||
// Assert | ||
Assert.AreEqual(valid, result); | ||
} | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
.../Plugins/Microsoft.Plugin.Calculator.UnitTest/Microsoft.Plugin.Calculator.UnitTest.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
|
||
<IsPackable>false</IsPackable> | ||
<Platforms>x64</Platforms> | ||
<RootNamespace>Microsoft.Plugin.Calculator.UnitTests</RootNamespace> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="nunit" Version="3.12.0" /> | ||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\Microsoft.Plugin.Calculator\Microsoft.Plugin.Calculator.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs"> | ||
<Link>GlobalSuppressions.cs</Link> | ||
</Compile> | ||
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json"> | ||
<Link>StyleCop.json</Link> | ||
</AdditionalFiles> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="StyleCop.Analyzers"> | ||
<Version>1.1.118</Version> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
<PrivateAssets>all</PrivateAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
</Project> |
87 changes: 87 additions & 0 deletions
87
src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/BracketHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Microsoft.Plugin.Calculator | ||
{ | ||
public static class BracketHelper | ||
{ | ||
public static bool IsBracketComplete(string query) | ||
{ | ||
if (string.IsNullOrWhiteSpace(query)) | ||
{ | ||
return true; | ||
} | ||
|
||
var valueTuples = query | ||
.Select(BracketTrail) | ||
.Where(r => r != default); | ||
|
||
var trailTest = new Stack<TrailType>(); | ||
|
||
foreach (var (direction, type) in valueTuples) | ||
{ | ||
switch (direction) | ||
{ | ||
case TrailDirection.Open: | ||
trailTest.Push(type); | ||
break; | ||
case TrailDirection.Close: | ||
// Try to get item out of stack | ||
if (!trailTest.TryPop(out var popped)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (type != popped) | ||
{ | ||
return false; | ||
} | ||
|
||
continue; | ||
default: | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(direction), direction, "Can't process value"); | ||
} | ||
} | ||
} | ||
|
||
return !trailTest.Any(); | ||
} | ||
|
||
private static (TrailDirection direction, TrailType type) BracketTrail(char @char) | ||
{ | ||
switch (@char) | ||
{ | ||
case '(': | ||
return (TrailDirection.Open, TrailType.Round); | ||
case ')': | ||
return (TrailDirection.Close, TrailType.Round); | ||
case '[': | ||
return (TrailDirection.Open, TrailType.Bracket); | ||
case ']': | ||
return (TrailDirection.Close, TrailType.Bracket); | ||
default: | ||
return default; | ||
} | ||
} | ||
|
||
private enum TrailDirection | ||
{ | ||
None, | ||
Open, | ||
Close, | ||
} | ||
|
||
private enum TrailType | ||
{ | ||
None, | ||
Bracket, | ||
Round, | ||
} | ||
} | ||
} |
Oops, something went wrong.