Hello GitHub

This commit is contained in:
Howard Wolosky
2019-01-28 16:24:37 -08:00
parent 456fe5e355
commit c13b8a099e
822 changed files with 276650 additions and 75 deletions

View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{24767C43-CD5A-4DC9-8D6B-429F255524E5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Calculator.TestPackage</RootNamespace>
<AssemblyName>Calculator.TestPackage</AssemblyName>
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<NuGetTargetMoniker>.NETCore,Version=v5.0</NuGetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17763.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<FileAlignment>512</FileAlignment>
<!-- The app doesn't contain any tests so we don't generate a testmd -->
<NoTestMD>true</NoTestMD>
<NoPackage Condition="'$(IsTFSBuild)' != 'True'">True</NoPackage>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\x86</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\x86</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\x64</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\x64</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\arm</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\arm</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\ARM64\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\ARM64\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<None Include="Calculator.TestPackage.wm.xml" />
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Calculator\Calculator.vcxproj">
<Project>{9447424a-0e05-4911-beb8-e0354405f39a}</Project>
<Name>Calculator</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0' ">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<!-- Redefine build target as we don't want to build anything. -->
<Target Name="Build" />
<Target Name="Clean" />
<Target Name="Rebuild" />
<!-- Append the appx properties to the custom macros as we use this in the testmd.definition file. -->
<Target Name="AppendUniversalTestCustomMacros" BeforeTargets="BuildUniversalTest">
<ItemGroup>
<AppxBundleOutput Include="$(OutDir)..\Calculator\AppPackages\**\*.appxbundle" />
<AppxPackagePublicKeyFile Include="$(OutDir)..\Calculator\AppPackages\**\*.cer" />
</ItemGroup>
<PropertyGroup>
<AppxPackageTestDir>@(AppxBundleOutput->'%(RootDir)%(Directory)')</AppxPackageTestDir>
<UniversalTestCustomMacros Condition="'$(Configuration)'=='Debug'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.VCLibs.$(PlatformTarget).Debug.14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros Condition="'$(Configuration)'=='Release'">$(UniversalTestCustomMacros)AppxPackageVCLibsDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.VCLibs.$(PlatformTarget).14.00.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackageWinUIDependency=$(AppxPackageTestDir)Dependencies\$(PlatformTarget)\Microsoft.UI.Xaml.2.0.appx;</UniversalTestCustomMacros>
<UniversalTestCustomMacros>$(UniversalTestCustomMacros)AppxPackagePublicKeyFile=@(AppxPackagePublicKeyFile->'%(FullPath)');AppxBundleOutput=@(AppxBundleOutput->'%(FullPath)');</UniversalTestCustomMacros>
</PropertyGroup>
</Target>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) Microsoft Corporation. All rights reserved.-->
<identity
xmlns="urn:Microsoft.CompPlat/ManifestSchema.v1.00"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="App"
namespace="Calculator"
owner="Microsoft">
<files>
<file
source="$(AppxBundleOutput)"
destinationDir="$(runtime.testbin)"
name="Calculator.appxbundle" />
<file
source="$(AppxPackagePublicKeyFile)"
destinationDir="$(runtime.testbin)"
name="Calculator.cer" />
<file
source="$(AppxPackageVCLibsDependency)"
destinationDir="$(runtime.testbin)"
name="Microsoft.VCLibs.appx" />
<file
source="$(AppxPackageWinUIDependency)"
destinationDir="$(runtime.testbin)"
name="Microsoft.UI.Xaml.appx" />
</files>
</identity>

View File

@@ -0,0 +1,13 @@
{
"dependencies": {
"Microsoft.TestInfrastructure.UniversalTest": "1.0.20181107.1"
},
"frameworks": {
"netcore50": {}
},
"runtimes": {
"win10-arm": {},
"win10-x64": {},
"win10-x86": {}
}
}

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A43517B5-8BE3-4312-913F-004978C34444}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Calculator.UIAutomationLibrary</RootNamespace>
<AssemblyName>Calculator.UIAutomationLibrary</AssemblyName>
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<NuGetTargetMoniker>.NETCore,Version=v5.0</NuGetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17763.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<FileAlignment>512</FileAlignment>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="CalculatorAppLauncher.cs" />
<Compile Include="Components\App\CalculatorAppLfm.cs" />
<Compile Include="Components\App\CalculatorAppPom.cs" />
<Compile Include="Components\ContentDialogLfm.cs" />
<Compile Include="Components\Pages\CalculatorBasePom.cs" />
<Compile Include="Components\Pages\AboutFlyoutLfm.cs" />
<Compile Include="Components\Pages\AboutFlyoutPom.cs" />
<Compile Include="Components\Pages\DateCalculatorLfm.cs" />
<Compile Include="Components\Pages\DateCalculatorPom.cs" />
<Compile Include="Components\Pages\UnitConverterLfm.cs" />
<Compile Include="Components\Pages\UnitConverterPom.cs" />
<Compile Include="Components\Shared\HistoryLfm.cs" />
<Compile Include="Components\Shared\HistoryPom.cs" />
<Compile Include="Components\Shared\ICanFocusWithClicks.cs" />
<Compile Include="Components\Shared\MemoryLfm.cs" />
<Compile Include="Components\Shared\MemoryPom.cs" />
<Compile Include="Components\Pages\NavBarLfm.cs" />
<Compile Include="Components\Pages\NavBarPom.cs" />
<Compile Include="Components\Shared\NumberPadPom.cs" />
<Compile Include="Components\Pages\ProgrammerCalculatorLfm.cs" />
<Compile Include="Components\Pages\ProgrammerCalculatorPom.cs" />
<Compile Include="Components\Pages\ScientificCalculatorLfm.cs" />
<Compile Include="Components\Pages\ScientificCalculatorPom.cs" />
<Compile Include="Components\Pages\StandardCalculatorLfm.cs" />
<Compile Include="Components\Pages\StandardCalculatorPom.cs" />
<Compile Include="Components\Pages\MainPageLfm.cs" />
<Compile Include="Components\Pages\MainPagePom.cs" />
<Compile Include="Utilities\Impersonator.cs" />
<Compile Include="Utilities\PerfTestConstants.cs" />
<Compile Include="Tests\BasicCalculationTest.cs" />
<Compile Include="Tests\ScientificCalculationTest.cs" />
<Compile Include="Utilities\EtwHelper.cs" />
<Compile Include="Utilities\InstallHelper.cs" />
<Compile Include="Components\ContentDialogPom.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utilities\Constants.cs" />
<Compile Include="Utilities\NativeMethods.cs" />
<Compile Include="Utilities\ServiceHelper.cs" />
<Compile Include="Utilities\UIObjectExtensions.cs" />
<Compile Include="Utilities\Utilities.cs" />
<Compile Include="Utilities\WindowHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<ItemGroup />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0' ">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!--additional imports-->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Etw.Managed;
using Microsoft.OneCoreUap.Test.AppModel;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Calculator.UIAutomationLibrary.Components;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary
{
/// <summary>
/// Class that can open and close the Calculator app.
/// </summary>
public static class CalculatorAppLauncher
{
public const string CoreWindowClassName = "Windows.UI.Core.CoreWindow";
// This doesn't actually work right now becaue popup will disappear
// Bug 13713223: ContentDialog/Popup does not show up in the UIA tree when Windows.Current.Content has an AutomationName set.
// public static readonly UICondition TopLevelWindowUICondition = UICondition.CreateFromId(Constants.TopLevelWindowAutomationId);
public static readonly UICondition CoreWindowUICondition = UICondition.CreateFromClassName(CoreWindowClassName)
.AndWith(UICondition.CreateFromName(Constants.AppWindowName));
/// <summary>
/// Launch the app
/// </summary>
public static CalculatorAppLfm Launch()
{
Log.Comment("Launching Calculator and waiting for first page load...");
// Need to set this for the MITALite Tap~ methods to work on high DPI screens.
UAPApp.SetTestDPIAwareness();
// We want to be able to see any element in the tree
Context.RawContext.Activate();
// Set default wait timeout.
MS.Internal.Mita.Foundation.Waiters.Waiter.DefaultTimeout = TimeSpan.FromSeconds(30);
// Enable Mita internal logging.
MS.Internal.Mita.Foundation.Utilities.Log.OutImplementation = (s, a) => { Log.Comment($"- [MitaLite] { string.Format(s, a) }"); };
using (EtwWaiter appLaunchWaiter = new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.AppLaunchEndETWEventName))
{
var viewDescriptor = NavigationHelper.LaunchApplication(Constants.PackageAppUserModelId);
appLaunchWaiter.Wait(TimeSpan.FromSeconds(30));
Window calculatorWindow = new Window(UIObject.Root.Descendants.Find(CoreWindowUICondition));
Debug.Assert(calculatorWindow.ClassName == CoreWindowClassName);
// Move our window to the foreground.
WindowHelper.SetAsForeground(calculatorWindow.GetTopLevelWindow());
return new CalculatorAppLfm(new CalculatorAppPom(calculatorWindow), viewDescriptor);
}
}
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.OneCoreUap.Test.AppModel;
using MS.Internal.Mita.Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary.Components
{
public class CalculatorAppLfm
{
private readonly IViewDescriptor viewDescriptor;
public CalculatorAppLfm(CalculatorAppPom objectModel, IViewDescriptor viewDescriptor)
{
this.ObjectModel = objectModel;
this.viewDescriptor = viewDescriptor;
}
public CalculatorAppPom ObjectModel { get; }
public MainPageLfm MainPageLfm
{
get
{
return new MainPageLfm(this.ObjectModel.MainPagePom);
}
}
public void Close()
{
// ObjectModel is essentially the window ui object.
if (this.viewDescriptor != null)
{
NavigationHelper.CloseApplication(this.viewDescriptor.AUMID);
}
}
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary.Components
{
public class CalculatorAppPom : UIObject
{
/// <summary>
/// Creates a new instance of the <see cref="CalculatorAppPom"/> class.
/// </summary>
/// <param name="uiObject">UIObject for the calculator app window.</param>
public CalculatorAppPom(UIObject uiObject)
: base(uiObject)
{
}
public MainPagePom MainPagePom
{
get
{
return new MainPagePom(this);
}
}
}
}

View File

@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary.Components
{
public class ContentDialogLfm
{
public ContentDialogLfm(ContentDialogPom objectModel)
{
this.ObjectModel = objectModel;
}
public ContentDialogPom ObjectModel { get; }
public void InvokePrimary()
{
this.ObjectModel.PrimaryButton.Invoke();
}
public void InvokeSecondary()
{
this.ObjectModel.SecondaryButton.Invoke();
}
public void InvokeClose()
{
this.ObjectModel.CloseButton.Invoke();
}
}
}

View File

@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class ContentDialogPom : UIObject
{
private static readonly UICondition textScrollViewerCondition = UICondition.CreateFromId("ContentScrollViewer");
private static readonly UICondition titleTextBlockCondition = UICondition.CreateFromClassName("TextBlock");
private static readonly UICondition primaryButtonCondition =
UICondition.CreateFromClassName("Button")
.AndWith(UICondition.CreateFromId("PrimaryButton"));
private static readonly UICondition secondaryButtonCondition =
UICondition.CreateFromClassName("Button")
.AndWith(UICondition.CreateFromId("SecondaryButton"));
private static readonly UICondition closeButtonCondition =
UICondition.CreateFromClassName("Button")
.AndWith(UICondition.CreateFromId("CloseButton"));
public ContentDialogPom(UIObject uiObject) : base(uiObject)
{
}
public Button PrimaryButton
{
get
{
return new Button(this.Children.Find(primaryButtonCondition));
}
}
public Button SecondaryButton
{
get
{
return new Button(this.Children.Find(secondaryButtonCondition));
}
}
public Button CloseButton
{
get
{
return new Button(this.Children.Find(closeButtonCondition));
}
}
public string Title
{
get
{
var scrollViewer = this.Children.Find(textScrollViewerCondition);
var textBlock = scrollViewer.Children.Find(titleTextBlockCondition);
return textBlock.Name;
}
}
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Calculator.UIAutomationLibrary.Components
{
public class AboutFlyoutLfm : ICanFocusWithClicks
{
private const string FlyoutId = "FlyoutNav";
/// <summary>
/// Initializes a new instance of the <see cref="AboutFlyoutLfm" /> class.
/// </summary>
/// <param name="objectModel">The AboutFlyoutPom that represents the About flyout panel.</param>
public AboutFlyoutLfm(AboutFlyoutPom objectModel)
{
this.ObjectModel = objectModel;
}
public AboutFlyoutPom ObjectModel { get; }
public void FocusWithClicks()
{
this.ObjectModel.Title.DoubleClick();
}
public void Close()
{
this.ObjectModel.SendKeys("{ESC}");
}
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class AboutFlyoutPom : UIObject
{
private const string TitleId = "Header";
/// <summary>
/// Initializes a new instance of the <see cref="AboutFlyoutPom" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the navigation menu.</param>
public AboutFlyoutPom(UIObject uiObject) : base(uiObject)
{
}
public UIObject Title
{
get
{
return new UIObject(this.Descendants.Find(TitleId));
}
}
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the Display section of the calculator modes.
/// </summary>
public class CalculatorBasePom : UIObject
{
private const string ExpressionContainerId = "CalculatorExpression";
private const string NormalOutputId = "normalOutput";
/// <summary>
/// Initializes a new instance of the <see cref="StandardCalculatorPom" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the standard calculator.</param>
public CalculatorBasePom(UIObject uiObject) : base(uiObject)
{
}
public TextBlock Expression
{
get
{
return new TextBlock(this.Descendants.Find(ExpressionContainerId));
}
}
public UIEventWaiter GetExpressionChangedWaiter()
{
return new PropertyChangedEventWaiter(this.Expression, UIProperty.Get("Name"));
}
public TextBlock Display
{
get
{
return new TextBlock(this.Descendants.Find(NormalOutputId));
}
}
public UIEventWaiter GetDisplayChangedWaiter()
{
return new PropertyChangedEventWaiter(this.Display, UIProperty.Get("Name"));
}
}
}

View File

@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Calculator.UIAutomationLibrary.Components
{
public class DateCalculatorLfm
{
public DateCalculatorLfm(DateCalculatorPom dateCalculatorPom)
{
this.ObjectModel = dateCalculatorPom;
}
public DateCalculatorPom ObjectModel { get; }
public void EnsureDateDifferenceMode()
{
this.OpenModeSelector();
this.ObjectModel.ModeSelector.AllItems[0].Select();
}
public void EnsureAddSubtractMode()
{
this.OpenModeSelector();
this.ObjectModel.ModeSelector.AllItems[1].Select();
}
private void OpenModeSelector()
{
using (var waiter = this.ObjectModel.ModeSelector.GetExpandedWaiter())
{
this.ObjectModel.ModeSelector.Expand();
waiter.TryWait();
}
}
}
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class DateCalculatorPom : UIObject
{
private const string ModeSelectorId = "DateCalculationOption";
public DateCalculatorPom(UIObject uiObject) : base(uiObject)
{
}
public ComboBox ModeSelector
{
get
{
return new ComboBox(this.Descendants.Find(ModeSelectorId));
}
}
}
}

View File

@@ -0,0 +1,255 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Etw.Managed;
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
public class MainPageLfm : ICanFocusWithClicks
{
public MainPageLfm(MainPagePom objectModel)
{
this.ObjectModel = objectModel;
}
public MainPagePom ObjectModel { get; }
public NavBarLfm OpenNavBar()
{
using (EtwWaiter waiter = this.ObjectModel.GetNavBarOpenedWaiter())
{
this.ObjectModel.NavButton.Invoke();
waiter.Wait();
}
return new NavBarLfm(this.ObjectModel.NavBarPom);
}
public void CloseNavBar()
{
this.ObjectModel.NavBarPom.CloseButton.Invoke();
}
public void FocusWithClicks()
{
this.ObjectModel.Header.DoubleClick();
}
public StandardCalculatorLfm NavigateToStandardCalculator()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectStandard();
waiter.TryWait();
}
return new StandardCalculatorLfm(this.ObjectModel.StandardCalculatorPom);
}
public ScientificCalculatorLfm NavigateToScientificCalculator()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectScientific();
waiter.TryWait();
}
return new ScientificCalculatorLfm(this.ObjectModel.ScientificCalculatorPom);
}
public ProgrammerCalculatorLfm NavigateToProgrammerCalculator()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectProgrammer();
waiter.TryWait();
}
return new ProgrammerCalculatorLfm(this.ObjectModel.ProgrammerCalculatorPom);
}
public DateCalculatorLfm NavigateToDateCalculator()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectDate();
waiter.TryWait();
}
return new DateCalculatorLfm(this.ObjectModel.DateCalculatorPom);
}
public UnitConverterLfm NavigateToCurrencyConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectCurrency();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToVolumeConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectVolume();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToLengthConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectLength();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToWeightConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectWeight();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToTemperatureConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectTemperature();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToEnergyConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectEnergy();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToAreaConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectArea();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToSpeedConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectSpeed();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToTimeConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectTime();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToPowerConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectPower();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToDataConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectData();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToPressureConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectPressure();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public UnitConverterLfm NavigateToAngleConverter()
{
var navBar = this.OpenNavBar();
using (var waiter = this.ObjectModel.GetModeChangedWaiter())
{
navBar.SelectAngle();
waiter.TryWait();
}
return new UnitConverterLfm(this.ObjectModel.UnitConverterPom);
}
public AboutFlyoutLfm OpenAboutFlyout()
{
var navBar = this.OpenNavBar();
using (EtwWaiter waiter = new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.AboutFlyoutOpenedETWEventName))
{
navBar.SelectAbout();
waiter.Wait();
}
return new AboutFlyoutLfm(this.ObjectModel.AboutFlyoutPom);
}
}
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Etw.Managed;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Physical Object Model for the app window.
/// POM is the implementation model of the app.
/// See following references to POM:
/// * https://blogs.msdn.microsoft.com/wltester/2011/11/14/object-model-design/
/// * https://blogs.msdn.microsoft.com/micahel/2005/06/03/how-do-i-invoke-thee-let-me-count-the-ways-the-physical-object-model/
/// See https://en.wikipedia.org/wiki/Model-based_testing for model-based testing.
/// </summary>
public class MainPagePom : UIObject
{
private const string NavButtonId = "TogglePaneButton";
private const string SplitViewPaneRootId = "PaneRoot";
private const string NavBarFlyoutId = "FlyoutNav";
private const string HeaderId = "Header";
private const string AboutPageFlyoutId = "AboutPageFlyout";
public MainPagePom(UIObject uiObject)
: base(uiObject)
{
}
public Button NavButton => new Button(this.Descendants.Find(UICondition.CreateFromId(NavButtonId)));
public UIObject Header => new UIObject(this.Descendants.Find(HeaderId));
public NavBarPom NavBarPom => new NavBarPom(this.Children.Find(SplitViewPaneRootId));
public EtwWaiter GetNavBarOpenedWaiter() => new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.NavBarOpenedETWEventName);
public StandardCalculatorPom StandardCalculatorPom => new StandardCalculatorPom(this);
public ScientificCalculatorPom ScientificCalculatorPom => new ScientificCalculatorPom(this);
public ProgrammerCalculatorPom ProgrammerCalculatorPom => new ProgrammerCalculatorPom(this);
public DateCalculatorPom DateCalculatorPom => new DateCalculatorPom(this);
public UnitConverterPom UnitConverterPom => new UnitConverterPom(this);
public AboutFlyoutPom AboutFlyoutPom => new AboutFlyoutPom(this.Descendants.Find(AboutPageFlyoutId));
public EtwWaiter GetModeChangedWaiter() => new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.AppModeChangeEndETWEventName);
}
}

View File

@@ -0,0 +1,144 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Windows.Automation;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Patterns;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the NavBar of the Calculator app.
/// </summary>
public class NavBarLfm : ICanFocusWithClicks
{
/// <summary>
/// Initializes a new instance of the <see cref="NavBarLfm" /> class.
/// </summary>
/// <param name="objectModel">The NavBarPom that represents the NavBar.</param>
public NavBarLfm(NavBarPom objectModel)
{
this.ObjectModel = objectModel;
}
public NavBarPom ObjectModel { get; }
public void SelectStandard()
{
SelectItem(this.ObjectModel.StandardMenuItem);
}
public void SelectScientific()
{
SelectItem(this.ObjectModel.ScientificMenuItem);
}
public void SelectProgrammer()
{
SelectItem(this.ObjectModel.ProgrammerMenuItem);
}
public void SelectDate()
{
SelectItem(this.ObjectModel.DateMenuItem);
}
public void SelectCurrency()
{
SelectItem(this.ObjectModel.CurrencyMenuItem);
}
public void SelectVolume()
{
SelectItem(this.ObjectModel.VolumeMenuItem);
}
public void SelectLength()
{
SelectItem(this.ObjectModel.LengthMenuItem);
}
public void SelectWeight()
{
SelectItem(this.ObjectModel.WeightMenuItem);
}
public void SelectTemperature()
{
SelectItem(this.ObjectModel.TemperatureMenuItem);
}
public void SelectEnergy()
{
SelectItem(this.ObjectModel.EnergyMenuItem);
}
public void SelectArea()
{
SelectItem(this.ObjectModel.AreaMenuItem);
}
public void SelectSpeed()
{
SelectItem(this.ObjectModel.SpeedMenuItem);
}
public void SelectTime()
{
SelectItem(this.ObjectModel.TimeMenuItem);
}
public void SelectPower()
{
SelectItem(this.ObjectModel.PowerMenuItem);
}
public void SelectData()
{
SelectItem(this.ObjectModel.DataMenuItem);
}
public void SelectPressure()
{
SelectItem(this.ObjectModel.PressureMenuItem);
}
public void SelectAngle()
{
SelectItem(this.ObjectModel.AngleMenuItem);
}
public void SelectAbout()
{
this.ObjectModel.AboutButton.Invoke();
}
public void Close()
{
this.ObjectModel.CloseButton.Invoke();
}
public void FocusWithClicks()
{
// To focus (for AccSpot) without changing anything, click to the right of the close button.
Button button = this.ObjectModel.CloseButton;
int xPos = button.BoundingRectangle.Width + Constants.ClickMargin;
int yPos = button.BoundingRectangle.Height / 2;
button.DoubleClick(PointerButtons.Primary, xPos, yPos);
}
private void SelectItem(ListViewItem item)
{
if (item.IsSelected)
{
this.Close();
}
else
{
item.Select();
}
}
}
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the navigation menu.
/// </summary>
public class NavBarPom : UIObject
{
private const string StandardId = "Standard";
private const string ScientificId = "Scientific";
private const string ProgrammerId = "Programmer";
private const string DateId = "Date";
private const string CurrencyId = "Currency";
private const string VolumeId = "Volume";
private const string LengthId = "Length";
private const string WeightId = "Weight";
private const string TemperatureId = "Temperature";
private const string EnergyId = "Energy";
private const string AreaId = "Area";
private const string SpeedId = "Speed";
private const string TimeId = "Time";
private const string PowerId = "Power";
private const string DataId = "Data";
private const string PressureId = "Pressure";
private const string AngleId = "Angle";
private const string AboutId = "AboutButton";
private const string CloseId = "TogglePaneButton";
private const string FlyoutListViewId = "MenuItemsHost";
private const string ConverterSectionId = "Converter";
private const string ConverterTextKey = "ConverterModeText";
/// <summary>
/// Initializes a new instance of the <see cref="NavBarPom" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the navigation menu.</param>
public NavBarPom(UIObject uiObject) : base(uiObject)
{
}
public ListViewItem StandardMenuItem => ScrollAndGetItem(StandardId);
public ListViewItem ScientificMenuItem => ScrollAndGetItem(ScientificId);
public ListViewItem ProgrammerMenuItem => ScrollAndGetItem(ProgrammerId);
public ListViewItem DateMenuItem => ScrollAndGetItem(DateId);
public ListViewItem CurrencyMenuItem => ScrollAndGetItem(CurrencyId);
public ListViewItem VolumeMenuItem => ScrollAndGetItem(VolumeId);
public ListViewItem LengthMenuItem => ScrollAndGetItem(LengthId);
public ListViewItem WeightMenuItem => ScrollAndGetItem(WeightId);
public ListViewItem TemperatureMenuItem => ScrollAndGetItem(TemperatureId);
public ListViewItem EnergyMenuItem => ScrollAndGetItem(EnergyId);
public ListViewItem AreaMenuItem => ScrollAndGetItem(AreaId);
public ListViewItem SpeedMenuItem => ScrollAndGetItem(SpeedId);
public ListViewItem TimeMenuItem => ScrollAndGetItem(TimeId);
public ListViewItem PowerMenuItem => ScrollAndGetItem(PowerId);
public ListViewItem DataMenuItem => ScrollAndGetItem(DataId);
public ListViewItem PressureMenuItem => ScrollAndGetItem(PressureId);
public ListViewItem AngleMenuItem => ScrollAndGetItem(AngleId);
public Button AboutButton => new Button(this.Descendants.Find(AboutId));
public Button CloseButton => new Button(this.Parent.Children.Find(CloseId));
public ListView ModeListView => new ListView(this.Descendants.Find(FlyoutListViewId));
private ListViewItem ScrollAndGetItem(string id)
{
ListViewItem item;
var res = this.ModeListView.AllItems.TryFind(id, out item);
item.ScrollIntoView();
return item;
}
}
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
public class ProgrammerCalculatorLfm
{
public ProgrammerCalculatorLfm(ProgrammerCalculatorPom programmerCalculatorPom)
{
this.ObjectModel = programmerCalculatorPom;
}
public ProgrammerCalculatorPom ObjectModel { get; }
public void EnsureFullKeypad()
{
if (!this.ObjectModel.FullKeypadButton.IsSelected)
{
this.ObjectModel.FullKeypadButton.Select();
}
}
public void EnsureBitTogglingKeypad()
{
if (!this.ObjectModel.BitFlipKeypadButton.IsSelected)
{
this.ObjectModel.BitFlipKeypadButton.Select();
}
}
public void ChangeBitLength()
{
this.ObjectModel.GetCurrentBitLengthButton().Invoke();
}
public MemoryLfm OpenMemory()
{
MemoryLfm lfm = new MemoryLfm(this.ObjectModel.MemoryControls);
lfm.OpenBody();
return lfm;
}
public void FiveMemorySet()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
this.ObjectModel.NumberPad.FiveButton.Invoke();
waiter.TryWait();
}
this.ObjectModel.MemoryControls.SetButton.Invoke();
}
}
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
public class ProgrammerCalculatorPom : UIObject
{
private const string FullKeypadButtonId = "fullKeypad";
private const string BitFlipKeypadButtonId = "bitFlip";
private const string CalculatorResultsId = "CalculatorResults";
private const string NumberPadId = "NumberPad";
private readonly string[] BitLengthButtonIds =
{
"qwordButton",
"dwordButton",
"wordButton",
"byteButton"
};
public ProgrammerCalculatorPom(UIObject uiObject) : base(uiObject)
{
}
public NumberPadPom NumberPad => new NumberPadPom(this.Descendants.Find(NumberPadId));
public MemoryPom MemoryControls => new MemoryPom(this);
public RadioButton FullKeypadButton => new RadioButton(this.Descendants.Find(FullKeypadButtonId));
public RadioButton BitFlipKeypadButton => new RadioButton(this.Descendants.Find(BitFlipKeypadButtonId));
public TextBlock Display => new TextBlock(this.Descendants.Find(CalculatorResultsId));
public UIEventWaiter GetDisplayChangedWaiter() => this.Display.GetNameChangedWaiter();
public Button GetCurrentBitLengthButton()
{
// There are four bit length buttons, with only one visible at a time.
UIObject button = null;
foreach (var buttonId in this.BitLengthButtonIds)
{
if (this.Descendants.TryFind(buttonId, out button))
{
break;
}
}
return new Button(button);
}
}
}

View File

@@ -0,0 +1,138 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation.Waiters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the Standard calculator view.
/// </summary>
public class ScientificCalculatorLfm
{
/// <summary>
/// Initializes a new instance of the <see cref="ScientificCalculatorLfm" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the scientific Calculator.</param>
public ScientificCalculatorLfm(ScientificCalculatorPom objectModel)
{
this.ObjectModel = objectModel;
}
public ScientificCalculatorPom ObjectModel { get; }
public void Press1()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking 1");
this.ObjectModel.OneButton.Invoke();
waiter.TryWait();
}
}
public void Press2()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking 2");
this.ObjectModel.NumberPad.TwoButton.Invoke();
waiter.TryWait();
}
}
public void Press3()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking 3");
this.ObjectModel.ThreeButton.Invoke();
waiter.TryWait();
}
}
public void Press4()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking 4");
this.ObjectModel.FourButton.Invoke();
waiter.TryWait();
}
}
public void PressSqrt()
{
// When invoking sqrt, both the expression changes.
using (UIEventWaiter waiter = this.ObjectModel.GetExpressionChangedWaiter())
{
Log.Comment("Invoking sqrt");
this.ObjectModel.SqrtButton.Invoke();
waiter.TryWait();
}
}
public void PressMinus()
{
using (UIEventWaiter waiter = this.ObjectModel.GetExpressionChangedWaiter())
{
Log.Comment("Invoking minus");
this.ObjectModel.MinusButton.Invoke();
waiter.TryWait();
}
}
public void PressPlus()
{
using (UIEventWaiter waiter = this.ObjectModel.GetExpressionChangedWaiter())
{
Log.Comment("Invoking plus");
this.ObjectModel.PlusButton.Invoke();
waiter.TryWait();
}
}
public void PressEquals()
{
// When invoking equals, both the display and the expression change.
using (UIEventWaiter expressionWaiter = this.ObjectModel.GetExpressionChangedWaiter())
using (UIEventWaiter displayWaiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking equals");
this.ObjectModel.EqualButton.Invoke();
expressionWaiter.TryWait();
displayWaiter.TryWait();
}
}
public void OnePlusTwoEnter()
{
Press1();
PressPlus();
Press2();
PressEquals();
}
public void MemorySet() => this.ObjectModel.MemoryControls.SetButton.Invoke();
public MemoryLfm OpenMemory()
{
MemoryLfm lfm = new MemoryLfm(this.ObjectModel.MemoryControls);
lfm.OpenBody();
return lfm;
}
public HistoryLfm OpenHistory()
{
HistoryLfm lfm = new HistoryLfm(this.ObjectModel.HistoryControls);
lfm.OpenBody();
return lfm;
}
}
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the Scientific Calculator
/// </summary>
public class ScientificCalculatorPom : CalculatorBasePom
{
private const string NumberPadId = "NumberPad";
private const string StandardOperatorsId = "StandardOperators";
private const string DisplayControlsId = "DisplayControls";
private const string ScientificFunctionsId = "ScientificFunctions";
private const string OneButtonId = "num1Button";
private const string ThreeButtonId = "num3Button";
private const string FourButtonId = "num4Button";
private const string SqrtButtonId = "squareRootButton";
private const string MinusButtonId = "minusButton";
private const string PlusButtonId = "plusButton";
private const string EqualButtonId = "equalButton";
private const string ClearButtonId = "clearButton";
/// <summary>
/// Initializes a new instance of the <see cref="ScientificCalculatorPom" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the scientific calculator.</param>
public ScientificCalculatorPom(UIObject uiObject) : base(uiObject)
{
}
public UIObject StandardOperatorsGroup => this.Descendants.Find(StandardOperatorsId);
public UIObject DisplayControlsGroup => this.Descendants.Find(DisplayControlsId);
public UIObject ScientificFunctionsGroup => this.Descendants.Find(ScientificFunctionsId);
public Button OneButton => this.NumberPad.OneButton;
public Button ThreeButton => this.NumberPad.ThreeButton;
public Button FourButton => this.NumberPad.FourButton;
public Button SqrtButton => new Button(this.ScientificFunctionsGroup.Children.Find(SqrtButtonId));
public Button MinusButton => new Button(this.StandardOperatorsGroup.Children.Find(MinusButtonId));
public Button PlusButton => new Button(this.StandardOperatorsGroup.Children.Find(PlusButtonId));
public Button EqualButton => new Button(this.StandardOperatorsGroup.Children.Find(EqualButtonId));
public Button ClearButton => new Button(this.DisplayControlsGroup.Children.Find(ClearButtonId));
public NumberPadPom NumberPad => new NumberPadPom(this.Descendants.Find(NumberPadId));
public HistoryPom HistoryControls => new HistoryPom(this);
public MemoryPom MemoryControls => new MemoryPom(this);
}
}

View File

@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation.Waiters;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the Standard calculator view.
/// </summary>
public class StandardCalculatorLfm
{
/// <summary>
/// Initializes a new instance of the <see cref="StandardCalculatorLfm" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the Standard Calculator.</param>
public StandardCalculatorLfm(StandardCalculatorPom objectModel)
{
this.ObjectModel = objectModel;
}
public StandardCalculatorPom ObjectModel { get; }
public void OnePlusTwoEnter()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking 1");
this.ObjectModel.NumPad.OneButton.Invoke();
waiter.TryWait();
}
using (UIEventWaiter waiter = this.ObjectModel.GetExpressionChangedWaiter())
{
Log.Comment("Pressing +");
this.ObjectModel.SendKeys("{ADD}");
// PropertyChangeWaiter is unreliable for the first name changed notification
// Bug 17624996: PropertyChanged event not fired when Name is updated for the first time for a control with custom automation peer.
waiter.TryWait();
}
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Pressing 2");
this.ObjectModel.SendKeys("2");
waiter.TryWait();
}
// When pressing enter, both the display and the expression change.
using (UIEventWaiter expressionWaiter = this.ObjectModel.GetExpressionChangedWaiter())
using (UIEventWaiter displayWaiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Invoking equals");
this.ObjectModel.EqualButton.Invoke();
expressionWaiter.TryWait();
displayWaiter.TryWait();
}
}
public void Clear()
{
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
Log.Comment("Pressing escape");
this.ObjectModel.ClearButton.Invoke();
waiter.TryWait();
}
}
public void ClearFiveMemorySet()
{
this.Clear();
using (UIEventWaiter waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
this.ObjectModel.NumPad.FiveButton.Invoke();
waiter.TryWait();
}
this.ObjectModel.MemoryControls.SetButton.Invoke();
}
public MemoryLfm OpenMemory()
{
MemoryLfm lfm = new MemoryLfm(this.ObjectModel.MemoryControls);
lfm.OpenBody();
return lfm;
}
public HistoryLfm OpenHistory()
{
HistoryLfm lfm = new HistoryLfm(this.ObjectModel.HistoryControls);
lfm.OpenBody();
return lfm;
}
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
/// <summary>
/// Represents the Standard Calculator
/// </summary>
public class StandardCalculatorPom : CalculatorBasePom
{
private const string CalculatorResultsId = "CalculatorResults";
private const string ExpressionContainerId = "CalculatorExpression";
private const string NumberPadId = "NumberPad";
private const string StandardOperatorsId = "StandardOperators";
private const string DisplayControlsId = "DisplayControls";
private const string EqualButtonId = "equalButton";
private const string ClearButtonId = "clearButton";
/// <summary>
/// Initializes a new instance of the <see cref="StandardCalculatorPom" /> class.
/// </summary>
/// <param name="uiObject">The UIObject that is the root of the standard calculator.</param>
public StandardCalculatorPom(UIObject uiObject) : base(uiObject)
{
}
public NumberPadPom NumPad => new NumberPadPom(this.Descendants.Find(NumberPadId));
public MemoryPom MemoryControls => new MemoryPom(this);
public HistoryPom HistoryControls => new HistoryPom(this);
public UIObject StandardOperatorsGroup => this.Descendants.Find(StandardOperatorsId);
public UIObject DisplayControlsGroup => this.Descendants.Find(DisplayControlsId);
public Button EqualButton => new Button(this.StandardOperatorsGroup.Children.Find(EqualButtonId));
public Button ClearButton => new Button(this.DisplayControlsGroup.Children.Find(ClearButtonId));
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Calculator.UIAutomationLibrary.Components
{
public class UnitConverterLfm
{
public UnitConverterLfm(UnitConverterPom unitConverterPom)
{
this.ObjectModel = unitConverterPom;
}
public UnitConverterPom ObjectModel { get; }
public void Eight()
{
using (var waiter = this.ObjectModel.GetDisplayChangedWaiter())
{
this.ObjectModel.NumberPad.EightButton.Invoke();
waiter.TryWait();
}
}
}
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
namespace Calculator.UIAutomationLibrary.Components
{
public class UnitConverterPom : UIObject
{
private const string DisplayId = "Value1";
private const string NumberPadId = "numberPad";
public UnitConverterPom(UIObject uiObject) : base(uiObject)
{
}
public NumberPadPom NumberPad => new NumberPadPom(this.Descendants.Find(NumberPadId));
public TextBlock Display => new TextBlock(this.Descendants.Find(DisplayId));
public PropertyChangedEventWaiter GetDisplayChangedWaiter() => this.Display.GetNameChangedWaiter();
public ElementAddedWaiter GetDisplayElementAddedWaiter() => new ElementAddedWaiter(this, Scope.Descendants, DisplayId);
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Etw.Managed;
using MS.Internal.Mita.Foundation;
namespace Calculator.UIAutomationLibrary.Components
{
public class HistoryLfm : ICanFocusWithClicks
{
public HistoryLfm(HistoryPom historyPom)
{
this.ObjectModel = historyPom;
}
public HistoryPom ObjectModel { get; }
public void FocusWithClicks()
{
// On the Programming calc, the default click location can land on the first memory item, dismissing the flyout.
// Instead, click just below, in the gutter to the left of the trash can.
var body = this.ObjectModel.Body;
int height = body.BoundingRectangle.Height;
body.DoubleClick(PointerButtons.Primary, Constants.ClickMargin, height + Constants.ClickMargin);
}
public void OpenBody()
{
using (EtwWaiter waiter = new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.HistoryBodyOpenedETWEventName))
{
// Only one exists at a given time.
if (this.ObjectModel.IsHistoryButtonVisible)
{
if (!this.ObjectModel.IsBodyOpen)
{
this.ObjectModel.HistoryButton.Invoke();
waiter.Wait();
}
}
else if (!this.ObjectModel.HistoryPivot.IsSelected)
{
this.ObjectModel.HistoryPivot.Click();
waiter.Wait();
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class HistoryPom : UIObject
{
private const string HistoryButtonId = "HistoryButton";
private const string HistoryPivotId = "HistoryLabel";
private const string BodyId = "HistoryListView";
public HistoryPom(UIObject uiObject) : base(uiObject)
{
}
public Button HistoryButton => new Button(this.Descendants.Find(HistoryButtonId));
public bool IsHistoryButtonVisible => this.DoesDescendantExist(HistoryButtonId);
public TabItem HistoryPivot => new TabItem(this.Descendants.Find(HistoryPivotId));
public UIObject Body => this.Descendants.Find(BodyId);
public bool IsBodyOpen => this.DoesDescendantExist(BodyId);
}
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Calculator.UIAutomationLibrary.Components
{
public interface ICanFocusWithClicks
{
/// <summary>
/// Sets focus on an object by clicking on it, without causing further action.
/// Supports AccSpot scans by raising click events.
/// </summary>
void FocusWithClicks();
}
}

View File

@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Etw.Managed;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Waiters;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary.Components
{
public class MemoryLfm : ICanFocusWithClicks
{
public MemoryLfm(MemoryPom memoryPom)
{
this.ObjectModel = memoryPom;
}
public MemoryPom ObjectModel { get; }
public void FocusWithClicks()
{
// On the Programming calc, the default click location can land on the first memory item, dismissing the flyout.
// Instead, click just below, in the gutter to the left of the trash can.
var body = this.ObjectModel.Body;
int height = body.BoundingRectangle.Height;
body.DoubleClick(PointerButtons.Primary, Constants.ClickMargin, height + Constants.ClickMargin);
}
public void OpenBody()
{
using (EtwWaiter waiter = new EtwWaiter(Constants.CalculatorETWProviderGUID, Constants.MemoryBodyOpenedETWEventName))
{
// Only one exists at a given time
if (this.ObjectModel.IsMemoryButtonVisible)
{
if (!this.ObjectModel.IsBodyOpen)
{
this.ObjectModel.MemoryButton.Invoke();
waiter.Wait();
}
}
else if (!this.ObjectModel.MemoryPivot.IsSelected)
{
this.ObjectModel.MemoryPivot.Click();
waiter.Wait();
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class MemoryPom : UIObject
{
private const string ClearMemoryButtonId = "ClearMemoryButton";
private const string RecallButtonId = "MemRecall";
private const string PlusButtonId = "MemPlus";
private const string MinusButtonId = "MemMinus";
private const string SetButtonId = "memButton";
private const string MemoryButtonId = "MemoryButton";
private const string MemoryPivotId = "MemoryLabel";
private const string BodyId = "MemoryListView";
public MemoryPom(UIObject uiObject) : base(uiObject)
{
}
public Button ClearButton => new Button(this.Descendants.Find(ClearMemoryButtonId));
public Button RecallButton => new Button(this.Descendants.Find(RecallButtonId));
public Button PlusButton => new Button(this.Descendants.Find(PlusButtonId));
public Button MinusButton => new Button(this.Descendants.Find(MinusButtonId));
public Button SetButton => new Button(this.Descendants.Find(SetButtonId));
public Button MemoryButton => new Button(this.Descendants.Find(MemoryButtonId));
public bool IsMemoryButtonVisible => this.DoesDescendantExist(MemoryButtonId);
public TabItem MemoryPivot => new TabItem(this.Descendants.Find(MemoryPivotId));
public UIObject Body => this.Descendants.Find(BodyId);
public bool IsBodyOpen => this.DoesDescendantExist(BodyId);
}
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
namespace Calculator.UIAutomationLibrary.Components
{
public class NumberPadPom : UIObject
{
private const string OneButtonId = "num1Button";
private const string TwoButtonId = "num2Button";
private const string ThreeButtonId = "num3Button";
private const string FourButtonId = "num4Button";
private const string FiveButtonId = "num5Button";
private const string SixButtonId = "num6Button";
private const string SevenButtonId = "num7Button";
private const string EightButtonId = "num8Button";
private const string NineButtonId = "num9Button";
private const string ZeroButtonId = "num0Button";
private const string DecimalButtonId = "decimalSeparatorButton";
public NumberPadPom(UIObject uiObject) : base(uiObject)
{
}
public Button ZeroButton => new Button(this.Children.Find(ZeroButtonId));
public Button OneButton => new Button(this.Children.Find(OneButtonId));
public Button TwoButton => new Button(this.Children.Find(TwoButtonId));
public Button ThreeButton => new Button(this.Children.Find(ThreeButtonId));
public Button FourButton => new Button(this.Children.Find(FourButtonId));
public Button FiveButton => new Button(this.Children.Find(FiveButtonId));
public Button SixButton => new Button(this.Children.Find(SixButtonId));
public Button SevenButton => new Button(this.Children.Find(SevenButtonId));
public Button EightButton => new Button(this.Children.Find(EightButtonId));
public Button NineButton => new Button(this.Children.Find(NineButtonId));
public Button DecimalButton => new Button(this.Children.Find(DecimalButtonId));
}
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Calculator.UIAutomationLibrary")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("D6913DAD-1C3B-4229-915F-8301A57970FC")]

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Etw.Managed;
using Calculator.UIAutomationLibrary.Components;
using WEX.TestExecution;
namespace Calculator.UIAutomationLibrary.Tests
{
public static class BasicCalculationTest
{
/// <summary>
/// This test uses LFMs to add and then delete an alarm.
/// </summary>
/// <param name="calculatorAppLfm">The LFM for the alarms app window.</param>
public static void CalculateOnePlusTwo(this CalculatorAppLfm calculatorAppLfm)
{
var mainPage = calculatorAppLfm.MainPageLfm;
var standardCalculator = mainPage.NavigateToStandardCalculator();
standardCalculator.OnePlusTwoEnter();
Verify.AreEqual("\u202D3\u202C", standardCalculator.ObjectModel.Display.Name, "Ensure display value is 3");
standardCalculator.Clear();
Verify.AreEqual("\u202D0\u202C", standardCalculator.ObjectModel.Display.Name, "Ensure display value is 0");
}
}
}

View File

@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Calculator.UIAutomationLibrary.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WEX.TestExecution;
namespace Calculator.UIAutomationLibrary.Tests
{
public static class ScientificCalculationTest
{
/// <summary>
/// This test uses LFMs to calculate the sqrt(4) - 2.
/// </summary>
/// <param name="calculatorAppLfm">The LFM for the calculator app window.</param>
public static void CalculateSqrt4Minus2(this CalculatorAppLfm calculatorAppLfm)
{
var mainPage = calculatorAppLfm.MainPageLfm;
var scientificCalculator = mainPage.NavigateToScientificCalculator();
scientificCalculator.Press4();
scientificCalculator.PressSqrt();
scientificCalculator.PressMinus();
scientificCalculator.Press3();
scientificCalculator.PressPlus();
scientificCalculator.Press1();
scientificCalculator.PressEquals();
Verify.AreEqual("\u202D0\u202C", scientificCalculator.ObjectModel.Display.Name);
}
}
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace Calculator.UIAutomationLibrary
{
public class Constants
{
/// <summary>
/// The path to the certificate file.
/// </summary>
public const string CertificateFileName = @"Calculator.cer";
/// <summary>
/// The path to the appxbundle file.
/// </summary>
public const string PackageFileName = @"Calculator.appxbundle";
/// <summary>
/// The path to the appxbundle file.
/// </summary>
public const string VCLibsPackageFileName = @"Microsoft.VCLibs.appx";
/// <summary>
/// The path to the appxbundle file.
/// </summary>
public const string WinUIPackageFileName = @"Microsoft.UI.Xaml.appx";
/// <summary>
/// Name of the CoreWindow.
/// </summary>
public const string AppWindowName = "Calculator";
/// <summary>
/// Name of the process executable.
/// </summary>
public const string ProcessName = "Calculator.exe";
/// <summary>
/// The package name.
/// </summary>
public const string PackageName = "Microsoft.WindowsCalculator";
/// <summary>
/// The package family name for the app to test.
/// </summary>
public const string PackageFamilyName = PackageName + "_8wekyb3d8bbwe";
/// <summary>
/// The package App User Model Id.
/// </summary>
public const string PackageAppUserModelId = PackageFamilyName + "!App";
/// <summary>
/// AutomationId for the top level UI element.
/// </summary>
public const string TopLevelWindowAutomationId = "CalculatorWindow";
/// <summary>
/// Event fired when the first page is loaded.
/// </summary>
public const string AppLaunchEndETWEventName = "AppLaunchEnd";
/// <summary>
/// App Provider GUID for ETW Events
/// </summary>
public static readonly Guid CalculatorETWProviderGUID = new Guid("0905CA09-610E-401E-B650-2F212980B9E0");
/// <summary>
/// Event fired when a calculator mode change is complete.
/// </summary>
public const string AppModeChangeEndETWEventName = "ModeChangeEnd";
/// <summary>
/// Event fired when the History panel is opened by flyout or by changing pivot tabs.
/// </summary>
public const string HistoryBodyOpenedETWEventName = "HistoryBodyOpened";
/// <summary>
/// Event fired when the Memory panel is opened by flyout or by changing pivot tabs.
/// </summary>
public const string MemoryBodyOpenedETWEventName = "MemoryBodyOpened";
/// <summary>
/// Event fired when the About flyout control is loaded.
/// </summary>
public const string AboutFlyoutOpenedETWEventName = "AboutFlyoutOpened";
/// <summary>
/// Event fired when the Nav Bar control is opened.
/// </summary>
public const string NavBarOpenedETWEventName = "NavBarOpened";
/// <summary>
/// Margin used to click in the gutter beneath the History and Memory lists
/// </summary>
public const int ClickMargin = 10;
}
}

View File

@@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.OneCoreUap.Test.AppModel;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary
{
public class EtwHelper
{
private static bool etwServiceWasInstalled = false;
/// <summary>
/// Installs and starts the Etw.Service so that Tests may utilize Etw Waiters.
/// Wex.Services.exe is part of TAEF.
/// </summary>
public static void InstallAndStartETWService()
{
etwServiceWasInstalled = ServiceHelper.IsInstalled("Etw.Service");
if (!etwServiceWasInstalled)
{
string wexServices = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), "Wex.Services.exe");
if (!File.Exists(wexServices))
{
throw new FileNotFoundException(wexServices);
}
Log.Comment("Attempting to install Etw.Service...");
var startInfo = new ProcessStartInfo();
startInfo.FileName = wexServices;
startInfo.Arguments = "/install:Etw.Service";
var process = new Process();
process.StartInfo = startInfo;
if (process.Start())
{
process.WaitForExit();
Log.Comment("Completed installation of Etw.Service");
}
else
{
throw new Exception("ETW service was not able to be installed. Process didn't start.");
}
}
Log.Comment("Attempting to start Etw.Service...");
ServiceHelper.Start("Etw.Service");
Log.Comment("Etw.Service started");
}
/// <summary>
/// Stops the Etw.Service.
/// </summary>
public static void StopAndRemoveETWService()
{
if (ServiceHelper.IsInstalled("Etw.Service"))
{
Log.Comment("Attempting to stop Etw.Service...");
ServiceHelper.Stop("Etw.Service");
Log.Comment("Etw.Service stopped");
// if we installed the Etw.Service as part of this test we should also remove it.
// This prevents cases where TDP is upgraded but the service tregistration is referencing the old
// location that no longer exists.
if (!etwServiceWasInstalled)
{
string wexServices = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), "Wex.Services.exe");
if (!File.Exists(wexServices))
{
throw new FileNotFoundException(wexServices);
}
Log.Comment("Attempting to remove Etw.Service...");
var startInfo = new ProcessStartInfo();
startInfo.FileName = wexServices;
startInfo.Arguments = "/remove:Etw.Service";
var process = new Process();
process.StartInfo = startInfo;
if (process.Start())
{
process.WaitForExit();
Log.Comment("Completed removal of Etw.Service");
}
else
{
throw new Exception("ETW service could not be removed. Process didn't start.");
}
}
}
}
}
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary
{
public static class Impersonater
{
public static void RunAs(RunAsUser user, Action action)
{
IntPtr errorInfo;
SafeAccessTokenHandle restrictedToken;
GetRunAsUserToken getRunAsUserToken = ResolveGetRunAsUserTokenMethod();
Marshal.ThrowExceptionForHR(getRunAsUserToken(user, out restrictedToken, out errorInfo), errorInfo);
WindowsIdentity.RunImpersonated(restrictedToken, action);
}
public static void RunAs<T>(RunAsUser user, Func<T> function)
{
IntPtr errorInfo;
SafeAccessTokenHandle restrictedToken;
GetRunAsUserToken getRunAsUserToken = ResolveGetRunAsUserTokenMethod();
Marshal.ThrowExceptionForHR(getRunAsUserToken(user, out restrictedToken, out errorInfo), errorInfo);
WindowsIdentity.RunImpersonated(restrictedToken, function);
}
// From: https://microsoft.visualstudio.com/EngSys/_git/validation.taef?path=%2Fsrc%2FTAEF%2FCommon%2FPublished%2FRunAsFromSystem.h&version=GBdevelop
public enum RunAsUser
{
ElevatedUser,
User,
RestrictedUser,
LowIL,
InteractiveUser,
};
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int GetRunAsUserToken(RunAsUser user, out SafeAccessTokenHandle token, out IntPtr errorInfo);
// GetRunAsUserToken is defined in a namespace so we have to do some tricks to use P/Invoke.
// We got the actual exported method name by running dumpbin /exports TE.Common.dll
private static GetRunAsUserToken ResolveGetRunAsUserTokenMethod()
{
IntPtr teCommonDll = IntPtr.Zero;
try
{
teCommonDll = LoadLibrary(@"TE.Common.dll");
IntPtr x64GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PEAPEAXPEAPEAUIErrorInfo@@@Z");
if (x64GetRunAsUserToken != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(x64GetRunAsUserToken);
}
IntPtr x86GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YGJW4RunAsUser@12@PAPAXPAPAUIErrorInfo@@@Z");
if (x86GetRunAsUserToken != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(x86GetRunAsUserToken);
}
IntPtr armGetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PAPAXPAPAUIErrorInfo@@@Z");
if (armGetRunAsUserToken != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(armGetRunAsUserToken);
}
IntPtr arm64GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PEAPEAXPEAPEAUIErrorInfo@@@Z");
if (arm64GetRunAsUserToken != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(arm64GetRunAsUserToken);
}
throw new Exception("Unable to find the GetRunAsUserToken function in DLL 'TE.Common.dll'");
}
finally
{
if (teCommonDll != IntPtr.Zero)
{
FreeLibrary(teCommonDll);
}
}
}
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
}

View File

@@ -0,0 +1,84 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Microsoft.OneCoreUap.Test.AppModel;
using WEX.Logging.Interop;
using Windows.Foundation;
using Windows.Management.Deployment;
namespace Calculator.UIAutomationLibrary
{
public class InstallHelper
{
public static void InstallCertFile(string certFilePath)
{
// Ensure cert exists.
if (!File.Exists(certFilePath))
{
throw new FileNotFoundException(certFilePath);
}
// For some reason, attempting to use CertificateHelper.InstallFromSignedPackage() to install
// the certificate associated with the appx package fails with the error:
// "A certificate chain could not be built to a trusted root authority."
// The reason is that the cert needs to be installed in 'StoreName.TrustedPeople',
// but DeploymentHelper.AddPackage() attempts to install it in 'StoreName.Root'.
// Therefore, the cert has been installed manually beforehand.
Log.Comment($"Starting install of certificate at {certFilePath}");
X509Certificate2 certificate = new X509Certificate2(certFilePath);
X509Store trustedPeopleStore = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine);
trustedPeopleStore.Open(OpenFlags.MaxAllowed);
trustedPeopleStore.Add(certificate);
Log.Comment($"Completed install of certificate");
}
/// <summary>
/// Upgrades the appx/appxbundle from the path if needed.
/// </summary>
public static void InstallPackage(string appxFilePath, params string[] dependencyAppxFilePaths)
{
// Ensure the files exist.
if (!File.Exists(appxFilePath))
{
throw new FileNotFoundException(appxFilePath);
}
foreach (var path in dependencyAppxFilePaths.Where(p => !File.Exists(p)))
{
throw new FileNotFoundException(path);
}
Log.Comment($"Starting install of app package at {appxFilePath}");
PackageManager packageManager = new PackageManager();
var deploymentOperation = packageManager.AddPackageAsync(
new Uri(appxFilePath),
dependencyAppxFilePaths.Select(d => new Uri(d)),
DeploymentOptions.ForceApplicationShutdown | DeploymentOptions.ForceTargetApplicationShutdown | DeploymentOptions.ForceUpdateFromAnyVersion);
WaitForDeploymentOperation(deploymentOperation);
Log.Comment("Completed install of app package");
}
/// <summary>
/// Waits for a deployment operation to complete
/// </summary>
private static void WaitForDeploymentOperation(IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> operation)
{
ManualResetEvent isCompletedEvent = new ManualResetEvent(false);
operation.Completed = (IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> asyncInfo, AsyncStatus asyncStatus) =>
{
isCompletedEvent.Set();
};
isCompletedEvent.WaitOne();
}
}
}

View File

@@ -0,0 +1,139 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Calculator.UIAutomationLibrary
{
internal static class NativeMethods
{
internal const int GW_OWNER = 4;
internal delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);
[DllImport("api-ms-win-service-management-l1-1-0.dll")]
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
internal static extern bool QueryServiceStatus(IntPtr hService, ref SERVICE_STATUS dwServiceStatus);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SERVICE_STATUS
{
public int dwServiceType;
public int dwCurrentState;
public int dwControlsAccepted;
public int dwWin32ExitCode;
public int dwServiceSpecificExitCode;
public int dwCheckPoint;
public int dwWaitHint;
}
internal static uint STANDARD_RIGHTS_REQUIRED = 0xF0000;
internal static uint SC_MANAGER_CONNECT = 0x0001;
internal static uint SC_MANAGER_CREATE_SERVICE = 0x0002;
internal static uint SC_MANAGER_ENUMERATE_SERVICE = 0x0004;
internal static uint SC_MANAGER_LOCK = 0x0008;
internal static uint SC_MANAGER_QUERY_LOCK_STATUS = 0x0010;
internal static uint SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020;
internal static uint SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE |
SC_MANAGER_ENUMERATE_SERVICE |
SC_MANAGER_LOCK |
SC_MANAGER_QUERY_LOCK_STATUS |
SC_MANAGER_MODIFY_BOOT_CONFIG);
internal static uint SERVICE_QUERY_CONFIG = 0x0001;
internal static uint SERVICE_CHANGE_CONFIG = 0x0002;
internal static uint SERVICE_QUERY_STATUS = 0x0004;
internal static uint SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
internal static uint SERVICE_START = 0x0010;
internal static uint SERVICE_STOP = 0x0020;
internal static uint SERVICE_PAUSE_CONTINUE = 0x0040;
internal static uint SERVICE_INTERROGATE = 0x0080;
internal static uint SERVICE_USER_DEFINED_CONTROL = 0x0100;
internal static uint SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL);
[Flags]
internal enum SERVICE_CONTROL : uint
{
STOP = 0x00000001,
PAUSE = 0x00000002,
CONTINUE = 0x00000003,
INTERROGATE = 0x00000004,
SHUTDOWN = 0x00000005,
PARAMCHANGE = 0x00000006,
NETBINDADD = 0x00000007,
NETBINDREMOVE = 0x00000008,
NETBINDENABLE = 0x00000009,
NETBINDDISABLE = 0x0000000A,
DEVICEEVENT = 0x0000000B,
HARDWAREPROFILECHANGE = 0x0000000C,
POWEREVENT = 0x0000000D,
SESSIONCHANGE = 0x0000000E
}
internal enum SERVICE_STATE : int
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007
}
}
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace Calculator.UIAutomationLibrary
{
public class PerfConstants
{
/// <summary>
/// Path where the regions, wprprofiles and wpaprofiles will be deployed to by the spkg.
/// </summary>
public const string ConfigDirectory = @"Config\";
/// <summary>
/// Our FunGates source, where we can view test results.
/// </summary>
public const string FunGatesSource =
#if DEBUG
"TestSite";
#else
"Utility Apps Performance Tests";
#endif
/// <summary>
/// The Windows Performance Recorder profile. These strings must have the config directory prefix.
/// For use with the WPRProfileFile test attribute.
/// </summary>
public const string AppLifecycleWPRProfile = ConfigDirectory + "AppLifecycle.Profile.wprp";
/// <summary>
/// The regions of interest file that contains the events we are interested in measuring.
/// </summary>
public const string AppLifecycleRegions = ConfigDirectory + "AppLifecycle.regions.xml";
/// <summary>
/// These are uses with the DataSource test property to specify iteration info.
/// </summary>
public const string AppLifecycleInterationsSource = "Table:" + ConfigDirectory + "AppLifecycle.Iterations.xml#PerformanceConfigurations";
}
}

View File

@@ -0,0 +1,156 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Calculator.UIAutomationLibrary
{
public class ServiceHelper
{
public static void Start(string serviceName, int timeoutInMilliSeconds = 30000)
{
IntPtr hService = IntPtr.Zero;
IntPtr hSCManager = IntPtr.Zero;
try
{
hSCManager = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
if (IntPtr.Zero == hSCManager)
{
throw new Exception($"Start: Cannot Open OpenSCManager, {Marshal.GetLastWin32Error()}");
}
hService = NativeMethods.OpenService(hSCManager, serviceName, NativeMethods.SERVICE_ALL_ACCESS);
if (IntPtr.Zero == hService)
{
throw new Exception($"Start: Cannot Open Service, {Marshal.GetLastWin32Error()}");
}
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
{
throw new Exception($"Start: Unable to query status of Service, {Marshal.GetLastWin32Error()}");
}
if (serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_RUNNING &&
serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_START_PENDING)
{
if (!NativeMethods.StartService(hService, 0, null))
{
throw new Exception($"Start: Service cannot be started, {Marshal.GetLastWin32Error()}");
}
}
WaitForStatus(hService, NativeMethods.SERVICE_STATE.SERVICE_RUNNING, TimeSpan.FromMilliseconds(timeoutInMilliSeconds));
}
finally
{
if (IntPtr.Zero != hService)
{
NativeMethods.CloseServiceHandle(hService);
}
if (IntPtr.Zero != hSCManager)
{
NativeMethods.CloseServiceHandle(hSCManager);
}
}
}
public static void Stop(string serviceName, int timeoutInMilliSeconds = 30000)
{
IntPtr hSCManager = IntPtr.Zero;
IntPtr hService = IntPtr.Zero;
try
{
hSCManager = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
if (IntPtr.Zero == hSCManager)
{
throw new Exception($"Stop: Cannot Open OpenSCManager, {Marshal.GetLastWin32Error()}");
}
hService = NativeMethods.OpenService(hSCManager, serviceName, NativeMethods.SERVICE_ALL_ACCESS);
if (IntPtr.Zero == hService)
{
throw new Exception($"Stop: Cannot Open Service, {Marshal.GetLastWin32Error()}");
}
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
{
throw new Exception($"Stop: Unable to query status of Service, {Marshal.GetLastWin32Error()}");
}
if (serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_STOPPED &&
serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_STOP_PENDING)
{
if (!NativeMethods.ControlService(hService, NativeMethods.SERVICE_CONTROL.STOP, ref serviceStatus))
{
throw new Exception($"Stop: Service cannot be stopped, {Marshal.GetLastWin32Error()}");
}
}
WaitForStatus(hService, NativeMethods.SERVICE_STATE.SERVICE_STOPPED, TimeSpan.FromMilliseconds(timeoutInMilliSeconds));
}
finally
{
if (IntPtr.Zero != hService)
{
NativeMethods.CloseServiceHandle(hService);
}
if (IntPtr.Zero != hSCManager)
{
NativeMethods.CloseServiceHandle(hSCManager);
}
}
}
public static bool IsInstalled(string svcName)
{
IntPtr sc_handle = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
if (sc_handle == IntPtr.Zero)
{
throw new Exception($"IsInstalled: Cannot open service manager, {Marshal.GetLastWin32Error()}");
}
bool bResult = false;
IntPtr sv_handle = NativeMethods.OpenService(sc_handle, svcName, NativeMethods.SERVICE_QUERY_CONFIG);
if (sv_handle.ToInt64() != 0)
{
bResult = true;
NativeMethods.CloseServiceHandle(sv_handle);
}
NativeMethods.CloseServiceHandle(sc_handle);
return bResult;
}
private static void WaitForStatus(IntPtr hService, NativeMethods.SERVICE_STATE desiredStatus, TimeSpan timeout)
{
Stopwatch swLoop = new Stopwatch();
swLoop.Start();
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
do
{
Thread.Sleep(500);
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
{
throw new Exception($"WaitForStatus: Unable to query status of service, {Marshal.GetLastWin32Error()}");
}
}
while (serviceStatus.dwCurrentState != (int)desiredStatus && (swLoop.ElapsedMilliseconds <= timeout.TotalMilliseconds));
if (serviceStatus.dwCurrentState != (int)desiredStatus)
{
throw new Exception($"WaitForStatus: Service failed to reach desired state: {desiredStatus}, current state: {serviceStatus.dwCurrentState}");
}
}
}
}

View File

@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using System.Windows.Automation;
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary
{
public static class UIObjectExtensions
{
private const string NamePropertyName = "Name";
private static UICondition CoreWindowCondition = UICondition.CreateFromClassName("Windows.UI.Core.CoreWindow");
public static Window GetParentCoreWindow(this UIObject uiObject)
{
if (uiObject.Matches(CoreWindowCondition))
{
return new Window(uiObject);
}
return new Window(uiObject.Ancestors.Find(CoreWindowCondition));
}
public static Window GetTopLevelWindow(this Window window)
{
var node = window;
while (node != null && node.Parent != null && node.Parent.ControlType == ControlType.Window)
{
node = new Window(node.Parent);
}
return node;
}
public static void VerifyParentTreeStructure(this UIObject uiObject)
{
var node = uiObject;
while (node != null && node.Parent != null)
{
if (!node.Parent.Children.Contains(node))
{
Log.Comment($"- [VerifyingTree] {node} specifies {node.Parent} as parent but is not part of its children.");
}
if (!node.Parent.Descendants.Contains(node))
{
Log.Comment($"- [VerifyingTree] {node} specifies {node.Parent} as parent but is not part of its descendants.");
}
node = node.Parent;
}
}
public static bool DoesDescendantExist(this UIObject uiObject, string automationId)
{
UIObject temp;
return uiObject.Descendants.TryFind(automationId, out temp);
}
public static PropertyChangedEventWaiter GetNameChangedWaiter(this TextBlock textBlock)
{
return new PropertyChangedEventWaiter(textBlock, UIProperty.Get(NamePropertyName));
}
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
using System.IO;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary
{
public class Utilities
{
public static void KillExistingCalculatorProcesses()
{
Log.Comment("Killing any existing Calculator processes");
foreach (var process in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Constants.ProcessName)))
{
try
{
process.Kill();
Log.Comment($"Killed {process.ProcessName}, Id: {process.Id}");
}
catch (Exception) when (process.HasExited)
{
Log.Comment($"{process.ProcessName}, Id: {process.Id} already exited.");
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation.Controls;
using WEX.Logging.Interop;
namespace Calculator.UIAutomationLibrary
{
public class WindowHelper
{
public static void SetAsForeground(Window window)
{
Log.Comment($"Set window {window.NativeWindowHandle} as the foreground window.");
NativeMethods.SetForegroundWindow(window.NativeWindowHandle);
}
}
}

View File

@@ -0,0 +1,12 @@
{
"dependencies": {
"AppModel.TestHelper": "2018.3.22",
"EtwProcessor.Managed": "10.34.181220007",
"MITALite": "1.0.180128001",
"Taef.Managed": "10.34.181220007",
"Test.Net.Redist": "2.0.1"
},
"frameworks": {
"netcore50": {}
}
}

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{0224A709-0C48-4C4F-BA17-843A49842C15}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Calculator.UITests</RootNamespace>
<AssemblyName>Calculator.UITests</AssemblyName>
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<NuGetTargetMoniker>.NETCore,Version=v5.0</NuGetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17763.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<FileAlignment>512</FileAlignment>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\x86</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\x86</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\x64</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\x64</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\arm</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\arm</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\ARM64\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\ARM64\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Compile Include="Initialization.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tests\AppLifecycleTests.cs" />
<Compile Include="Tests\CalculatorTests.cs" />
<Compile Include="Tests\LaunchTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Config\AppLifecycle.Profile.wprp">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Config\AppLifecycle.Regions.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>AppLifecycle.Regions.xml</LastGenOutput>
<SubType>Designer</SubType>
</Content>
<Content Include="Config\AppLifecycle.Regions.xml">
<DependentUpon>AppLifecycle.Regions.tt</DependentUpon>
<AutoGen>True</AutoGen>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DesignTime>True</DesignTime>
</Content>
<None Include="project.json" />
<None Include="testmd.definition" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Calculator.UIAutomationLibrary\Calculator.UIAutomationLibrary.csproj">
<Project>{a43517b5-8be3-4312-913f-004978c34444}</Project>
<Name>Calculator.UIAutomationLibrary</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Config\AppLifecycle.Iterations.xml">
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0' ">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0"?>
<!--
This file defines a table of preformance configuration for use with
TAEF Table Based Data-driven Testing.
This table specifies we will run the test three times (each iteration has a
unique name to identify the scenario) with different parameters each time.
We use the same region file for WinPerf but we specify different WPR profiles
to capture ETW events from different providers, focusing on responsiveness for
launch runs and on memory for one diagnostic memory run.
The warm run is the one we are primarily interested in for startup performance.
-->
<Data>
<Table Id="PerformanceConfigurations">
<Row Name="Cold"
WinPerf.FriendlyAutomationName="AppLifecycle_Responsiveness_Cold"
WinPerf.Iterations="1"
WinPerf.WPRProfile="Config\AppLifecycle.Profile.wprp"
WinPerf.WPRProfileId="AppLifecycle.Responsiveness.Diagnostic.Verbose.File"
WinPerf.Regions="Config\AppLifecycle.Regions.xml">
</Row>
<Row Name="Warm"
WinPerf.FriendlyAutomationName="AppLifecycle_Responsiveness_Warm"
WinPerf.Iterations="10"
WinPerf.WPRProfile="Config\AppLifecycle.Profile.wprp"
WinPerf.WPRProfileId="AppLifecycle.Responsiveness.Diagnostic.Verbose.Memory"
WinPerf.Regions="Config\AppLifecycle.Regions.xml">
</Row>
<Row Name="Memory"
WinPerf.FriendlyAutomationName="AppLifecycle_Memory"
WinPerf.Iterations="1"
WinPerf.WPRProfile="Config\AppLifecycle.Profile.wprp"
WinPerf.WPRProfileId="AppLifecycle.Memory.Diagnostic.Verbose.File"
WinPerf.Regions="Config\AppLifecycle.Regions.xml">
</Row>
</Table>
</Data>

View File

@@ -0,0 +1,526 @@
<!--
This WPRP (WPR profile) contains the App Life Cycle settings for Mobile and Client Performance Gates (MPG and CPG).
Since the appcycle automations are currently still separate, any changes here should be made in two places to keep these wprp's in sync.
CPG: base\PerfTest\MemRe\AppLifecycle\Common\AppLifeCycle.wprp
MPG: wm\src\tools\Product\DH\Test\PerfWorkloads\AppLifeCycle\AppLifeCycle.wprp
Prefixes in the WPRP:
SC_ - System Collector controlling kernel event tracing
EC_ - Event Collector controlling user mode event tracing
SP_ - System Provider
EP_ - Event Provider
There are two separate traces - Responsiveness and Memory.
Within that, we have Light tracing which is for official gating metrics/traces, and we have Verbose tracing, which is for Diagnostic metrics\traces.
-->
<WindowsPerformanceRecorder Version="1.0" Comments="Test" Company="Microsoft Corporation" Copyright="Microsoft Corporation">
<Profiles>
<!-- BufferSizes are in KB in WPRP -->
<!-- System Collectors -->
<SystemCollector Id="SC_Responsiveness.LowCost.Light" Name="NT Kernel Resposiveness Logger LowCost Light">
<BufferSize Value="1024" />
<Buffers Value="3" PercentageOfTotalMemory="true" MaximumBufferSpace="30" />
</SystemCollector>
<SystemCollector Id="SC_Responsiveness.LowCost" Name="NT Kernel Resposiveness Logger LowCost">
<BufferSize Value="1024" />
<Buffers Value="35" />
</SystemCollector>
<SystemCollector Id="SC_Responsiveness.HighCost.Verbose" Name="NT Kernel Resposiveness Logger HighCost Verbose">
<BufferSize Value="1024" />
<Buffers Value="7" PercentageOfTotalMemory="true" MaximumBufferSpace="140" />
</SystemCollector>
<SystemCollector Id="SC_Memory.LowCost.Light" Name="NT Kernel Memory Logger LowCost Light">
<BufferSize Value="1024" />
<Buffers Value="35" />
</SystemCollector>
<SystemCollector Id="SC_Memory.HighCost.Verbose" Name="NT Kernel Memory Logger LowCost Light">
<BufferSize Value="1024" />
<Buffers Value="75" />
</SystemCollector>
<!-- Event Collectors -->
<EventCollector Id="EC_Responsiveness.LowCost.Light" Name="User Session Logger LowCost Light">
<BufferSize Value="1024" />
<Buffers Value="2" PercentageOfTotalMemory="true" MaximumBufferSpace="20"/>
</EventCollector>
<EventCollector Id="EC_Responsiveness.LowCost.Light.UTC" Name="User Session Logger LowCost Light UTC">
<BufferSize Value="1024"/>
<Buffers Value="5"/>
</EventCollector>
<EventCollector Id="EC_Responsiveness.LowCost" Name="User Session Logger LowCost">
<BufferSize Value="1024" />
<Buffers Value="15" />
</EventCollector>
<EventCollector Id="EC_Responsiveness.HighCost.Verbose" Name="User Session Logger Higcost Verbose">
<BufferSize Value="1024" />
<Buffers Value="3" PercentageOfTotalMemory="true" MaximumBufferSpace="60" />
</EventCollector>
<EventCollector Id="EC_Memory.LowCost.Light" Name="User Session Logger LowCost Light">
<BufferSize Value="1024" />
<Buffers Value="30" />
</EventCollector>
<!-- System Providers for collecting kernel events. -->
<SystemProvider Id="SP_Responsiveness.Light">
<Keywords Operation="Add">
<Keyword Value="CompactCSwitch"/>
<Keyword Value="CSwitch"/>
<Keyword Value="DiskIO"/>
<Keyword Value="ProcessThread"/>
<Keyword Value="Loader"/>
</Keywords>
</SystemProvider>
<SystemProvider Id="SP_Responsiveness" Base="SP_Responsiveness.Light">
<Keywords Operation="Add">
<Keyword Value="HardFaults"/>
<Keyword Value="MemoryInfo"/>
<Keyword Value="ReadyThread"/>
<Keyword Value="SampledProfile"/>
<Keyword Value="Session"/>
<Keyword Value="VAMap"/>
<Keyword Value="DPC"/>
<Keyword Value="Power"/>
</Keywords>
<Stacks Operation="Add">
<Stack Value="CSwitch"/>
<Stack Value="ReadyThread"/>
<Stack Value="SampledProfile"/>
</Stacks>
</SystemProvider>
<SystemProvider Id="SP_Memory.Light" Base="SP_Responsiveness.Light" >
<Keywords Operation="Add">
<Keyword Value="Memory"/>
<Keyword Value="MemoryInfo"/>
<Keyword Value="HardFaults"/>
<Keyword Value="ReferenceSet"/>
<Keyword Value="VirtualAllocation"/>
</Keywords>
</SystemProvider>
<SystemProvider Id="SP_Memory" Base="SP_Responsiveness" >
<Keywords Operation="Add">
<Keyword Value="FootPrint"/>
<Keyword Value="Memory"/>
<Keyword Value="MemoryInfoWS"/>
<Keyword Value="ReferenceSet"/>
<Keyword Value="VirtualAllocation"/>
</Keywords>
<Stacks Operation="Add">
<Stack Value="HeapCreate" />
<Stack Value="ImageLoad" />
<Stack Value="PageAccess" />
<Stack Value="PageAccessEx" />
<Stack Value="PagefileMappedSectionCreate" />
<Stack Value="PagefileMappedSectionDelete" />
<Stack Value="PageRangeAccess" />
<Stack Value="PageRangeRelease" />
<Stack Value="PageRelease" />
<Stack Value="PageRemovedfromWorkingSet" />
<Stack Value="VirtualAllocation" />
<Stack Value="VirtualFree" />
</Stacks>
</SystemProvider>
<!-- Start - AppLaunch.wprp -->
<EventProvider Id="EP_UTC" Name="UTC" NonPagedMemory="true" Level="4" />
<EventProvider Id="EP_Microsoft-WindowsPhone-AppPlatProvider" Name="3C42000F-CC27-48C3-A005-48F6E38B131F" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_XNA" Name="CD698436-A3E3-4607-BB60-0BAC4D765B59" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_TaskHost" Name="5CBDF2A5-7290-4ACC-B8A7-9BA285BEBC39" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsPhone-Silverlight" Name="AA087E0E-0B35-4e28-8F3A-440C3F51EEF1" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Device-Health-Etw" Name="F7A8FD9F-8FFD-482f-86C0-4C19240F334C" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsMobile-Compositor" Name="85FFFBA1-CF12-402c-B9B3-29A3217BB007" Level="5">
<Keywords>
<Keyword Value="0xfffffff" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsMobile-Splash" Name="872c8950-0def-4d5b-83f6-57dd027f88ce" Level="4">
<Keywords>
<Keyword Value="0xfffffff" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsMobile-UIXMobile" Name="0C0FFEE0-F4B1-4F4D-B591-FB3175B13413">
<Keywords>
<Keyword Value="0xE" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsMobile-StartMenu" Name="BECF83FD-D220-4b19-B7C1-C9127307F6B1" Level="5">
<Keywords>
<Keyword Value="0xfffffff" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-EventTracing" Name="b675ec37-bdb6-4648-bc92-f3fdc74d3ca2" Level="5">
<Keywords>
<Keyword Value="0x50" />
</Keywords>
<CaptureStateOnSave>
<Keyword Value="0x50" />
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsPhone-MobileUI" Name="F243DC34-205E-4d34-94CA-36E8C0859787" Level="5">
<Keywords>
<Keyword Value="0xfffffff" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Process" Name="2839ff94-8f12-4e1b-82e3-af7af77a450f" NonPagedMemory="true" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-TestExecution" Name="Microsoft-Windows-TestExecution" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft.Windows.WinPerf" Name="BE6F04EA-3488-4543-8082-24843EAEC303" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Shell-Launcher" Name="*Microsoft-Windows-Shell-Launcher" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Immersive-Shell" Name="315A8872-923E-4EA2-9889-33CD4754BF64" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-XAML-Light" Name="531A35AB-63CE-4BCF-AA98-F88C7A89E455" Level="4" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-XAML-Verbose" Name="531A35AB-63CE-4BCF-AA98-F88C7A89E455" Level="5" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-ProcessLifetimeManager" Name="*Microsoft.Windows.ProcessLifetimeManager" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Desktop-ApplicationFrame" Name="678e492b-5de1-50c5-7219-ae4aa7d6a141" Level="5" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Microsoft-Phone-AppLifecycle" Name="f623a8ef-84da-4640-8917-fd5b0f847f28" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsPhone-CoreUIComponents" Name="a0b7550f-4e9a-4f03-ad41-b8042d06a2f7" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-AppModel-Exec" Name="EB65A492-86C0-406A-BACE-9912D595BD69" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft.Windows.ActivationManager" Name="cf7f94b3-08dc-5257-422f-497d7dc86ab3">
<Keywords>
<Keyword Value="0x0" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-WindowsMobile-ExecManLogPublisher" Name="82c8ad90-5f3c-11be-bd9a-85bb5f50dfa4" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Shell-CortanaSearch" Name="E34441D9-5BCF-4958-B787-3BF824F362D7" >
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Dwm-Core" Name="9e9bba3c-2e38-40cb-99f4-9e8281425164" Level="4" >
<Keywords>
<Keyword Value="0x2000C"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-ImageLoad" Name="2cb15d1d-5fc1-11d2-abe1-00a0c911f518" >
<Keywords>
<Keyword Value="0x10"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-AppLifeCycle-UI" Name="ee97cdc4-b095-5c70-6e37-a541eb74c2b5" Level="5">
<Keywords>
<Keyword Value="0x400000000000"/>
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-AppLifeCycle" Name="ef00584a-2655-462c-bc24-e7de630e7fbf">
<Keywords>
<Keyword Value="0x0000000000000"/>
</Keywords>
<CaptureStateOnSave>
<Keyword Value="0x0000000000000"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Power" Name="331C3B3A-2005-44C2-AC5E-77220C37D6B4" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0xA4"/>
</Keywords>
<CaptureStateOnSave Timeout="0">
<Keyword Value="0xA4"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Processor-Power" Name="0f67e49f-fe51-4e9f-b490-6f2948cc6027" NonPagedMemory="true" EventKey="true" Level="4">
<Keywords>
<Keyword Value="0xC2"/>
</Keywords>
<CaptureStateOnSave Timeout="0">
<Keyword Value="0xC2"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Pep" Name="5412704E-B2E1-4624-8FFD-55777B8F7373" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
<CaptureStateOnSave Timeout="0">
<Keyword Value="0x0"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Acpi" Name="C514638F-7723-485B-BCFC-96565D735D4A" Level="5" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
<CaptureStateOnSave>
<Keyword Value="0x0"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-UserModePowerService" Name="CE8DEE0B-D539-4000-B0F8-77BED049C590" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x0"/>
</Keywords>
<CaptureStateOnSave Timeout="0">
<Keyword Value="0x0"/>
</CaptureStateOnSave>
</EventProvider>
<EventProvider Id="EP_Microsoft.ClipC" Level="0" Name="ed0c10a5-5396-4a96-9ee3-6f4aa0d1120d" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x200000000000" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft.ClipSp" Level="0" Name="b4b126de-32fe-4591-9ac5-b0778d79a0e7" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x200000000000" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft.ClipSvc" Level="0" Name="b94d76c5-9d56-454a-8d1b-6ca30898160e" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x200000000000" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft.Windows.LicenseManager.Telemetry" Level="0" Name="af9f58ec-0c04-4be9-9eb5-55ff6dbe72d7" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x200000000000" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Win32k" Level="0" Name="8c416c79-d49b-4f01-a467-e56d3aa8234c" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x26A000" />
</Keywords>
</EventProvider>
<EventProvider Id="EP_Microsoft-Windows-Kernel-Prefetch" Level="0" Name="Microsoft-Windows-Kernel-Prefetch" NonPagedMemory="true" EventKey="true">
<Keywords>
<Keyword Value="0x0" />
</Keywords>
</EventProvider>
<!-- End - AppLaunch.wprp -->
<Profile Id="AppLifecycle.Responsiveness.Light.File" LoggingMode="File" Name="AppLifecycle.Responsiveness" DetailLevel="Light" Description="App lifecycle responsiveness light to file">
<Collectors>
<SystemCollectorId Value="SC_Responsiveness.LowCost.Light">
<SystemProviderId Value="SP_Responsiveness.Light" />
</SystemCollectorId>
<EventCollectorId Value="EC_Responsiveness.LowCost.Light">
<EventProviders>
<EventProviderId Value="EP_Microsoft-Windows-TestExecution" />
<EventProviderId Value="EP_Microsoft.Windows.WinPerf" />
<EventProviderId Value="EP_Microsoft-Windows-Immersive-Shell"/>
<EventProviderId Value="EP_Microsoft-Windows-AppLifeCycle" />
<EventProviderId Value="EP_Microsoft-Windows-Shell-Launcher" />
<EventProviderId Value="EP_Microsoft-Windows-XAML-Light" />
<EventProviderId Value="EP_Microsoft-Windows-AppLifeCycle-UI" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Process" />
<EventProviderId Value="EP_Microsoft-Windows-Shell-CortanaSearch"/>
<EventProviderId Value="EP_Microsoft-Windows-AppModel-Exec"/>
<EventProviderId Value="EP_Microsoft.Windows.ActivationManager" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-EventTracing" />
<EventProviderId Value="EP_Microsoft-Windows-Desktop-ApplicationFrame" />
<EventProviderId Value="EP_XNA" />
<EventProviderId Value="EP_TaskHost" />
<EventProviderId Value="EP_Device-Health-Etw" />
<EventProviderId Value="EP_Microsoft-Microsoft-Phone-AppLifecycle"/>
<EventProviderId Value="EP_Microsoft-WindowsPhone-CoreUIComponents"/>
<EventProviderId Value="EP_Microsoft-WindowsPhone-AppPlatProvider" />
<EventProviderId Value="EP_Microsoft-WindowsPhone-Silverlight" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-Splash" />
</EventProviders>
</EventCollectorId>
<EventCollectorId Value="EC_Responsiveness.LowCost.Light.UTC">
<EventProviders>
<EventProviderId Value="EP_UTC"/>
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="AppLifecycle.Responsiveness.Diagnostic.Verbose.File" Base="AppLifecycle.Responsiveness.Light.File" LoggingMode="File" Name="AppLifecycle.Responsiveness.Diagnostic" DetailLevel="Verbose" Description="App lifecycle responsiveness verbose to file">
<Collectors Operation="Add">
<SystemCollectorId Value="SC_Responsiveness.LowCost">
<SystemProviderId Value="SP_Responsiveness" />
</SystemCollectorId>
<EventCollectorId Value="EC_Responsiveness.LowCost">
<EventProviders>
<EventProviderId Value="EP_Microsoft-Windows-XAML-Verbose" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-ExecManLogPublisher"/>
<EventProviderId Value="EP_Microsoft-WindowsMobile-Compositor" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-UIXMobile" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-StartMenu" />
<EventProviderId Value="EP_Microsoft-WindowsPhone-MobileUI" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="AppLifecycle.Responsiveness.Diagnostic.Verbose.Memory" Base="AppLifecycle.Responsiveness.Light.File" LoggingMode="Memory" Name="AppLifecycle.Responsiveness.Diagnostic" DetailLevel="Verbose" Description="App life cycle responsiveness verbose to memory">
<Collectors>
<SystemCollectorId Value="SC_Responsiveness.HighCost.Verbose">
<SystemProviderId Value="SP_Responsiveness"/>
</SystemCollectorId>
<EventCollectorId Value="EC_Responsiveness.HighCost.Verbose">
<EventProviders>
<EventProviderId Value="EP_Microsoft-Windows-ProcessLifetimeManager" />
<EventProviderId Value="EP_Microsoft-Windows-Shell-CortanaSearch"/>
<EventProviderId Value="EP_Microsoft-WindowsMobile-ExecManLogPublisher"/>
<EventProviderId Value="EP_Microsoft-WindowsMobile-Compositor" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-UIXMobile" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-StartMenu" />
<EventProviderId Value="EP_Microsoft-WindowsPhone-MobileUI" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Power" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Processor-Power" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Pep" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Acpi" />
<EventProviderId Value="EP_Microsoft-Windows-UserModePowerService" />
<EventProviderId Value="EP_Microsoft-Windows-Dwm-Core" />
<EventProviderId Value="EP_Microsoft-Windows-ImageLoad" />
<EventProviderId Value="EP_Microsoft.ClipC" />
<EventProviderId Value="EP_Microsoft.ClipSp" />
<EventProviderId Value="EP_Microsoft.ClipSvc" />
<EventProviderId Value="EP_Microsoft.Windows.LicenseManager.Telemetry" />
<EventProviderId Value="EP_Microsoft-Windows-Win32k" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Prefetch" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="AppLifecycle.Memory.Light.File" LoggingMode="File" Name="AppLifecycle.Memory" DetailLevel="Light" Description="App lifecycle memory light to file">
<Collectors>
<SystemCollectorId Value="SC_Memory.LowCost.Light">
<SystemProviderId Value="SP_Memory.Light" />
</SystemCollectorId>
<EventCollectorId Value="EC_Memory.LowCost.Light">
<EventProviders>
<EventProviderId Value="EP_Microsoft-Windows-TestExecution" />
<EventProviderId Value="EP_Microsoft.Windows.WinPerf" />
<EventProviderId Value="EP_Microsoft-Windows-Immersive-Shell"/>
<EventProviderId Value="EP_Microsoft-Windows-AppModel-Exec"/>
<EventProviderId Value="EP_Microsoft.Windows.ActivationManager" />
<EventProviderId Value="EP_Microsoft-Windows-AppLifeCycle" />
<EventProviderId Value="EP_Microsoft-Windows-AppLifeCycle-UI" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-EventTracing" />
<EventProviderId Value="EP_Microsoft-Windows-Desktop-ApplicationFrame" />
<EventProviderId Value="EP_XNA" />
<EventProviderId Value="EP_TaskHost" />
<EventProviderId Value="EP_Device-Health-Etw" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-ExecManLogPublisher"/>
<EventProviderId Value="EP_Microsoft-Microsoft-Phone-AppLifecycle"/>
<EventProviderId Value="EP_Microsoft-WindowsPhone-CoreUIComponents"/>
<EventProviderId Value="EP_Microsoft-WindowsPhone-AppPlatProvider" />
<EventProviderId Value="EP_Microsoft-WindowsPhone-Silverlight" />
<EventProviderId Value="EP_Microsoft-Windows-XAML-Light" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-Splash" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Prefetch" />
</EventProviders>
</EventCollectorId>
<EventCollectorId Value="EC_Responsiveness.LowCost.Light.UTC">
<EventProviders>
<EventProviderId Value="EP_UTC"/>
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="AppLifecycle.Memory.Diagnostic.Verbose.File" Base="AppLifecycle.Memory.Light.File" LoggingMode="File" Name="AppLifecycle.Memory.Diagnostic" DetailLevel="Verbose" Description="App lifecycle memory verbose to file">
<Collectors Operation="Add">
<SystemCollectorId Value="SC_Memory.HighCost.Verbose">
<SystemProviderId Value="SP_Memory" />
</SystemCollectorId>
<EventCollectorId Value="EC_Memory.LowCost.Light">
<EventProviders>
<EventProviderId Value="EP_Microsoft-Windows-Shell-Launcher" />
<EventProviderId Value="EP_Microsoft-Windows-XAML-Verbose" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Power" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Processor-Power" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Pep" />
<EventProviderId Value="EP_Microsoft-Windows-Dwm-Core" />
<EventProviderId Value="EP_Microsoft-Windows-ImageLoad" />
<EventProviderId Value="EP_Microsoft-Windows-Kernel-Process" />
<EventProviderId Value="EP_Microsoft-Windows-Shell-CortanaSearch"/>
<EventProviderId Value="EP_Microsoft-WindowsMobile-Compositor" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-UIXMobile" />
<EventProviderId Value="EP_Microsoft-WindowsMobile-StartMenu" />
<EventProviderId Value="EP_Microsoft-WindowsPhone-MobileUI" />
<EventProviderId Value="EP_Microsoft-Windows-ProcessLifetimeManager" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
</Profiles>
<TraceMergeProperties>
<TraceMergeProperty Id="TraceMerge_Default" Name="TraceMerge_Default" Base="">
<DeletePreMergedTraceFiles Value="true"/>
<CustomEvents>
<CustomEvent Value="ImageId"/>
<CustomEvent Value="BuildInfo"/>
<CustomEvent Value="VolumeMapping"/>
<CustomEvent Value="EventMetadata"/>
<CustomEvent Value="PerfTrackMetadata"/>
<CustomEvent Value="WinSAT"/>
<CustomEvent Value="NetworkInterface"/>
</CustomEvents>
</TraceMergeProperty>
</TraceMergeProperties>
</WindowsPerformanceRecorder>

View File

@@ -0,0 +1,364 @@
<# // Copyright (c) Microsoft Corporation. All rights reserved. #>
<#@ template language="C#" hostspecific="True" #>
<#@ output extension=".xml" #>
<# // Set options specific to your app here
var options = new {
RegionPrefix = "Calculator",
ImageFileName = "Calculator.exe",
PackageFamilyName = "Microsoft.WindowsCalculator",
FirstView = "ms-resource:///Files/Views/MainPage.xbf"
};
#>
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<!--
Based on:
\base\PerfTest\MemRe\AppLifecycle\Common\Regions\Regions_Calculator.xml Regions_Calculator.xml
This is a regions of interest file that can be used by WPA to get a quick overview of the time
spent on a set of operations called "regions".
A region is defined as the combination of a Start and a Stop event.
This file contains regions that are of interest for the startup of a UWP app.
The first region "<#= options.RegionPrefix #>_AppLifecycle" is defined by the Start and Stop event of the test.
Subsequent regions are defined as children of this region to make sure we are only tracking
events that occurred during the test.
The events that are defined as Start and Stop events must come from an event provider that is enabled for the
trace that is being analyzed. For WinPerf, that means that the WPR Profile must have these providers enabled.
-->
<?Copyright (c) Microsoft Corporation. All rights reserved.?>
<InstrumentationManifest>
<Instrumentation>
<Regions>
<RegionRoot Guid="{7e8672b5-efe5-4862-90f3-944f136d6c75}"
Name="<#= options.RegionPrefix #>_AppLifeCycle Region Root"
FriendlyName="Root">
<Region Guid="{cf6c4996-1dc8-4fc5-b275-7a7051376f77}"
Name="<#= options.RegionPrefix #>_AppLifeCycle"
FriendlyName="Application Life Cycle Test">
<Start>
<!-- Microsoft-Windows-TestExecution\RunTest_TestRunScope\win:Start -->
<Event Provider="{70d27130-f2f3-4365-b790-d31223254ef4}" Name="RunTest_TestRunScope" Opcode="1"/>
<!-- Match the name of the test we are running. -->
<PayloadIdentifier FieldName="Name" FieldValue="Calculator.PerfTests.AppLifecycleTests.*" FieldValueRelationship="RegEx"/>
</Start>
<Stop>
<!-- Microsoft-Windows-TestExecution\RunTest_TestRunScope\win:Stop -->
<Event Provider="{70d27130-f2f3-4365-b790-d31223254ef4}" Name="RunTest_TestRunScope" Opcode="2"/>
<!-- Match the name of the test we are running. -->
<PayloadIdentifier FieldName="Name" FieldValue="Calculator.PerfTests.AppLifecycleTests.*" FieldValueRelationship="RegEx"/>
</Stop>
<Naming>
<PayloadBased NameField="Name"/>
</Naming>
<Region Guid="{b18b32ec-6796-43e1-802f-aec9aea5eb28}"
Name="<#= options.RegionPrefix #>_Launch_ProcessStart"
FriendlyName="Process Started">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{2839ff94-8f12-4e1b-82e3-af7af77a450f}" Name="ProcessStarted" Version="0" />
<PayloadIdentifier FieldName="ImageFileName" FieldValue=".*<#= options.ImageFileName #>" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{b1e4255d-131c-4ea8-899d-30b7345bf7d3}"
Name="<#= options.RegionPrefix #>_Launch_UIThreadStart"
FriendlyName="UI Thread Started">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<!-- Ideally use actual thread start event, for now it's just close, using InitializeCore -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="31" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{38084b96-d955-4603-a2c7-2720195ce160}"
Name="<#= options.RegionPrefix #>_Launch_InitializeCore"
FriendlyName="Create XAML Core">
<Start>
<!-- Initialize Core Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="31" Version="0" />
</Start>
<Stop>
<!-- Initialize Core Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="32" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{cc909ec4-17c0-4cd9-9a83-293e06e0dc72}"
Name="<#= options.RegionPrefix #>_Launch_CreateDevice"
FriendlyName="Create Graphics Device">
<Start>
<!-- Create Device Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="76" Version="0" />
</Start>
<Stop>
<!-- Create Device Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="77" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{0ed49a01-2604-499e-8003-0878b3b3c61e}"
Name="<#= options.RegionPrefix #>_Launch_CreateResourceManager"
FriendlyName="Create Resource Manager">
<Start>
<!-- Create Resource Manager Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="463" Version="0" />
</Start>
<Stop>
<!-- Create Resource Manager Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="464" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{365920df-10e7-4b6e-8dcb-e769844ac11f}"
Name="<#= options.RegionPrefix #>_Launch_CreateWindow"
FriendlyName="Create Window">
<Start>
<!-- Create Window Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="29" Version="0" />
</Start>
<Stop>
<!-- Create Window Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="30" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{09995446-0266-4a34-aa39-d99467dfe85d}"
Name="<#= options.RegionPrefix #>_Launch_InitializeTheme"
FriendlyName="Initialize Theme Resources">
<Start>
<!-- Theme Changed Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="457" Version="0" />
</Start>
<Stop>
<!-- Theme Changed Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="458" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{a2fdff0b-75c8-440d-bb55-b87a3c60d55f}"
Name="<#= options.RegionPrefix #>_Launch_NavToFirstFrame"
FriendlyName="XAML Navigate To First Frame Drawn">
<Start>
<!-- Parse XAML -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="1" Version="0" />
<PayloadIdentifier FieldName="URI" FieldValue="<#= options.FirstView #>" />
</Start>
<Stop>
<!-- Frame Drawn -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="65" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
<Match>
<Event PID="true"/>
</Match>
</Region>
<Region Guid="{ffc47f79-2d90-470a-bfde-0d075972f23b}"
Name="<#= options.RegionPrefix #>_ApplicationActivate"
FriendlyName="Application Activate">
<Start>
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="5901" Version="1" />
</Start>
<Stop>
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="5902" Version="1" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{b0c74cf1-16fc-4a33-ba7e-2169727a08d7}"
Name="<#= options.RegionPrefix #>_Launch_SplashScreen"
FriendlyName="Splash Screen Dismissed">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<!-- NavigationServerTask_SplashScreenDismissed -->
<Event Provider="{a0b7550f-4e9a-4f03-ad41-b8042d06a2f7}" Id="1572" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{a1648637-d5ec-46d2-9655-a26d00a35764}"
Name="<#= options.RegionPrefix #>_Launch_UIResponsive"
FriendlyName="UI Responsive">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{EF00584A-2655-462C-BC24-E7DE630E7FBF}" Name="ModernAppLaunch_UIResponsive" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{74d63c4e-7dd7-4ff6-9ee8-adb462c1c101}"
Name="<#= options.RegionPrefix #>_Launch_VisibleComplete"
FriendlyName="Visible Complete">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{EF00584A-2655-462C-BC24-E7DE630E7FBF}" Name="ModernAppLaunch_VisibleComplete" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{ec31fb10-992b-438b-8c9e-42454f4b2e5a}"
Name="<#= options.RegionPrefix #>_Suspend"
FriendlyName="Suspended">
<Start>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_SuspendApplication\win:Start -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="2450" Version="1" />
<PayloadIdentifier FieldName="PsmKey" FieldValueRelationship="RegEx" FieldValue="<#= options.PackageFamilyName #>.*" />
</Start>
<Stop>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_SuspendApplication\win:Stop -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="2451" Version="1" />
<PayloadIdentifier FieldName="AppUserModelId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{83735b08-b17e-48cf-82f1-02cb08e45597}"
Name="<#= options.RegionPrefix #>_Resume"
FriendlyName="Resumed">
<Start>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_ResumeApplication_EndToEnd\win:Start -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="11118" Version="0" />
<PayloadIdentifier FieldName="PsmKey" FieldValueRelationship="RegEx" FieldValue="<#= options.PackageFamilyName #>.*" />
</Start>
<Stop>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_ResumeApplication_EndToEnd\win:Stop -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="11119" Version="0" />
<PayloadIdentifier FieldName="AppUserModelId" FieldValue="<#= options.PackageFamilyName #>.*" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName><#= options.ImageFileName #></WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
</Region>
</RegionRoot>
</Regions>
</Instrumentation>
</InstrumentationManifest>

View File

@@ -0,0 +1,353 @@
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<!--
Based on:
\base\PerfTest\MemRe\AppLifecycle\Common\Regions\Regions_Calculator.xml Regions_Calculator.xml
This is a regions of interest file that can be used by WPA to get a quick overview of the time
spent on a set of operations called "regions".
A region is defined as the combination of a Start and a Stop event.
This file contains regions that are of interest for the startup of a UWP app.
The first region "Calculator_AppLifecycle" is defined by the Start and Stop event of the test.
Subsequent regions are defined as children of this region to make sure we are only tracking
events that occurred during the test.
The events that are defined as Start and Stop events must come from an event provider that is enabled for the
trace that is being analyzed. For WinPerf, that means that the WPR Profile must have these providers enabled.
-->
<?Copyright (c) Microsoft Corporation. All rights reserved.?>
<InstrumentationManifest>
<Instrumentation>
<Regions>
<RegionRoot Guid="{7e8672b5-efe5-4862-90f3-944f136d6c75}"
Name="Calculator_AppLifeCycle Region Root"
FriendlyName="Root">
<Region Guid="{cf6c4996-1dc8-4fc5-b275-7a7051376f77}"
Name="Calculator_AppLifeCycle"
FriendlyName="Application Life Cycle Test">
<Start>
<!-- Microsoft-Windows-TestExecution\TE_TestRun\win:Start -->
<Event Provider="{065903c1-4883-4fb8-b163-d02bd5efc74c}" Id="7" Version="0" />
<!-- Match the name of the test we are running. -->
<PayloadIdentifier FieldName="Name" FieldValue="Calculator.PerfTests.AppLifecycleTests.*" FieldValueRelationship="RegEx"/>
</Start>
<Stop>
<!-- Microsoft-Windows-TestExecution\TE_TestRun\win:Stop -->
<Event Provider="{065903c1-4883-4fb8-b163-d02bd5efc74c}" Id="8" Version="0" />
<!-- Match the name of the test we are running. -->
<PayloadIdentifier FieldName="Name" FieldValue="Calculator.PerfTests.AppLifecycleTests.*" FieldValueRelationship="RegEx"/>
</Stop>
<Naming>
<PayloadBased NameField="Name"/>
</Naming>
<Region Guid="{b18b32ec-6796-43e1-802f-aec9aea5eb28}"
Name="Calculator_Launch_ProcessStart"
FriendlyName="Process Started">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{2839ff94-8f12-4e1b-82e3-af7af77a450f}" Name="ProcessStarted" Version="0" />
<PayloadIdentifier FieldName="ImageFileName" FieldValue=".*Calculator.exe" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{b1e4255d-131c-4ea8-899d-30b7345bf7d3}"
Name="Calculator_Launch_UIThreadStart"
FriendlyName="UI Thread Started">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<!-- Ideally use actual thread start event, for now it's just close, using InitializeCore -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="31" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{38084b96-d955-4603-a2c7-2720195ce160}"
Name="Calculator_Launch_InitializeCore"
FriendlyName="Create XAML Core">
<Start>
<!-- Initialize Core Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="31" Version="0" />
</Start>
<Stop>
<!-- Initialize Core Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="32" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{cc909ec4-17c0-4cd9-9a83-293e06e0dc72}"
Name="Calculator_Launch_CreateDevice"
FriendlyName="Create Graphics Device">
<Start>
<!-- Create Device Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="76" Version="0" />
</Start>
<Stop>
<!-- Create Device Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="77" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{0ed49a01-2604-499e-8003-0878b3b3c61e}"
Name="Calculator_Launch_CreateResourceManager"
FriendlyName="Create Resource Manager">
<Start>
<!-- Create Resource Manager Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="463" Version="0" />
</Start>
<Stop>
<!-- Create Resource Manager Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="464" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{365920df-10e7-4b6e-8dcb-e769844ac11f}"
Name="Calculator_Launch_CreateWindow"
FriendlyName="Create Window">
<Start>
<!-- Create Window Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="29" Version="0" />
</Start>
<Stop>
<!-- Create Window Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="30" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{09995446-0266-4a34-aa39-d99467dfe85d}"
Name="Calculator_Launch_InitializeTheme"
FriendlyName="Initialize Theme Resources">
<Start>
<!-- Theme Changed Start -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="457" Version="0" />
</Start>
<Stop>
<!-- Theme Changed Stop -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="458" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{a2fdff0b-75c8-440d-bb55-b87a3c60d55f}"
Name="Calculator_Launch_NavToFirstFrame"
FriendlyName="XAML Navigate To First Frame Drawn">
<Start>
<!-- Parse XAML -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="1" Version="0" />
<PayloadIdentifier FieldName="URI" FieldValue="ms-resource:///Files/Views/MainPage.xbf" />
</Start>
<Stop>
<!-- Frame Drawn -->
<Event Provider="{531A35AB-63CE-4BCF-AA98-F88C7A89E455}" Id="65" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
<Match>
<Event PID="true"/>
</Match>
</Region>
<Region Guid="{ffc47f79-2d90-470a-bfde-0d075972f23b}"
Name="Calculator_ApplicationActivate"
FriendlyName="Application Activate">
<Start>
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="5901" Version="1" />
</Start>
<Stop>
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="5902" Version="1" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{b0c74cf1-16fc-4a33-ba7e-2169727a08d7}"
Name="Calculator_Launch_SplashScreen"
FriendlyName="Splash Screen Dismissed">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<!-- NavigationServerTask_SplashScreenDismissed -->
<Event Provider="{a0b7550f-4e9a-4f03-ad41-b8042d06a2f7}" Id="1572" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{a1648637-d5ec-46d2-9655-a26d00a35764}"
Name="Calculator_Launch_UIResponsive"
FriendlyName="UI Responsive">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{EF00584A-2655-462C-BC24-E7DE630E7FBF}" Name="ModernAppLaunch_UIResponsive" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{74d63c4e-7dd7-4ff6-9ee8-adb462c1c101}"
Name="Calculator_Launch_VisibleComplete"
FriendlyName="Visible Complete">
<Start>
<!-- Use AAMShim_ActivationStart instead of AppLaunch_UserClick as we don't lanch from Start -->
<Event Provider="{cf7f94b3-08dc-5257-422f-497d7dc86ab3}" Name="AAMShim_ActivationStart" />
<PayloadIdentifier FieldName="AppId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Start>
<Stop>
<Event Provider="{EF00584A-2655-462C-BC24-E7DE630E7FBF}" Name="ModernAppLaunch_VisibleComplete" Version="0" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{ec31fb10-992b-438b-8c9e-42454f4b2e5a}"
Name="Calculator_Suspend"
FriendlyName="Suspended">
<Start>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_SuspendApplication\win:Start -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="2450" Version="1" />
<PayloadIdentifier FieldName="PsmKey" FieldValueRelationship="RegEx" FieldValue="Microsoft.WindowsCalculator.*" />
</Start>
<Stop>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_SuspendApplication\win:Stop -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="2451" Version="1" />
<PayloadIdentifier FieldName="AppUserModelId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
<Region Guid="{83735b08-b17e-48cf-82f1-02cb08e45597}"
Name="Calculator_Resume"
FriendlyName="Resumed">
<Start>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_ResumeApplication_EndToEnd\win:Start -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="11118" Version="0" />
<PayloadIdentifier FieldName="PsmKey" FieldValueRelationship="RegEx" FieldValue="Microsoft.WindowsCalculator.*" />
</Start>
<Stop>
<!-- Microsoft-Windows-Immersive-Shell\PerfTrack_PLM_ResumeApplication_EndToEnd\win:Stop -->
<Event Provider="{315a8872-923e-4ea2-9889-33cd4754bf64}" Id="11119" Version="0" />
<PayloadIdentifier FieldName="AppUserModelId" FieldValue="Microsoft.WindowsCalculator.*" FieldValueRelationship="RegEx" />
</Stop>
<Naming>
<PrependParentName />
</Naming>
<Metadata>
<WinperfWPAPreset.1>CPU</WinperfWPAPreset.1>
<WinperfWPAPreset.1.ProcessName>Calculator.exe</WinperfWPAPreset.1.ProcessName>
<WinperfWPAPreset.2>Commit</WinperfWPAPreset.2>
<WinperfWPAPreset.2.ProcessName>Calculator.exe</WinperfWPAPreset.2.ProcessName>
</Metadata>
</Region>
</Region>
</RegionRoot>
</Regions>
</Instrumentation>
</InstrumentationManifest>

View File

@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Calculator.UIAutomationLibrary;
using Microsoft.OneCoreUap.Test.AppModel;
using WEX.TestExecution;
using WEX.TestExecution.Markup;
namespace Calculator.UITests
{
[TestClass]
public class Initialization
{
[DllImport("AppModel.TestHelper.dll")]
private static extern Int32 WinRTHelper_Register();
[AssemblyInitialize]
[TestProperty("CoreClrProfile", "TestNetv2.0")]
[TestProperty("RunFixtureAs:Assembly", "System")]
public static void AssemblySetup(TestContext context)
{
Verify.AreEqual(0, WinRTHelper_Register());
TestHelper.Initialize();
// Install and Start the Etw.Service service to enable the use of EtwWaiter.
EtwHelper.InstallAndStartETWService();
bool installApp = false;
if (context.Properties.Contains("InstallApp") && (bool.TryParse(context.Properties["InstallApp"].ToString(), out installApp)) && installApp)
{
string certToDeploy = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), Constants.CertificateFileName);
InstallHelper.InstallCertFile(certToDeploy);
string vcLibsToDeploy = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), Constants.VCLibsPackageFileName);
string winUIToDeploy = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), Constants.WinUIPackageFileName);
string appxToDeploy = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), Constants.PackageFileName);
Impersonater.RunAs(Impersonater.RunAsUser.RestrictedUser, () => InstallHelper.InstallPackage(appxToDeploy, vcLibsToDeploy, winUIToDeploy));
}
}
[AssemblyCleanup]
[TestProperty("RunFixtureAs:Assembly", "System")]
public static void AssemblyCleanup()
{
// Stop and remove the Etw.Service service.
EtwHelper.StopAndRemoveETWService();
TestHelper.Uninitialize();
}
}
}

View File

@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UIAutomationTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f5e8f9b8-f7f1-4300-a5cb-35bfab83f51e")]
// The following was autogenerated by UpdateVersion.ps1
[assembly: AssemblyProduct(@"10.16.1128.1252")]

View File

@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using Etw.Managed;
using Microsoft.Windows.Apps.Performance;
using WEX.Logging.Interop;
using WEX.TestExecution;
using WEX.TestExecution.Markup;
using Calculator.UIAutomationLibrary;
namespace Calculator.PerfTests
{
[TestClass]
public class AppLifecycleTests
{
[TestInitialize]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodSetup()
{
Utilities.KillExistingCalculatorProcesses();
}
[TestCleanup]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodCleanup()
{
Utilities.KillExistingCalculatorProcesses();
}
/// <summary>
/// This method executes the AppLifecycle performance test.
/// The test launches the application, suspend and resumes it and then terminates the app.
///
/// A TAEF data source is used to specify the Windows Performance Recorder profile and
/// regions of interest file to use and defines threee different configurations to execute this test with.
/// Cold: The initial run to get dlls loaded into memory and to execute any first-run app logic.
/// Warm: The run that will produce consistent results and that would be used for measures.
/// Memory: A run that is focused on collecting more info on allocations.
/// </summary>
[TestMethod]
[TestProperty("RunAs", "User")]
[TestProperty("Category", "Performance")]
[TestProperty(WinperfConstants.DataSource, PerfConstants.AppLifecycleInterationsSource)]
public void AppLifecycleTest()
{
AppLifecycle.Run(Constants.PackageAppUserModelId);
}
}
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Calculator.UIAutomationLibrary;
using Calculator.UIAutomationLibrary.Tests;
using WEX.TestExecution.Markup;
namespace Calculator.UITests
{
[TestClass]
public class CalculatorTests
{
[TestInitialize]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodSetup()
{
Utilities.KillExistingCalculatorProcesses();
}
[TestCleanup]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodCleanup()
{
Utilities.KillExistingCalculatorProcesses();
}
[TestMethod]
[TestProperty("RunAs", "User")]
public void OnePlusTwoTest()
{
var calculatorLfm = CalculatorAppLauncher.Launch();
calculatorLfm.CalculateOnePlusTwo();
calculatorLfm.Close();
}
[TestMethod]
[TestProperty("RunAs", "User")]
public void Sqrt4Minus2Test()
{
var calculatorLfm = CalculatorAppLauncher.Launch();
calculatorLfm.CalculateSqrt4Minus2();
calculatorLfm.Close();
}
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using MS.Internal.Mita.Foundation;
using MS.Internal.Mita.Foundation.Controls;
using MS.Internal.Mita.Foundation.Waiters;
using System;
using WEX.TestExecution;
using WEX.TestExecution.Markup;
using System.Runtime.InteropServices;
using Microsoft.OneCoreUap.Test.AppModel;
using System.IO;
using Calculator.UITests;
using Calculator.UIAutomationLibrary;
namespace Calculator.UITests
{
[TestClass]
public class LaunchTests
{
[TestInitialize]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodSetup()
{
Utilities.KillExistingCalculatorProcesses();
}
[TestCleanup]
[TestProperty("RunAs", "ElevatedUserOrSystem")]
public void MethodCleanup()
{
Utilities.KillExistingCalculatorProcesses();
}
[TestMethod]
[TestProperty("RunAs", "User")]
public void NormalLaunchTest()
{
var calculatorLfm = CalculatorAppLauncher.Launch();
calculatorLfm.Close();
}
}
}

View File

@@ -0,0 +1,19 @@
{
"dependencies": {
"AppModel.TestHelper": "2018.3.22",
"EtwProcessor.Managed": "10.34.181220007",
"Microsoft.TestInfrastructure.UniversalTest": "1.0.20181107.1",
"Microsoft.Windows.Apps.Performance": "1.0.7",
"MITALite": "1.0.180128001",
"Taef.Managed": "10.34.181220007",
"Test.Net.Redist": "2.0.1"
},
"frameworks": {
"netcore50": {}
},
"runtimes": {
"win10-arm": {},
"win10-x64": {},
"win10-x86": {}
}
}

View File

@@ -0,0 +1,73 @@
{
"$schema": "http://universaltest/schema/testmddefinition-4.json",
"Package": {
"ComponentName": "Calculator",
"SubComponentName": "UITests"
},
"SupportedArchitectures": [ "All" ],
"Execution": {
"Type": "TAEF",
"Parameter": "/ScreenCaptureOnError /TestMode:EnsureLoggedOnUser",
"ExecutionTimeoutInMinutes": "30"
},
"Dependencies": {
"Files": [
{
"SourcePath": "$(OUT_DIR)Calculator.UIAutomationLibrary.dll",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
},
{
"SourcePath": "$(OUT_DIR)Microsoft.Windows.Apps.Performance.dll",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
},
{
"SourcePath": "$(OUT_DIR)Config\\AppLifecycle.Profile.wprp",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)\\Config\\"
},
{
"SourcePath": "$(OUT_DIR)Config\\AppLifecycle.Regions.xml",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)\\Config\\"
},
{
"SourcePath": "$(OUT_DIR)Config\\AppLifecycle.Iterations.xml",
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)\\Config\\"
}
],
"Packages": [
"Microsoft-Windows-Test-Taef",
"Microsoft-Windows-Test-EtwProcessor",
"Microsoft-Test-Taef-EnsureLoggedOnUserTestMode",
"Microsoft-Test-Taef-EtwLoggerTestMode",
"Microsoft-Windows-Test-MitaLite",
"Microsoft-Windows-Test-TestNetV2.0",
"Microsoft-OneCoreUap-Test-AppModel-AreaLibrary"
]
},
"Logs": [],
"Plugins": [],
"Profiles": [
{
"Name": "All",
"Execution": {
"AdditionalParameter": "/TestMode:EtwLogger /p:InstallApp=true /select:not(@Category='Performance')"
},
"Dependencies": {
"AdditionalPackages": [
"Microsoft-Calculator-App"
]
}
},
{
"Name": "Performance",
"Execution": {
"AdditionalParameter": "/TestMode:WinPerf /WinPerf:Upload=Full /winperf:WinPerfSource=\"Utility Apps Performance Tests\" /winperf:VersionProcess=Calculator.exe /winperf:VersionImage=Calculator.exe /p:InstallApp=true /select:@Category='Performance'"
},
"Dependencies": {
"AdditionalPackages": [
"Microsoft-Windows-Performance-Winperf-Winperf",
"Microsoft-Calculator-App"
]
}
}
]
}

View File

@@ -0,0 +1,165 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2036
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.UIAutomationLibrary", "Calculator.UIAutomationLibrary\Calculator.UIAutomationLibrary.csproj", "{A43517B5-8BE3-4312-913F-004978C34444}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.UITests", "Calculator.UITests\Calculator.UITests.csproj", "{0224A709-0C48-4C4F-BA17-843A49842C15}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E73C8A6E-BB94-4258-ACED-7C837A6A587B}"
ProjectSection(SolutionItems) = preProject
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Calculator", "..\src\Calculator\Calculator.vcxproj", "{9447424A-0E05-4911-BEB8-E0354405F39A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "..\src\CalcViewModel\CalcViewModel.vcxproj", "{90E9761D-9262-4773-942D-CAEAE75D7140}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcManager", "..\src\CalcManager\CalcManager.vcxproj", "{311E866D-8B93-4609-A691-265941FEE101}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.TestPackage", "Calculator.TestPackage\Calculator.TestPackage.csproj", "{24767C43-CD5A-4DC9-8D6B-429F255524E5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|ARM.Build.0 = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|x64.ActiveCfg = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|x64.Build.0 = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|x86.ActiveCfg = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Debug|x86.Build.0 = Debug|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|ARM.ActiveCfg = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|ARM.Build.0 = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|ARM64.ActiveCfg = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|x64.ActiveCfg = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|x64.Build.0 = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|x86.ActiveCfg = Release|Any CPU
{A43517B5-8BE3-4312-913F-004978C34444}.Release|x86.Build.0 = Release|Any CPU
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|ARM.ActiveCfg = Debug|ARM
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|ARM.Build.0 = Debug|ARM
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|x64.ActiveCfg = Debug|x64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|x64.Build.0 = Debug|x64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|x86.ActiveCfg = Debug|x86
{0224A709-0C48-4C4F-BA17-843A49842C15}.Debug|x86.Build.0 = Debug|x86
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|ARM.ActiveCfg = Release|ARM
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|ARM.Build.0 = Release|ARM
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|ARM64.ActiveCfg = Release|ARM64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x64.ActiveCfg = Release|x64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x64.Build.0 = Release|x64
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x86.ActiveCfg = Release|x86
{0224A709-0C48-4C4F-BA17-843A49842C15}.Release|x86.Build.0 = Release|x86
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.ActiveCfg = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Build.0 = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Deploy.0 = Debug|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.Build.0 = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM64.Deploy.0 = Debug|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.ActiveCfg = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.Build.0 = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x64.Deploy.0 = Debug|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.ActiveCfg = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.Build.0 = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|x86.Deploy.0 = Debug|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.ActiveCfg = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.Build.0 = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM.Deploy.0 = Release|ARM
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.ActiveCfg = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.Build.0 = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|ARM64.Deploy.0 = Release|ARM64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.ActiveCfg = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.Build.0 = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x64.Deploy.0 = Release|x64
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.ActiveCfg = Release|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Build.0 = Release|Win32
{9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Deploy.0 = Release|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.ActiveCfg = Debug|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.Build.0 = Debug|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM64.ActiveCfg = Debug|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM64.Build.0 = Debug|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x64.ActiveCfg = Debug|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x64.Build.0 = Debug|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x86.ActiveCfg = Debug|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|x86.Build.0 = Debug|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM.ActiveCfg = Release|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM.Build.0 = Release|ARM
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM64.ActiveCfg = Release|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|ARM64.Build.0 = Release|ARM64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x64.ActiveCfg = Release|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x64.Build.0 = Release|x64
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x86.ActiveCfg = Release|Win32
{90E9761D-9262-4773-942D-CAEAE75D7140}.Release|x86.Build.0 = Release|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.ActiveCfg = Debug|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.Build.0 = Debug|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.ActiveCfg = Debug|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.Build.0 = Debug|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.ActiveCfg = Debug|x64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.Build.0 = Debug|x64
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.ActiveCfg = Debug|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.Build.0 = Debug|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.ActiveCfg = Release|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.Build.0 = Release|ARM
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.ActiveCfg = Release|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.Build.0 = Release|ARM64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x64.ActiveCfg = Release|x64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x64.Build.0 = Release|x64
{311E866D-8B93-4609-A691-265941FEE101}.Release|x86.ActiveCfg = Release|Win32
{311E866D-8B93-4609-A691-265941FEE101}.Release|x86.Build.0 = Release|Win32
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM.ActiveCfg = Debug|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM.Build.0 = Debug|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|x64.ActiveCfg = Debug|x64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|x64.Build.0 = Debug|x64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|x86.ActiveCfg = Debug|x86
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Debug|x86.Build.0 = Debug|x86
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|ARM.ActiveCfg = Release|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|ARM.Build.0 = Release|ARM
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|ARM64.ActiveCfg = Release|ARM64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x64.ActiveCfg = Release|x64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x64.Build.0 = Release|x64
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x86.ActiveCfg = Release|x86
{24767C43-CD5A-4DC9-8D6B-429F255524E5}.Release|x86.Build.0 = Release|x86
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.ActiveCfg = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.Build.0 = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM.Deploy.0 = Debug|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.Build.0 = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|ARM64.Deploy.0 = Debug|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.ActiveCfg = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.Build.0 = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x64.Deploy.0 = Debug|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.ActiveCfg = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.Build.0 = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Debug|x86.Deploy.0 = Debug|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.ActiveCfg = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.Build.0 = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM.Deploy.0 = Release|ARM
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.ActiveCfg = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.Build.0 = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|ARM64.Deploy.0 = Release|ARM64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.ActiveCfg = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.Build.0 = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x64.Deploy.0 = Release|x64
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.ActiveCfg = Release|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.Build.0 = Release|Win32
{E527A1F4-6B63-4DD0-B540-B8C06CFC3AFE}.Release|x86.Deploy.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {97D9888A-CF9F-4147-8CCE-71093C057452}
EndGlobalSection
EndGlobal

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "AsyncHelper.h"
#include <chrono>
#include <thread>
using namespace std;
using namespace concurrency;
using namespace Platform;
using namespace CalculatorApp;
using namespace Windows::UI::Core;
using namespace Windows::ApplicationModel::Core;
task<void> AsyncHelper::RunOnUIThreadAsync(function<void()>&& action)
{
auto callback = ref new DispatchedHandler([action]()
{
action();
});
return create_task(CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, callback));
}
void AsyncHelper::RunOnUIThread(function<void()>&& action, DWORD timeout)
{
task<void> waitTask = RunOnUIThreadAsync([action]()
{
action();
});
WaitForTask<void>(waitTask, timeout);
}
void AsyncHelper::Delay(DWORD milliseconds)
{
thread timer(bind(CalculatorApp::AsyncHelper::Sleep, milliseconds));
timer.join();
}
void AsyncHelper::Sleep(DWORD milliseconds)
{
this_thread::sleep_for(chrono::milliseconds(milliseconds));
}

View File

@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <wrl\wrappers\corewrappers.h>
namespace CalculatorApp
{
class AsyncHelper
{
public:
static concurrency::task<void> RunOnUIThreadAsync(std::function<void()>&& action);
static void RunOnUIThread(std::function<void()>&& action, DWORD timeout = INFINITE);
static void Delay(DWORD milliseconds);
template<typename T>
static void RunOnUIThread(std::function<concurrency::task<T>()>&& action, DWORD timeout = INFINITE)
{
concurrency::task<T> t;
concurrency::task<void> uiTask = RunOnUIThreadAsync([&t, action]()
{
t = action();
}).then([&t]()
{
t.wait();
}, concurrency::task_continuation_context::use_arbitrary());
WaitForTask<void>(uiTask, timeout);
}
template<typename T>
static bool WaitForTask(concurrency::task<T>& t, DWORD timeout = INFINITE)
{
Microsoft::WRL::Wrappers::Event event(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS));
if (!event.IsValid())
{
throw std::bad_alloc();
}
Platform::Exception^ ex;
t.then([&event, &ex](concurrency::task<T> prevTask)
{
try
{
prevTask.get();
}
catch (Platform::Exception^ e)
{
ex = e;
}
if (event.IsValid())
{
SetEvent(event.Get());
}
}, concurrency::task_continuation_context::use_arbitrary());
DWORD waitResult;// = STATUS_PENDING;
waitResult = WaitForSingleObjectEx(event.Get(), timeout, true);
event.Close();
if (ex != nullptr)
{
throw ex;
}
if (waitResult == WAIT_FAILED)
{
throw ref new Platform::Exception(-1, L"Error in waiting for task completion: " + waitResult.ToString());
}
return waitResult == WAIT_OBJECT_0;
}
private:
static void Sleep(DWORD milliseconds);
};
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,582 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <WexTestClass.h>
#include "DateUtils.h"
#include "CalcViewModel\Common\DateCalculator.h"
#include "CalcViewModel\DateCalculatorViewModel.h"
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Globalization;
using namespace Windows::Globalization::DateTimeFormatting;
using namespace CalculatorApp::Common::DateCalculation;
using namespace CalculatorApp::ViewModel;
namespace DateCalculationUnitTests
{
const int c_numDate = 15;
const int c_diffTestCase = 9;
const int c_numAddOobDate = 2;
const int c_numSubtractOobDate = 2;
const int c_addCases = 3;
const int c_subtractCases = 3;
const int c_dateDiff = 14;
DateCalculationEngine m_DateCalcEngine(CalendarIdentifiers::Gregorian);
typedef struct
{
SYSTEMTIME startDate;
SYSTEMTIME endDate;
DateDifference dateDiff;
} DateTimeTestCase;
SYSTEMTIME date[c_numDate];
DateDifference dateDifference[c_dateDiff];
DateTimeTestCase datetimeDifftest[c_diffTestCase];
DateTimeTestCase datetimeBoundAdd[c_numAddOobDate];
DateTimeTestCase datetimeBoundSubtract[c_numSubtractOobDate];
DateTimeTestCase datetimeAddCase[c_addCases];
DateTimeTestCase datetimeSubtractCase[c_subtractCases];
// Test Class
class DateCalculatorUnitTests
{
public:
TEST_CLASS(DateCalculatorUnitTests);
TEST_CLASS_SETUP(TestClassSetup)
{
/* Test Case Data */
// Dates - DD.MM.YYYY
/*31.12.9999*/ date[0].wYear = 9999; date[0].wMonth = 12; date[0].wDayOfWeek = 5; date[0].wDay = 31; date[0].wHour = 0; date[0].wMinute = 0; date[0].wSecond = 0; date[0].wMilliseconds = 0;
/*30.12.9999*/ date[1].wYear = 9999; date[1].wMonth = 12; date[1].wDayOfWeek = 4; date[1].wDay = 30; date[1].wHour = 0; date[1].wMinute = 0; date[1].wSecond = 0; date[1].wMilliseconds = 0;
/*31.12.9998*/ date[2].wYear = 9998; date[2].wMonth = 12; date[2].wDayOfWeek = 4; date[2].wDay = 31; date[2].wHour = 0; date[2].wMinute = 0; date[2].wSecond = 0; date[2].wMilliseconds = 0;
/*01.01.1601*/ date[3].wYear = 1601; date[3].wMonth = 1; date[3].wDayOfWeek = 1; date[3].wDay = 1; date[3].wHour = 0; date[3].wMinute = 0; date[3].wSecond = 0; date[3].wMilliseconds = 0;
/*02.01.1601*/ date[4].wYear = 1601; date[4].wMonth = 1; date[4].wDayOfWeek = 2; date[4].wDay = 2; date[4].wHour = 0; date[4].wMinute = 0; date[4].wSecond = 0; date[4].wMilliseconds = 0;
/*10.05.2008*/ date[5].wYear = 2008; date[5].wMonth = 5; date[5].wDayOfWeek = 6; date[5].wDay = 10; date[5].wHour = 0; date[5].wMinute = 0; date[5].wSecond = 0; date[5].wMilliseconds = 0;
/*10.03.2008*/ date[6].wYear = 2008; date[6].wMonth = 3; date[6].wDayOfWeek = 1; date[6].wDay = 10; date[6].wHour = 0; date[6].wMinute = 0; date[6].wSecond = 0; date[6].wMilliseconds = 0;
/*29.02.2008*/ date[7].wYear = 2008; date[7].wMonth = 2; date[7].wDayOfWeek = 5; date[7].wDay = 29; date[7].wHour = 0; date[7].wMinute = 0; date[7].wSecond = 0; date[7].wMilliseconds = 0;
/*28.02.2007*/ date[8].wYear = 2007; date[8].wMonth = 2; date[8].wDayOfWeek = 3; date[8].wDay = 28; date[8].wHour = 0; date[8].wMinute = 0; date[8].wSecond = 0; date[8].wMilliseconds = 0;
/*10.03.2007*/ date[9].wYear = 2007; date[9].wMonth = 3; date[9].wDayOfWeek = 6; date[9].wDay = 10; date[9].wHour = 0; date[9].wMinute = 0; date[9].wSecond = 0; date[9].wMilliseconds = 0;
/*10.05.2007*/ date[10].wYear = 2007; date[10].wMonth = 5; date[10].wDayOfWeek = 4; date[10].wDay = 10; date[10].wHour = 0; date[10].wMinute = 0; date[10].wSecond = 0; date[10].wMilliseconds = 0;
/*29.01.2008*/ date[11].wYear = 2008; date[11].wMonth = 1; date[11].wDayOfWeek = 2; date[11].wDay = 29; date[11].wHour = 0; date[11].wMinute = 0; date[11].wSecond = 0; date[11].wMilliseconds = 0;
/*28.01.2007*/ date[12].wYear = 2007; date[12].wMonth = 1; date[12].wDayOfWeek = 0; date[12].wDay = 28; date[12].wHour = 0; date[12].wMinute = 0; date[12].wSecond = 0; date[12].wMilliseconds = 0;
/*31.01.2008*/ date[13].wYear = 2008; date[13].wMonth = 1; date[13].wDayOfWeek = 4; date[13].wDay = 31; date[13].wHour = 0; date[13].wMinute = 0; date[13].wSecond = 0; date[13].wMilliseconds = 0;
/*31.03.2008*/ date[14].wYear = 2008; date[14].wMonth = 3; date[14].wDayOfWeek = 1; date[14].wDay = 31; date[14].wHour = 0; date[14].wMinute = 0; date[14].wSecond = 0; date[14].wMilliseconds = 0;
// Date Differences
dateDifference[0].year = 1; dateDifference[0].month = 1;
dateDifference[1].month = 1; dateDifference[1].day = 10;
dateDifference[2].day = 2;
/*date[2]-[0]*/ dateDifference[3].week = 52; dateDifference[3].day = 1;
/*date[2]-[0]*/ dateDifference[4].year = 1;
dateDifference[5].day = 365;
dateDifference[6].month = 1;
dateDifference[7].month = 1; dateDifference[7].day = 2;
dateDifference[8].day = 31;
dateDifference[9].month = 11; dateDifference[9].day = 1;
dateDifference[10].year = 8398; dateDifference[10].month = 11; dateDifference[10].day = 30;
dateDifference[11].year = 2008;
dateDifference[12].year = 7991; dateDifference[12].month = 11;
dateDifference[13].week = 416998; dateDifference[13].day = 1;
/* Test Cases */
// Date Difference test cases
datetimeDifftest[0].startDate = date[0]; datetimeDifftest[0].endDate = date[3]; datetimeDifftest[0].dateDiff = dateDifference[10];
datetimeDifftest[1].startDate = date[0]; datetimeDifftest[1].endDate = date[2]; datetimeDifftest[1].dateDiff = dateDifference[5];
datetimeDifftest[2].startDate = date[0]; datetimeDifftest[2].endDate = date[2]; datetimeDifftest[2].dateDiff = dateDifference[4];
datetimeDifftest[3].startDate = date[0]; datetimeDifftest[3].endDate = date[2]; datetimeDifftest[3].dateDiff = dateDifference[3];
datetimeDifftest[4].startDate = date[14]; datetimeDifftest[4].endDate = date[7]; datetimeDifftest[4].dateDiff = dateDifference[7];
datetimeDifftest[5].startDate = date[14]; datetimeDifftest[5].endDate = date[7]; datetimeDifftest[5].dateDiff = dateDifference[8];
datetimeDifftest[6].startDate = date[11]; datetimeDifftest[6].endDate = date[8]; datetimeDifftest[6].dateDiff = dateDifference[9];
datetimeDifftest[7].startDate = date[13]; datetimeDifftest[7].endDate = date[0]; datetimeDifftest[7].dateDiff = dateDifference[12];
datetimeDifftest[8].startDate = date[13]; datetimeDifftest[8].endDate = date[0]; datetimeDifftest[8].dateDiff = dateDifference[13];
// Date Add Out of Bound test cases (Negative tests)
/*OutofBound*/ datetimeBoundAdd[0].startDate = date[1]; datetimeBoundAdd[0].endDate = date[0]; datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
/*OutofBound*/ datetimeBoundAdd[1].startDate = date[2]; datetimeBoundAdd[1].endDate = date[0]; datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
// Date Subtract Out of Bound test cases (Negative tests)
/*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3]; datetimeBoundSubtract[0].endDate = date[0]; datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
/*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14]; datetimeBoundSubtract[1].endDate = date[0]; datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
// Date Add test cases (Positive tests)
datetimeAddCase[0].startDate = date[13]; datetimeAddCase[0].endDate = date[7]; datetimeAddCase[0].dateDiff = dateDifference[6];// add
datetimeAddCase[1].startDate = date[14]; datetimeAddCase[1].endDate = date[5]; datetimeAddCase[1].dateDiff = dateDifference[1];// add
datetimeAddCase[2].startDate = date[13]; datetimeAddCase[2].endDate = date[6]; datetimeAddCase[2].dateDiff = dateDifference[1];// add
// Date Subtract test cases (Positive tests)
datetimeSubtractCase[0].startDate = date[14]; datetimeSubtractCase[0].endDate = date[7]; datetimeSubtractCase[0].dateDiff = dateDifference[6];// subtract
datetimeSubtractCase[1].startDate = date[6]; datetimeSubtractCase[1].endDate = date[11]; datetimeSubtractCase[1].dateDiff = dateDifference[1];// subtract
datetimeSubtractCase[2].startDate = date[9]; datetimeSubtractCase[2].endDate = date[12]; datetimeSubtractCase[2].dateDiff = dateDifference[1];// subtract
return true;
}
/* Duration Between Two Date Tests -- Timediff obtained after calculation should be checked to be identical */
TEST_METHOD(TestDateDiff)
{
// TODO - MSFT 10331900, fix this test
//for (int testIndex = 0; testIndex < c_diffTestCase; testIndex++)
//{
// DateDifference diff;
// DateUnit dateOutputFormat;
// switch (testIndex)
// {
// case 0:
// case 2:
// dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
// break;
// case 1:
// dateOutputFormat = DateUnit::Day;
// break;
// case 3:
// case 8:
// dateOutputFormat = DateUnit::Week | DateUnit::Day;
// break;
// case 7:
// dateOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Day;
// break;
// case 4:
// case 6:
// dateOutputFormat = DateUnit::Month | DateUnit::Day;
// break;
// case 5:
// dateOutputFormat = DateUnit::Day;
// break;
// }
// // Calculate the difference
// m_DateCalcEngine.GetDateDifference(DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].startDate), DateUtils::SystemTimeToDateTime(datetimeDifftest[testIndex].endDate), dateOutputFormat, &diff);
// // Assert for the result
// bool areIdentical = true;
// if (diff.year != datetimeDifftest[testIndex].dateDiff.year ||
// diff.month != datetimeDifftest[testIndex].dateDiff.month ||
// diff.week != datetimeDifftest[testIndex].dateDiff.week ||
// diff.day != datetimeDifftest[testIndex].dateDiff.day)
// {
// areIdentical = false;
// }
// VERIFY_IS_TRUE(areIdentical);
//}
}
/*Add Out of bound Tests*/
TEST_METHOD(TestAddOob)
{
// TODO - MSFT 10331900, fix this test
//for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
//{
// DateTime endDate;
// // Add Duration
// bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate), datetimeBoundAdd[testIndex].dateDiff, &endDate);
// // Assert for the result
// VERIFY_IS_FALSE(isValid);
//}
}
/*Subtract Out of bound Tests*/
TEST_METHOD(TestSubtractOob)
{
for (int testIndex = 0; testIndex< c_numSubtractOobDate; testIndex++)
{
DateTime endDate;
// Subtract Duration
bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate), datetimeBoundSubtract[testIndex].dateDiff, &endDate);
// Assert for the result
VERIFY_IS_FALSE(isValid);
}
}
// Add Tests
TEST_METHOD(TestAddition)
{
// TODO - MSFT 10331900, fix this test
//for (int testIndex = 0; testIndex < c_addCases; testIndex++)
//{
// DateTime endDate;
// // Add Duration
// bool isValid = m_DateCalcEngine.AddDuration(DateUtils::SystemTimeToDateTime(datetimeAddCase[testIndex].startDate), datetimeAddCase[testIndex].dateDiff, &endDate);
// // Assert for the result
// VERIFY_IS_TRUE(isValid);
// SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
// if (systemTime.wYear != datetimeAddCase[testIndex].endDate.wYear ||
// systemTime.wMonth != datetimeAddCase[testIndex].endDate.wMonth ||
// systemTime.wDay != datetimeAddCase[testIndex].endDate.wDay ||
// systemTime.wDayOfWeek != datetimeAddCase[testIndex].endDate.wDayOfWeek)
// {
// isValid = false;
// }
// VERIFY_IS_TRUE(isValid);
//}
}
// Subtract Tests
TEST_METHOD(TestSubtraction)
{
// TODO - MSFT 10331900, fix this test
//for (int testIndex = 0; testIndex < c_subtractCases; testIndex++)
//{
// DateTime endDate;
// // Subtract Duration
// bool isValid = m_DateCalcEngine.SubtractDuration(DateUtils::SystemTimeToDateTime(datetimeSubtractCase[testIndex].startDate), datetimeSubtractCase[testIndex].dateDiff, &endDate);
// // assert for the result
// VERIFY_IS_TRUE(isValid);
// SYSTEMTIME systemTime = DateUtils::DateTimeToSystemTime(endDate);
// if (systemTime.wYear != datetimeSubtractCase[testIndex].endDate.wYear ||
// systemTime.wMonth != datetimeSubtractCase[testIndex].endDate.wMonth ||
// systemTime.wDay != datetimeSubtractCase[testIndex].endDate.wDay ||
// systemTime.wDayOfWeek != datetimeSubtractCase[testIndex].endDate.wDayOfWeek)
// {
// isValid = false;
// }
// VERIFY_IS_TRUE(isValid);
//}
}
private:
};
class DateCalculatorViewModelTests
{
public:
TEST_CLASS(DateCalculatorViewModelTests);
TEST_CLASS_SETUP(TestClassSetup)
{
/* Test Case Data */
// Dates - DD.MM.YYYY
/*31.12.9999*/ date[0].wYear = 9999; date[0].wMonth = 12; date[0].wDayOfWeek = 5; date[0].wDay = 31; date[0].wHour = 0; date[0].wMinute = 0; date[0].wSecond = 0; date[0].wMilliseconds = 0;
/*30.12.9999*/ date[1].wYear = 9999; date[1].wMonth = 12; date[1].wDayOfWeek = 4; date[1].wDay = 30; date[1].wHour = 0; date[1].wMinute = 0; date[1].wSecond = 0; date[1].wMilliseconds = 0;
/*31.12.9998*/ date[2].wYear = 9998; date[2].wMonth = 12; date[2].wDayOfWeek = 4; date[2].wDay = 31; date[2].wHour = 0; date[2].wMinute = 0; date[2].wSecond = 0; date[2].wMilliseconds = 0;
/*01.01.1601*/ date[3].wYear = 1601; date[3].wMonth = 1; date[3].wDayOfWeek = 1; date[3].wDay = 1; date[3].wHour = 0; date[3].wMinute = 0; date[3].wSecond = 0; date[3].wMilliseconds = 0;
/*02.01.1601*/ date[4].wYear = 1601; date[4].wMonth = 1; date[4].wDayOfWeek = 2; date[4].wDay = 2; date[4].wHour = 0; date[4].wMinute = 0; date[4].wSecond = 0; date[4].wMilliseconds = 0;
/*10.05.2008*/ date[5].wYear = 2008; date[5].wMonth = 5; date[5].wDayOfWeek = 6; date[5].wDay = 10; date[5].wHour = 0; date[5].wMinute = 0; date[5].wSecond = 0; date[5].wMilliseconds = 0;
/*10.03.2008*/ date[6].wYear = 2008; date[6].wMonth = 3; date[6].wDayOfWeek = 1; date[6].wDay = 10; date[6].wHour = 0; date[6].wMinute = 0; date[6].wSecond = 0; date[6].wMilliseconds = 0;
/*29.02.2008*/ date[7].wYear = 2008; date[7].wMonth = 2; date[7].wDayOfWeek = 5; date[7].wDay = 29; date[7].wHour = 0; date[7].wMinute = 0; date[7].wSecond = 0; date[7].wMilliseconds = 0;
/*28.02.2007*/ date[8].wYear = 2007; date[8].wMonth = 2; date[8].wDayOfWeek = 3; date[8].wDay = 28; date[8].wHour = 0; date[8].wMinute = 0; date[8].wSecond = 0; date[8].wMilliseconds = 0;
/*10.03.2007*/ date[9].wYear = 2007; date[9].wMonth = 3; date[9].wDayOfWeek = 6; date[9].wDay = 10; date[9].wHour = 0; date[9].wMinute = 0; date[9].wSecond = 0; date[9].wMilliseconds = 0;
/*10.05.2007*/ date[10].wYear = 2007; date[10].wMonth = 5; date[10].wDayOfWeek = 4; date[10].wDay = 10; date[10].wHour = 0; date[10].wMinute = 0; date[10].wSecond = 0; date[10].wMilliseconds = 0;
/*29.01.2008*/ date[11].wYear = 2008; date[11].wMonth = 1; date[11].wDayOfWeek = 2; date[11].wDay = 29; date[11].wHour = 0; date[11].wMinute = 0; date[11].wSecond = 0; date[11].wMilliseconds = 0;
/*28.01.2007*/ date[12].wYear = 2007; date[12].wMonth = 1; date[12].wDayOfWeek = 0; date[12].wDay = 28; date[12].wHour = 0; date[12].wMinute = 0; date[12].wSecond = 0; date[12].wMilliseconds = 0;
/*31.01.2008*/ date[13].wYear = 2008; date[13].wMonth = 1; date[13].wDayOfWeek = 4; date[13].wDay = 31; date[13].wHour = 0; date[13].wMinute = 0; date[13].wSecond = 0; date[13].wMilliseconds = 0;
/*31.03.2008*/ date[14].wYear = 2008; date[14].wMonth = 3; date[14].wDayOfWeek = 1; date[14].wDay = 31; date[14].wHour = 0; date[14].wMinute = 0; date[14].wSecond = 0; date[14].wMilliseconds = 0;
// Date Differences
dateDifference[0].year = 1; dateDifference[0].month = 1;
dateDifference[1].month = 1; dateDifference[1].day = 10;
dateDifference[2].day = 2;
/*date[2]-[0]*/ dateDifference[3].week = 52; dateDifference[3].day = 1;
/*date[2]-[0]*/ dateDifference[4].year = 1;
dateDifference[5].day = 365;
dateDifference[6].month = 1;
dateDifference[7].month = 1; dateDifference[7].day = 2;
dateDifference[8].day = 31;
dateDifference[9].month = 11; dateDifference[9].day = 1;
dateDifference[10].year = 8398; dateDifference[10].month = 11; dateDifference[10].day = 30;
dateDifference[11].year = 2008;
dateDifference[12].year = 7991; dateDifference[12].month = 11;
dateDifference[13].week = 416998; dateDifference[13].day = 1;
/* Test Cases */
// Date Difference test cases
datetimeDifftest[0].startDate = date[0]; datetimeDifftest[0].endDate = date[3]; datetimeDifftest[0].dateDiff = dateDifference[10];
datetimeDifftest[1].startDate = date[0]; datetimeDifftest[1].endDate = date[2]; datetimeDifftest[1].dateDiff = dateDifference[5];
datetimeDifftest[2].startDate = date[0]; datetimeDifftest[2].endDate = date[2]; datetimeDifftest[2].dateDiff = dateDifference[4];
datetimeDifftest[3].startDate = date[0]; datetimeDifftest[3].endDate = date[2]; datetimeDifftest[3].dateDiff = dateDifference[3];
datetimeDifftest[4].startDate = date[14]; datetimeDifftest[4].endDate = date[7]; datetimeDifftest[4].dateDiff = dateDifference[7];
datetimeDifftest[5].startDate = date[14]; datetimeDifftest[5].endDate = date[7]; datetimeDifftest[5].dateDiff = dateDifference[8];
datetimeDifftest[6].startDate = date[11]; datetimeDifftest[6].endDate = date[8]; datetimeDifftest[6].dateDiff = dateDifference[9];
datetimeDifftest[7].startDate = date[13]; datetimeDifftest[7].endDate = date[0]; datetimeDifftest[7].dateDiff = dateDifference[12];
datetimeDifftest[8].startDate = date[13]; datetimeDifftest[8].endDate = date[0]; datetimeDifftest[8].dateDiff = dateDifference[13];
// Date Add Out of Bound test cases (Negative tests)
/*OutofBound*/ datetimeBoundAdd[0].startDate = date[1]; datetimeBoundAdd[0].endDate = date[0]; datetimeBoundAdd[0].dateDiff = dateDifference[2]; // on Add date[0] not used
/*OutofBound*/ datetimeBoundAdd[1].startDate = date[2]; datetimeBoundAdd[1].endDate = date[0]; datetimeBoundAdd[1].dateDiff = dateDifference[11]; // on Add date[0] not used
// Date Subtract Out of Bound test cases (Negative tests)
/*OutofBound*/ datetimeBoundSubtract[0].startDate = date[3]; datetimeBoundSubtract[0].endDate = date[0]; datetimeBoundSubtract[0].dateDiff = dateDifference[2]; // on subtract date[0] not used
/*OutofBound*/ datetimeBoundSubtract[1].startDate = date[14]; datetimeBoundSubtract[1].endDate = date[0]; datetimeBoundSubtract[1].dateDiff = dateDifference[11]; // on subtract date[0] not used
// Date Add test cases (Positive tests)
datetimeAddCase[0].startDate = date[13]; datetimeAddCase[0].endDate = date[7]; datetimeAddCase[0].dateDiff = dateDifference[6];// add
datetimeAddCase[1].startDate = date[14]; datetimeAddCase[1].endDate = date[5]; datetimeAddCase[1].dateDiff = dateDifference[1];// add
datetimeAddCase[2].startDate = date[13]; datetimeAddCase[2].endDate = date[6]; datetimeAddCase[2].dateDiff = dateDifference[1];// add
// Date Subtract test cases (Positive tests)
datetimeSubtractCase[0].startDate = date[14]; datetimeSubtractCase[0].endDate = date[7]; datetimeSubtractCase[0].dateDiff = dateDifference[6];// subtract
datetimeSubtractCase[1].startDate = date[6]; datetimeSubtractCase[1].endDate = date[11]; datetimeSubtractCase[1].dateDiff = dateDifference[1];// subtract
datetimeSubtractCase[2].startDate = date[9]; datetimeSubtractCase[2].endDate = date[12]; datetimeSubtractCase[2].dateDiff = dateDifference[1];// subtract
return true;
}
TEST_METHOD(DateCalcViewModelInitializationTest)
{
auto viewModel = ref new DateCalculatorViewModel();
// Check for the initialized values
VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
VERIFY_IS_TRUE(viewModel->IsAddMode);
VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
VERIFY_IS_TRUE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
VERIFY_IS_NULL(viewModel->StrDateResult);
}
TEST_METHOD(DateCalcViewModelAddSubtractInitTest)
{
auto viewModel = ref new DateCalculatorViewModel();
viewModel->IsDateDiffMode = false;
// Check for the initialized values
VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
VERIFY_IS_TRUE(viewModel->IsAddMode);
VERIFY_IS_TRUE(0 != viewModel->FromDate.UniversalTime);
VERIFY_IS_TRUE(0 != viewModel->ToDate.UniversalTime);
VERIFY_IS_TRUE(0 != viewModel->StartDate.UniversalTime);
VERIFY_ARE_EQUAL(0, viewModel->DaysOffset);
VERIFY_ARE_EQUAL(0, viewModel->MonthsOffset);
VERIFY_ARE_EQUAL(0, viewModel->YearsOffset);
VERIFY_IS_TRUE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"Same dates"), viewModel->StrDateDiffResult);
VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
VERIFY_IS_NOT_NULL(viewModel->StrDateResult);
VERIFY_IS_TRUE(StringReference(L"") != viewModel->StrDateResult);
}
TEST_METHOD(DateCalcViewModelAddTest)
{
// TODO - MSFT 10331900, fix this test
// A few issues to be investigated..
// The date returned by DateUtils::GetLongDate can be a different string than expected
// based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
// doesn't format according to UTC. If it did, the test would still be incorrect because
// the ViewModel is not necessarily in UTC.
//
// The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
// the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
// This means testing a specific date here, is *not* the same as selecting that date in the app.
//auto viewModel = ref new DateCalculatorViewModel();
//viewModel->Initialize();
//viewModel->IsDateDiffMode = false;
//viewModel->IsAddMode = true;
//VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
//VERIFY_IS_TRUE(viewModel->IsAddMode);
//viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeAddCase[0].startDate);
//viewModel->DaysOffset = datetimeAddCase[0].dateDiff.day;
//viewModel->MonthsOffset = datetimeAddCase[0].dateDiff.month;
//viewModel->YearsOffset = datetimeAddCase[0].dateDiff.year;
//// Assert for the result
//VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
}
TEST_METHOD(DateCalcViewModelSubtractTest)
{
// TODO - MSFT 10331900, fix this test
// A few issues to be investigated..
// The date returned by DateUtils::GetLongDate can be a different string than expected
// based on the values of date[7]. This is because date[7] is in UTC but GetLongDate
// doesn't format according to UTC. If it did, the test would still be incorrect because
// the ViewModel is not necessarily in UTC.
//
// The DateTime value assigned to StartDate after the conversion SystemTimeToDateTime is not
// the same DateTime value as if the user were to select the same date from the CalendarDatePicker.
// This means testing a specific date here, is *not* the same as selecting that date in the app.
//auto viewModel = ref new DateCalculatorViewModel();
//viewModel->Initialize();
//viewModel->IsDateDiffMode = false;
//viewModel->IsAddMode = false;
//VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
//VERIFY_IS_FALSE(viewModel->IsAddMode);
//viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeSubtractCase[0].startDate);
//viewModel->DaysOffset = datetimeSubtractCase[0].dateDiff.day;
//viewModel->MonthsOffset = datetimeSubtractCase[0].dateDiff.month;
//viewModel->YearsOffset = datetimeSubtractCase[0].dateDiff.year;
//// Assert for the result
//VERIFY_ARE_EQUAL(DateUtils::GetLongDate(date[7]), viewModel->StrDateResult);
}
TEST_METHOD(DateCalcViewModelAddOobTest)
{
// TODO - MSFT 10331900, fix this test
// Curiously enough, this test fails because it fails to go Oob.
// Possibly need to update test to use a new max date.
//auto viewModel = ref new DateCalculatorViewModel();
//viewModel->Initialize();
//viewModel->IsDateDiffMode = false;
//viewModel->IsAddMode = true;
//VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
//VERIFY_IS_TRUE(viewModel->IsAddMode);
//for (int testIndex = 0; testIndex< c_numAddOobDate; testIndex++)
//{
// viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundAdd[testIndex].startDate);
// viewModel->DaysOffset = datetimeBoundAdd[testIndex].dateDiff.day;
// viewModel->MonthsOffset = datetimeBoundAdd[testIndex].dateDiff.month;
// viewModel->YearsOffset = datetimeBoundAdd[testIndex].dateDiff.year;
// // Assert for the result
// VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
//}
}
TEST_METHOD(DateCalcViewModelSubtractOobTest)
{
auto viewModel = ref new DateCalculatorViewModel();
viewModel->IsDateDiffMode = false;
viewModel->IsAddMode = false;
VERIFY_IS_FALSE(viewModel->IsDateDiffMode);
VERIFY_IS_FALSE(viewModel->IsAddMode);
for (int testIndex = 0; testIndex < c_numSubtractOobDate; testIndex++)
{
viewModel->StartDate = DateUtils::SystemTimeToDateTime(datetimeBoundSubtract[testIndex].startDate);
viewModel->DaysOffset = datetimeBoundSubtract[testIndex].dateDiff.day;
viewModel->MonthsOffset = datetimeBoundSubtract[testIndex].dateDiff.month;
viewModel->YearsOffset = datetimeBoundSubtract[testIndex].dateDiff.year;
// Assert for the result
VERIFY_ARE_EQUAL(StringReference(L"Date out of Bound"), viewModel->StrDateResult);
}
}
TEST_METHOD(DateCalcViewModelDateDiffTest)
{
// TODO - MSFT 10331900, fix this test
// The last VERIFY checks with expected value "8398 years, 11 months, 4 weeks, 2 days"
// The viewmodel result is something like "8398 years, 12 months, 6568892 weeks, 1 day",
// which shows there is a problem with the viewmodel's reduction algorithm.
//auto viewModel = ref new DateCalculatorViewModel();
//viewModel->Initialize();
//viewModel->IsDateDiffMode = true;
//VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
//viewModel->FromDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].startDate);
//viewModel->ToDate = DateUtils::SystemTimeToDateTime(datetimeDifftest[0].endDate);
//// Assert for the result
//VERIFY_IS_FALSE(viewModel->IsDiffInDays);
//VERIFY_ARE_EQUAL(StringReference(L"3067670 days"), viewModel->StrDateDiffResultInDays);
//VERIFY_ARE_EQUAL(StringReference(L"8398 years, 11 months, 4 weeks, 2 days"), viewModel->StrDateDiffResult);
}
TEST_METHOD(DateCalcViewModelDateDiffResultInDaysTest)
{
auto viewModel = ref new DateCalculatorViewModel();
viewModel->IsDateDiffMode = true;
VERIFY_IS_TRUE(viewModel->IsDateDiffMode);
viewModel->FromDate = DateUtils::SystemTimeToDateTime(date[0]);
viewModel->ToDate = DateUtils::SystemTimeToDateTime(date[1]);
// Assert for the result
VERIFY_IS_TRUE(viewModel->IsDiffInDays);
VERIFY_ARE_EQUAL(StringReference(L"1 day"), viewModel->StrDateDiffResult);
VERIFY_IS_NULL(viewModel->StrDateDiffResultInDays);
}
// Tests that the automation name for the resulting date in Add Mode
// contains the DayOfWeek, Day, Month, and Year
TEST_METHOD(DateCalcViewModelAddSubtractResultAutomationNameTest)
{
auto viewModel = ref new DateCalculatorViewModel();
auto cal = ref new Calendar();
cal->Year = 2007;
cal->Month = 5;
cal->Day = 10;
cal->Hour = 12;
cal->Period = 2;
cal->Nanosecond = 0;
cal->Second = 0;
DateTime startDate = cal->GetDateTime();
viewModel->StartDate = startDate;
viewModel->IsDateDiffMode = false;
viewModel->IsAddMode = true;
wstring actualValue = viewModel->StrDateResultAutomationName->Data();
// Verify each component is present in the result
wstring components[] = {
L"dayofweek.full",
L"month.full",
L"year.full",
L"day"
};
for (const wstring &component : components)
{
auto formatter = ref new DateTimeFormatter(ref new String(component.c_str()));
wstring expectedValue = formatter->Format(startDate)->Data();
wstring message = L"Verifying " + component + L" is present in the result";
VERIFY_IS_TRUE(actualValue.find(expectedValue) != wstring::npos, message.c_str());
}
}
};
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel\DataLoaders\ICurrencyHttpClient.h"
namespace CalculatorApp
{
namespace DataLoaders
{
class CurrencyHttpClient : public ICurrencyHttpClient
{
public:
CurrencyHttpClient();
static Platform::String^ GetRawStaticDataResponse();
static Platform::String^ GetRawAllRatiosDataResponse();
// ICurrencyHttpClient
void SetSourceCurrencyCode(Platform::String^ sourceCurrencyCode) override {}
void SetResponseLanguage(Platform::String^ responseLanguage) override {}
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyMetadata() override;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyRatios() override;
// ICurrencyHttpClient
};
public ref class MockAsyncOperationWithProgress sealed :
public Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>
{
public:
MockAsyncOperationWithProgress(Platform::String^ result);
// IAsyncInfo
virtual property Windows::Foundation::HResult ErrorCode
{
Windows::Foundation::HResult get();
}
virtual property unsigned int Id
{
unsigned int get() { return 128u; }
}
virtual property Windows::Foundation::AsyncStatus Status
{
Windows::Foundation::AsyncStatus get() { return Windows::Foundation::AsyncStatus::Completed; }
}
virtual void Cancel() {}
virtual void Close() {}
// IAsyncInfo
// IAsyncOperationWithProgress
virtual property Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ Progress
{
Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ get() { return nullptr; }
void set(Windows::Foundation::AsyncOperationProgressHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ handler) {}
}
virtual property Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ Completed
{
Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ get() { return nullptr; }
void set(Windows::Foundation::AsyncOperationWithProgressCompletedHandler<Platform::String^, Windows::Web::Http::HttpProgress>^ handler) {}
}
virtual Platform::String^ GetResults() { return m_result; }
// IAsyncOperationWithProgress
private:
Platform::String^ m_result;
};
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1
internal/Readme.txt Normal file
View File

@@ -0,0 +1 @@
This directory contains projects that have dependencies on internal Microsoft tools and that are not necessary to build Calculator.

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