diff --git a/Microsoft.DotNet.Wpf.Test.sln b/Microsoft.DotNet.Wpf.Test.sln index 889fce278..e7d9ffa21 100644 --- a/Microsoft.DotNet.Wpf.Test.sln +++ b/Microsoft.DotNet.Wpf.Test.sln @@ -367,6 +367,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElementLayoutData", "src\Te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElementLayoutTestPart1", "src\Test\ElementLayout\FeatureTests\Part1\ElementLayoutTestPart1.csproj", "{4A3C635A-23B8-4440-8000-AAFA3B83997D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElementServicesTest", "src\Test\ElementServices\FeatureTests\BuildSources\ElementServicesTest.csproj", "{8E9541C8-C7FB-4D27-B2F4-9C47F475F6E9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTestsTrusted", "src\Test\ElementServices\FeatureTests\Trusted\CoreTestsTrusted.csproj", "{1A7495C0-26CF-4FD7-8D16-7773CDA46B93}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTestsUntrusted", "src\Test\ElementServices\FeatureTests\Untrusted\CoreTestsUntrusted.csproj", "{C9B8F473-0F60-4E3D-B3A2-D30A5D36704E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElementServicesData", "src\Test\ElementServices\FeatureTests\TestData\ElementServicesData.csproj", "{2C04C254-08CD-4267-9C5A-D0AD6090C948}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApp", "src\Test\ElementServices\FeatureTests\ControllerApplications\WpfApp\WpfApp.csproj", "{0C0165BA-0B4B-4F2E-A5D8-A281F51E5739}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreezablesTest", "src\Test\ElementServices\FeatureTests\Freezables\BuildSources\FreezablesTest.csproj", "{80929AB1-8C35-452A-B995-3D6D28502BF3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiTouchTestCommon", "src\Test\ElementServices\FeatureTests\Part1\Common\MultiTouchTestCommon.csproj", "{56170610-87BA-4922-AF06-60FB1F5D70A9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiTouchTest", "src\Test\ElementServices\FeatureTests\Part1\multitouch\MultiTouchTest.csproj", "{7D7B24E7-C3ED-4E38-99D1-2859B7805055}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Part1CommonData", "src\Test\ElementServices\FeatureTests\Part1\Common\Part1CommonData.csproj", "{1073D625-B196-4883-BC36-6CBA357B173C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ea7f34985..6db47c493 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -17,7 +17,7 @@ - $(NoWarn);SYSLIB0021;SYSLIB0024;SYSLIB0018;SYSLIB0044 + $(NoWarn);SYSLIB0021;SYSLIB0024;SYSLIB0018;SYSLIB0044;SYSLIB0050 diff --git a/src/Test/BranchCommon/data/DiscoveryInfo.xml b/src/Test/BranchCommon/data/DiscoveryInfo.xml index d2da2dfed..eb4f07435 100644 --- a/src/Test/BranchCommon/data/DiscoveryInfo.xml +++ b/src/Test/BranchCommon/data/DiscoveryInfo.xml @@ -484,5 +484,151 @@ + + + + ElementServices + + + + + + + + + + + FeatureTests\ElementServices\ElementServicesTest.deployment + + + 3.0+ + 4.0Client+ + + + + + + + + + + + + 3.0+ + 4.0Client+ + + + + + + + ElementServices + + + + + + + + + + + FeatureTests\ElementServices\ElementServicesTest.deployment + + + 3.0+ + 4.0Client+ + + + + + + + + Infra\Configurations\Multitouch_Win7_Forward.xml + + + + + + + + + + + + + + FeatureTests\ElementServices\MultiTouchTest.deployment + + + 4.0+ + 4.0Client+ + + + diff --git a/src/Test/ElementServices/FeatureTests/BuildSources/ElementServicesTest.csproj b/src/Test/ElementServices/FeatureTests/BuildSources/ElementServicesTest.csproj new file mode 100644 index 000000000..37e7793e3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/BuildSources/ElementServicesTest.csproj @@ -0,0 +1,856 @@ + + + ElementServicesTest + Library + false + $(DefineConstants);TARGET_NET3_5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/AssemblyInfo.cs b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/AssemblyInfo.cs new file mode 100644 index 000000000..1b0a7ce1b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/AssemblyInfo.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// This file specifies various assembly level attributes. +// + +using System; +using System.Security; + +[assembly:AllowPartiallyTrustedCallers] diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/BrowserApp.csproj b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/BrowserApp.csproj new file mode 100644 index 000000000..abb20997d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/BrowserApp.csproj @@ -0,0 +1,77 @@ + + + + + + + Client + ControllerBrowserApp + AnyCPU + winexe + FeatureTests\ElementServices + true + Internet + true + False + True + 1.0.0.%2a + + + $(WpfTest)\Common\clickoncetest.pfx + cd582af19e477ae94a53102e0453e71b3c592a80 + + + true + full + false + DEBUG;TRACE + 1 + + + false + true + TRACE + + + + + + + + + + + false + TestRuntime + {C2FE511F-B1BA-42E2-A24F-41F93926DE51} + + + + false + CoreTestsTrusted + {6D1A1BE6-D461-4726-A73E-DA7F0AAD1368} + + + + false + ElementServicesTest + {CA0FEFED-E08A-4eb6-AB82-E70AB81C931B} + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml new file mode 100644 index 000000000..f5d0e821b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml.cs b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml.cs new file mode 100644 index 000000000..ffc196cdb --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/BrowserApp/ControllerBrowserApp.xaml.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using Avalon.Test.CoreUI.Common; +using Microsoft.Test.TestTypes; + +namespace Avalon.Test.CoreUI.Common +{ + public partial class ControllerBrowserApp : Application + { + void AppStartup(object sender, StartupEventArgs e) + { + ApplicationController proxy = new ApplicationController(); + proxy.RunVariationLoop(); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml new file mode 100644 index 000000000..51749bf9f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml.cs b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml.cs new file mode 100644 index 000000000..9683b3f8b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/ControllerWpfApp.xaml.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using Avalon.Test.CoreUI.Common; +using Microsoft.Test.TestTypes; + +namespace Avalon.Test.CoreUI.Common +{ + public partial class ControllerWpfApp : Application + { + void AppStartup(object sender, StartupEventArgs e) + { + ApplicationController proxy = new ApplicationController(); + proxy.RunVariationLoop(); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/WpfApp.csproj b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/WpfApp.csproj new file mode 100644 index 000000000..b3436a397 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/WpfApp/WpfApp.csproj @@ -0,0 +1,17 @@ + + + ControllerWpfApp + winexe + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ControllerApplications/dirs.proj b/src/Test/ElementServices/FeatureTests/ControllerApplications/dirs.proj new file mode 100644 index 000000000..97b33a8e9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ControllerApplications/dirs.proj @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Directory.Build.props b/src/Test/ElementServices/FeatureTests/Directory.Build.props new file mode 100644 index 000000000..7516f266b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Directory.Build.props @@ -0,0 +1,7 @@ + + + + $(WpfTestBasePath)\ElementServices\FeatureTests\Trusted\CoreTestsTrusted.csproj + $(WpfFeatureTestBasePublishPath)\ElementServices + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/BuildSources/FreezablesTest.csproj b/src/Test/ElementServices/FeatureTests/Freezables/BuildSources/FreezablesTest.csproj new file mode 100644 index 000000000..3a993eaf7 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/BuildSources/FreezablesTest.csproj @@ -0,0 +1,39 @@ + + + FreezablesTest + Library + Library + false + + + + + + + + + + + + + + + + + + + + + + + Always + Always + Always + PreserveNewest + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/BoolModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/BoolModifier.cs new file mode 100644 index 000000000..7ce0d6281 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/BoolModifier.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked BooleanModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class BooleanModifier : System.Windows.Media.Animation.BooleanAnimationBase + { + //---------------------------------------------------------- + + public BooleanModifier ( ModifierController c, bool b ) + { + _controller = c; + _delta = b; + } + public BooleanModifier() + { + } + //---------------------------------------------------------- + public new BooleanModifier GetAsFrozen() + { + return (BooleanModifier)base.GetAsFrozen(); + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + BooleanModifier booleanModifier = (BooleanModifier)sourceFreezable; + + base.CloneCore(sourceFreezable); + _controller = booleanModifier._controller; + _delta = booleanModifier._delta; + } + //---------------------------------------------------------- + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + BooleanModifier booleanModifier = (BooleanModifier)sourceFreezable; + + base.GetAsFrozenCore(sourceFreezable); + _controller = booleanModifier._controller; + _delta = booleanModifier._delta; + } + //---------------------------------------------------------- + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + BooleanModifier booleanModifier = (BooleanModifier)sourceFreezable; + + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = booleanModifier._controller; + _delta = booleanModifier._delta; + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new BooleanModifier(); + } + + + protected override bool GetCurrentValueCore ( bool defaultOriginValue, bool baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if (!_controller.UsesBaseValue) + { + return _delta; + } + else + { + return (baseValue && _delta); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private bool _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ByteModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ByteModifier.cs new file mode 100644 index 000000000..e4390dc20 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ByteModifier.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked ByteModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class ByteModifier : System.Windows.Media.Animation.ByteAnimationBase + { + //---------------------------------------------------------- + + public ByteModifier ( ModifierController c, System.Byte d ) + { + _controller = c; + _delta = d; + } + protected ByteModifier() + { + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + ByteModifier byteModifier = (ByteModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = byteModifier._controller; + _delta = byteModifier._delta; + } + //---------------------------------------------------------- + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + ByteModifier byteModifier = (ByteModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = byteModifier._controller; + _delta = byteModifier._delta; + } + //---------------------------------------------------------- + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + ByteModifier byteModifier = (ByteModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = byteModifier._controller; + _delta = byteModifier._delta; + } + public new ByteModifier GetAsFrozen() + { + return (ByteModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new ByteModifier(); + } + + protected override System.Byte GetCurrentValueCore (System.Byte defaultOriginValue, System.Byte baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return (byte)(baseValue + _delta); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private System.Byte _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/CharModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/CharModifier.cs new file mode 100644 index 000000000..11475f85c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/CharModifier.cs @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked CharModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class CharModifier : System.Windows.Media.Animation.CharAnimationBase + { + //---------------------------------------------------------- + + public CharModifier ( ModifierController c, char d ) + { + _controller = c; + _delta = d; + } + protected CharModifier() + { + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + CharModifier charModifier = (CharModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = charModifier._controller; + _delta = charModifier._delta; + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + CharModifier charModifier = (CharModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = charModifier._controller; + _delta = charModifier._delta; + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + CharModifier charModifier = (CharModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = charModifier._controller; + _delta = charModifier._delta; + } + public new CharModifier GetAsFrozen() + { + return (CharModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new CharModifier(); + } + + protected override char GetCurrentValueCore(char defaultOriginValue, char baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if (!_controller.UsesBaseValue) + { + return _delta; + } + else + { + return (char)('a' + 'b'); + } + + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private char _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ColorModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ColorModifier.cs new file mode 100644 index 000000000..3dfeda065 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ColorModifier.cs @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked ColorModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class ColorModifier : System.Windows.Media.Animation.ColorAnimationBase + { + //---------------------------------------------------------- + + public ColorModifier ( ModifierController c, float da, float dr, float dg, float db ) + { + _controller = c; + _deltaA = da; + _deltaR = dr; + _deltaG = dg; + _deltaB = db; + } + protected ColorModifier() + { + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + ColorModifier colorModifier = (ColorModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = colorModifier._controller; + _deltaA = colorModifier._deltaA; + _deltaR = colorModifier._deltaR; + _deltaG = colorModifier._deltaG; + _deltaB = colorModifier._deltaB; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + ColorModifier colorModifier = (ColorModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = colorModifier._controller; + _deltaA = colorModifier._deltaA; + _deltaR = colorModifier._deltaR; + _deltaG = colorModifier._deltaG; + _deltaB = colorModifier._deltaB; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + ColorModifier colorModifier = (ColorModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = colorModifier._controller; + _deltaA = colorModifier._deltaA; + _deltaR = colorModifier._deltaR; + _deltaG = colorModifier._deltaG; + _deltaB = colorModifier._deltaB; + + } + public new ColorModifier GetAsFrozen() + { + return (ColorModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new ColorModifier(); + } + protected override System.Windows.Media.Color + GetCurrentValueCore(System.Windows.Media.Color defaultOriginValue, System.Windows.Media.Color baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if ( !_controller.UsesBaseValue ) + { + return System.Windows.Media.Color.FromScRgb ( _deltaA, _deltaR, _deltaG, _deltaB ); + } + else + { + return System.Windows.Media.Color.FromScRgb ( baseValue.ScA + _deltaA, baseValue.ScR + _deltaR, baseValue.ScG + _deltaG, baseValue.ScB + _deltaB ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private float _deltaA; + private float _deltaR; + private float _deltaG; + private float _deltaB; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DecimalModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DecimalModifier.cs new file mode 100644 index 000000000..f4a75eb9a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DecimalModifier.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked DecimalModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class DecimalModifier : System.Windows.Media.Animation.DecimalAnimationBase + { + //---------------------------------------------------------- + + public DecimalModifier ( ModifierController c, System.Decimal d ) + { + _controller = c; + _delta = d; + } + protected DecimalModifier() + { + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + DecimalModifier decimalModifier = (DecimalModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = decimalModifier._controller; + _delta = decimalModifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + DecimalModifier decimalModifier = (DecimalModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = decimalModifier._controller; + _delta = decimalModifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + DecimalModifier decimalModifier = (DecimalModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = decimalModifier._controller; + _delta = decimalModifier._delta; + + } + public new DecimalModifier GetAsFrozen() + { + return (DecimalModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new DecimalModifier(); + } + + protected override System.Decimal GetCurrentValueCore(System.Decimal defaultOriginValue, System.Decimal baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private System.Decimal _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DoubleModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DoubleModifier.cs new file mode 100644 index 000000000..78f3ad7db --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/DoubleModifier.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked DoubleModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class DoubleModifier : System.Windows.Media.Animation.DoubleAnimationBase + { + //---------------------------------------------------------- + + public DoubleModifier ( ModifierController c, double d ) + { + _controller = c; + _delta = d; + } + protected DoubleModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + DoubleModifier doubleModifier = (DoubleModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = doubleModifier._controller; + _delta = doubleModifier._delta; + + } + //---------------------------------------------------------- + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + DoubleModifier doubleModifier = (DoubleModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = doubleModifier._controller; + _delta = doubleModifier._delta; + + } + //---------------------------------------------------------- + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + DoubleModifier doubleModifier = (DoubleModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = doubleModifier._controller; + _delta = doubleModifier._delta; + + } + public new DoubleModifier GetAsFrozen() + { + return (DoubleModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new DoubleModifier(); + } + + protected override double GetCurrentValueCore (double defaultOriginValue, double baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/FloatModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/FloatModifier.cs new file mode 100644 index 000000000..59238435b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/FloatModifier.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked SingleModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class SingleModifier : System.Windows.Media.Animation.SingleAnimationBase + { + //---------------------------------------------------------- + + public SingleModifier ( ModifierController c, float d ) + { + _controller = c; + _delta = d; + } + protected SingleModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + SingleModifier singleModifier = (SingleModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = singleModifier._controller; + _delta = singleModifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + SingleModifier singleModifier = (SingleModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = singleModifier._controller; + _delta = singleModifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + SingleModifier singleModifier = (SingleModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = singleModifier._controller; + _delta = singleModifier._delta; + + } + public new SingleModifier GetAsFrozen() + { + return (SingleModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new SingleModifier(); + } + + protected override float GetCurrentValueCore (float defaultOriginValue, float baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private float _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/IntModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/IntModifier.cs new file mode 100644 index 000000000..5d4c8fd83 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/IntModifier.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked Int32Modifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class Int32Modifier : System.Windows.Media.Animation.Int32AnimationBase + { + //---------------------------------------------------------- + + public Int32Modifier ( ModifierController c, int d ) + { + _controller = c; + _delta = d; + } + protected Int32Modifier() + { + } + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + Int32Modifier int32Modifier = (Int32Modifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = int32Modifier._controller; + _delta = int32Modifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int32Modifier int32Modifier = (Int32Modifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = int32Modifier._controller; + _delta = int32Modifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int32Modifier int32Modifier = (Int32Modifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = int32Modifier._controller; + _delta = int32Modifier._delta; + + } + public new Int32Modifier GetAsFrozen() + { + return (Int32Modifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new Int32Modifier(); + } + + protected override int GetCurrentValueCore (int defaultOriginValue, int baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private int _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/LongModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/LongModifier.cs new file mode 100644 index 000000000..4cb2ec5ba --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/LongModifier.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked Int64Modifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class Int64Modifier : System.Windows.Media.Animation.Int64AnimationBase + { + //---------------------------------------------------------- + + public Int64Modifier ( ModifierController c, long d ) + { + _controller = c; + _delta = d; + } + protected Int64Modifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + Int64Modifier int64Modifier = (Int64Modifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = int64Modifier._controller; + _delta = int64Modifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int64Modifier int64Modifier = (Int64Modifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = int64Modifier._controller; + _delta = int64Modifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int64Modifier int64Modifier = (Int64Modifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = int64Modifier._controller; + _delta = int64Modifier._delta; + + } + public new Int64Modifier GetAsFrozen() + { + return (Int64Modifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new Int64Modifier(); + } + + + protected override long GetCurrentValueCore (long defaultOriginValue, long baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private long _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MatrixModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MatrixModifier.cs new file mode 100644 index 000000000..d8b7c2bec --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MatrixModifier.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked MatrixModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class MatrixModifier : System.Windows.Media.Animation.MatrixAnimationBase + { + //---------------------------------------------------------- + + public MatrixModifier ( ModifierController c, double M11, double M12, double M21, double M22, double OffsetX, double OffsetY ) + { + _controller = c; + _M11 = M11; + _M12 = M12; + _M21 = M21; + _M22 = M22; + _OffsetX = OffsetX; + _OffsetY = OffsetY; + } + + + protected MatrixModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + MatrixModifier matrixModifier = (MatrixModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = matrixModifier._controller; + _M11 = matrixModifier._M11; + _M12 = matrixModifier._M12; + _M21 = matrixModifier._M21; + _M22 = matrixModifier._M22; + _OffsetX = matrixModifier._OffsetX; + _OffsetY = matrixModifier._OffsetY; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + MatrixModifier matrixModifier = (MatrixModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = matrixModifier._controller; + _M11 = matrixModifier._M11; + _M12 = matrixModifier._M12; + _M21 = matrixModifier._M21; + _M22 = matrixModifier._M22; + _OffsetX = matrixModifier._OffsetX; + _OffsetY = matrixModifier._OffsetY; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + MatrixModifier matrixModifier = (MatrixModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = matrixModifier._controller; + _M11 = matrixModifier._M11; + _M12 = matrixModifier._M12; + _M21 = matrixModifier._M21; + _M22 = matrixModifier._M22; + _OffsetX = matrixModifier._OffsetX; + _OffsetY = matrixModifier._OffsetY; + + } + public new MatrixModifier GetAsFrozen() + { + return (MatrixModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new MatrixModifier(); + } + + protected override System.Windows.Media.Matrix GetCurrentValueCore(System.Windows.Media.Matrix defaultOriginValue, System.Windows.Media.Matrix baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if ( !_controller.UsesBaseValue ) + { + return new System.Windows.Media.Matrix(_M11, _M12, _M21, _M22, _OffsetX, _OffsetY); + } + else + { + return new System.Windows.Media.Matrix (baseValue.M11 + _M11, baseValue.M12 + _M12, + baseValue.M21 + _M21, baseValue.M22 + _M22, baseValue.OffsetX + _OffsetX, baseValue.OffsetY + _OffsetY); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _M11; + private double _M12; + private double _M21; + private double _M22; + private double _OffsetX; + private double _OffsetY; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ModifierController.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ModifierController.cs new file mode 100644 index 000000000..ce1e84164 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ModifierController.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Common part of all the test Modifiers + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // Unfortunately I cannot use inheritance to factor out all the commonalities + // between different Modifiers I use in testing IAnimatable. So I am using delegation. + // This class to be hooked in every Modifier used for IAnimatable property & rendering + // testing + + public class ModifierController + { + //---------------------------------------------------------- + + public void SetDefaultParentTimeline ( System.Windows.Media.Animation.Timeline tml ) + { + _timeline = tml; + } + + //---------------------------------------------------------- + + public System.Windows.Media.Animation.Timeline + Timeline { get { return _timeline; } } + public bool UsesBaseValue { get { return _usesBase; } set { _usesBase = value; } } + + //---------------------------------------------------------- + + private System.Windows.Media.Animation.Timeline _timeline; + private bool _usesBase; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MyFreezable.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MyFreezable.cs new file mode 100644 index 000000000..41952cfeb --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/MyFreezable.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: MyFreezable + + * + ************************************************************/ +using System; + +//------------------------------------------------------------------ +namespace Microsoft.Test.ElementServices.Freezables.Objects +{ + //-------------------------------------------------------------- + /* + //This object is created to provide more granular testings as failures are clearly realted to Freezable + //logic, and not influenced by misuse of the framework or core code + */ + public class MyFreezable : System.Windows.Freezable + { + //-------------------------------- + public MyFreezable() + { + } + + //-------------------------------- + public MyFreezable(System.Windows.Freezable ChObj) + { + FreezableObj = ChObj; + } + + //-------------------------------- + public System.Windows.Freezable FreezableObj + { + get + { + ReadPreamble(); + return _changeableObj; + } + set + { + if (_changeableObj != value) + { + WritePreamble(); + OnFreezablePropertyChanged(_changeableObj, value); + _changeableObj = value; + WritePostscript(); + } + } + } + + //-------------------------------- + protected override bool FreezeCore(bool IsChecking) + { + return System.Windows.Freezable.Freeze(_changeableObj, IsChecking); + } + + //-------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + MyFreezable myFreezable = (MyFreezable)sourceFreezable; + base.CloneCore(sourceFreezable); + _changeableObj = myFreezable._changeableObj; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + MyFreezable myFreezable = (MyFreezable)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _changeableObj = myFreezable._changeableObj; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + MyFreezable myFreezable = (MyFreezable)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _changeableObj = myFreezable._changeableObj; + + } + public new MyFreezable GetAsFrozen() + { + return (MyFreezable)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new MyFreezable(); + } + + //-------------------------------- + private System.Windows.Freezable _changeableObj; + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Point3DModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Point3DModifier.cs new file mode 100644 index 000000000..169f9cf7f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Point3DModifier.cs @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked Point3DModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class Point3DModifier : System.Windows.Media.Animation.Point3DAnimationBase + { + //---------------------------------------------------------- + + public Point3DModifier ( ModifierController c, double dx, double dy, double dz ) + { + _controller = c; + _deltaX = dx; + _deltaY = dy; + _deltaZ = dz; + } + + protected Point3DModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + Point3DModifier point3DModifier = (Point3DModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = point3DModifier._controller; + _deltaX = point3DModifier._deltaX; + _deltaY = point3DModifier._deltaY; + _deltaZ = point3DModifier._deltaZ; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Point3DModifier point3DModifier = (Point3DModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = point3DModifier._controller; + _deltaX = point3DModifier._deltaX; + _deltaY = point3DModifier._deltaY; + _deltaZ = point3DModifier._deltaZ; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Point3DModifier point3DModifier = (Point3DModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = point3DModifier._controller; + _deltaX = point3DModifier._deltaX; + _deltaY = point3DModifier._deltaY; + _deltaZ = point3DModifier._deltaZ; + + } + public new Point3DModifier GetAsFrozen() + { + return (Point3DModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new Point3DModifier(); + } + + + protected override System.Windows.Media.Media3D.Point3D + GetCurrentValueCore (System.Windows.Media.Media3D.Point3D defaultOriginValue, System.Windows.Media.Media3D.Point3D baseValue , System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return new System.Windows.Media.Media3D.Point3D ( _deltaX, _deltaY, _deltaZ ); + } + else + { + return new System.Windows.Media.Media3D.Point3D ( baseValue.X + _deltaX, baseValue.Y + _deltaY, baseValue.Z + _deltaZ ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _deltaX; + private double _deltaY; + private double _deltaZ; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PointModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PointModifier.cs new file mode 100644 index 000000000..8fd48a71d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PointModifier.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked PointModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class PointModifier : System.Windows.Media.Animation.PointAnimationBase + { + //---------------------------------------------------------- + + public PointModifier ( ModifierController c, double dx, double dy ) + { + _controller = c; + _deltaX = dx; + _deltaY = dy; + } + protected PointModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + PointModifier pointModifier = (PointModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = pointModifier._controller; + _deltaX = pointModifier._deltaX; + _deltaY = pointModifier._deltaY; + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + PointModifier pointModifier = (PointModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = pointModifier._controller; + _deltaX = pointModifier._deltaX; + _deltaY = pointModifier._deltaY; + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + PointModifier pointModifier = (PointModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = pointModifier._controller; + _deltaX = pointModifier._deltaX; + _deltaY = pointModifier._deltaY; + } + public new PointModifier GetAsFrozen() + { + return (PointModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new PointModifier(); + } + protected override System.Windows.Point + GetCurrentValueCore(System.Windows.Point defaultOriginValue, System.Windows.Point baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if ( !_controller.UsesBaseValue ) + { + return new System.Windows.Point ( _deltaX, _deltaY ); + } + else + { + return new System.Windows.Point ( baseValue.X + _deltaX, baseValue.Y + _deltaY ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _deltaX; + private double _deltaY; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PredefinedObjects.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PredefinedObjects.cs new file mode 100644 index 000000000..bb7801173 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/PredefinedObjects.cs @@ -0,0 +1,1362 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Factory of predefined objects + + * + ************************************************************/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Modifiers; + + +namespace Microsoft.Test.ElementServices.Freezables.Objects +{ + /********************************************************************************** + * CLASS: PredefinedObjects + **********************************************************************************/ + public class PredefinedObjects + { + #region Private Data + private static string s_jpegFile = "BORG.jpg"; + #endregion + + + //---------------------------------------------------------- + // + + + #region Public and Protected Members + /****************************************************************************** + * Function: MakeValue + ******************************************************************************/ + public static object MakeValue (PropertyInfo p) + { + return MakeTypeNameValue (p.PropertyType.ToString (), true); + } + + /****************************************************************************** + * Function: MakeValue + ******************************************************************************/ + public static object MakeValue (Type t) + { + return MakeTypeNameValue(t.FullName.ToString(), true); + } + + /****************************************************************************** + * Function: MakeSecondValue + ******************************************************************************/ + public static object MakeSecondValue(Type t) + { + return MakeTypeNameValue(t.FullName.ToString(), false); + } + + + /****************************************************************************** + * Function: MakeTypeNameValue + ******************************************************************************/ + private static object MakeTypeNameValue(string name, bool firstOption) + { + switch (name) + { + case "System.Boolean": + { + return (firstOption) ? true : false; + } + + case "System.Char": + { + return '0'; + } + + case "System.Single" : + { + return (firstOption) ? Convert.ToSingle(true):Convert.ToSingle(false); + } + + case "System.Int32" : + { + return (firstOption) ? 0 : 2; + } + case "System.Int32[]": + { + System.Int32[] retval = new System.Int32[1]; + + return (firstOption) ? retval[0] = 2 : retval[0] = 1; + } + case "System.Double": + { + return (firstOption) ? 0.4 : 0.3; + } + case "System.Double[]": + { + System.Double[] retval = new System.Double[1]; + + return (firstOption) ? retval[0] = 0.4 : retval[0] = 0.3; + } + case "System.String": + { + return (firstOption) ? "":"a"; + } + + case "System.Byte": + { + return Convert.ToByte("0", System.Globalization.CultureInfo.InvariantCulture); + } + + case "System.Byte[]": + { + System.Byte[] retval = new System.Byte[1]; + retval[0] = Convert.ToByte("10", System.Globalization.CultureInfo.InvariantCulture); + return retval; + } + case "System.Decimal": + { + return Convert.ToDecimal("0", System.Globalization.CultureInfo.InvariantCulture); + } + + case "System.Int16": + { + return Convert.ToInt16("0", System.Globalization.CultureInfo.InvariantCulture); + } + + case "System.Int64": + { + return Convert.ToInt64("0", System.Globalization.CultureInfo.InvariantCulture); + } + + case "System.IntPtr" : + { + return IntPtr.Zero; + } + case "System.Object": + { + return new System.Object(); + } + case "System.TimeSpan": + { + return new System.TimeSpan(0, 0, 1); + } + + case "System.UInt16[]": + { + System.UInt16[] retval = new System.UInt16[1]; + + retval[0] = Convert.ToUInt16("0", System.Globalization.CultureInfo.InvariantCulture); + return retval; + } + case "System.Uri": + { + System.Uri retval = new System.Uri(s_jpegFile, UriKind.RelativeOrAbsolute); + return retval; + } + case "System.Windows.DependencyProperty": + { + System.Windows.DependencyObject dobj = new System.Windows.DependencyObject(); + return null;//System.Windows.DependencyProperty.FromName("ChangeableTest", dobj.GetType()); + } + + case "System.Windows.DependencyObject": + { + + return new System.Windows.DependencyObject(); + } + case "System.Windows.Vector" : + { + return (firstOption) ? new System.Windows.Vector(1.2, 3.7) : new System.Windows.Vector(1.3, 3.8); + } + case "System.Windows.Vector[]": + { + System.Windows.Vector[] retval = new System.Windows.Vector[1]; + + return (firstOption) ? retval[0] = new System.Windows.Vector(1.2, 3.7) : retval[0] = new System.Windows.Vector(1.3, 3.8); + } + + case "System.Windows.Media.BrushMappingMode" : + { + return (firstOption) ? System.Windows.Media.BrushMappingMode.RelativeToBoundingBox : System.Windows.Media.BrushMappingMode.Absolute ; + } + case "System.Windows.Media.Stretch" : + { + return (firstOption) ? System.Windows.Media.Stretch.Fill : System.Windows.Media.Stretch.None; + } + case "System.Windows.Media.HorizontalAlignment" : + { + return (firstOption) ? System.Windows.Media.AlignmentX.Left : System.Windows.Media.AlignmentX.Right; + } + case "System.Windows.Media.VerticalAlignment" : + { + return (firstOption) ? System.Windows.Media.AlignmentY.Top : System.Windows.Media.AlignmentY.Bottom; + } + + case "System.Windows.Media.TileMode" : + { + return (firstOption) ? System.Windows.Media.TileMode.None : System.Windows.Media.TileMode.Tile; + } + case "System.Windows.Media.ColorInterpolationMode" : + { + return (firstOption) ? System.Windows.Media.ColorInterpolationMode.SRgbLinearInterpolation : System.Windows.Media.ColorInterpolationMode.ScRgbLinearInterpolation; + } + case "System.Windows.Media.GradientSpreadMethod" : + { + return (firstOption) ? System.Windows.Media.GradientSpreadMethod.Pad : System.Windows.Media.GradientSpreadMethod.Reflect; + } + + case "System.Windows.Point" : + { + return (firstOption) ? new System.Windows.Point(10.0, 20.0) : new System.Windows.Point(10.1, 20.1); + } + case "System.Windows.Point[]": + { + System.Windows.Point[] retval = new System.Windows.Point[1]; + retval[0] = new System.Windows.Point (10.0, 20.0); + return retval; + } + + case "System.Windows.Size": + { + return firstOption ? new System.Windows.Size(50.0, 70.0) : new System.Windows.Size(50.1, 70.1); + } + + case "System.Windows.Rect": + { + return firstOption ? new System.Windows.Rect(10.0, 20.0, 50.0, 70.0) : new System.Windows.Rect(10.1, 20.0, 50.1, 70.0); + } + case "System.Windows.FrameworkContentElement": + { + return new System.Windows.FrameworkContentElement(); + } + case "System.Windows.FrameworkElement": + { + return new System.Windows.Controls.Button(); + } + case "System.Windows.FrameworkTemplate": + { + return new System.Windows.Controls.ControlTemplate(); + } + + case "System.Windows.Media.Color": + { + return firstOption ? System.Windows.Media.Color.FromScRgb(0.8f, 0.7f, 0.5f, 0.1f) : System.Windows.Media.Color.FromScRgb(0.9f, 0.8f, 0.6f, 0.2f); + } + case "System.Windows.Media.Color[]": + { + System.Windows.Media.Color[] retval = new System.Windows.Media.Color[1]; + + return firstOption ? retval[0] = System.Windows.Media.Color.FromScRgb(0.8f, 0.7f, 0.5f, 0.1f) : retval[0] = System.Windows.Media.Color.FromScRgb(0.9f, 0.8f, 0.6f, 0.2f); + } + + case "System.Windows.Color[]": + { + System.Windows.Media.Color[] retval = new System.Windows.Media.Color[1]; + + retval[0] = System.Windows.Media.Color.FromScRgb (0.8f, 0.7f, 0.5f, 0.1f); + return retval; + } + case "System.Windows.Media.Drawing": + { + return new System.Windows.Media.DrawingGroup (); + } + case "System.Windows.Media.Matrix": + { + return firstOption ? new System.Windows.Media.Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) : new System.Windows.Media.Matrix(2.0, 0.0, 0.0, 1.0, 0.0, 0.0); + } + case "System.Windows.Media.Transform": + { + return new System.Windows.Media.TranslateTransform (17.0, 3.0); + } + case "System.Windows.Media.Transform[]": + { + System.Windows.Media.Transform[] retval = new System.Windows.Media.Transform[1]; + retval[0] = new System.Windows.Media.TranslateTransform (17.0, 3.0); + return retval; + } + case "System.Windows.Media.Brush": + { + return new System.Windows.Media.SolidColorBrush (System.Windows.Media.Color.FromScRgb (0.7f, 0.55f, 1.0f, 0.1f)); + } + + case "System.Windows.Media.GeometryCombineMode": + { + return (firstOption) ? System.Windows.Media.GeometryCombineMode.Union : System.Windows.Media.GeometryCombineMode.Intersect; + } + + case "System.Windows.Media.FillRule": + { + return firstOption ? System.Windows.Media.FillRule.EvenOdd : System.Windows.Media.FillRule.Nonzero; + } + case "System.Windows.Media.Pen" : + { + System.Windows.Media.SolidColorBrush scb = new System.Windows.Media.SolidColorBrush (System.Windows.Media.Color.FromScRgb (1f, 0.1f, 1.0f, 0.7f)); + return new System.Windows.Media.Pen(scb, 2.0); + } + case "System.Windows.Media.PenLineCap" : + { + return (firstOption) ? System.Windows.Media.PenLineCap.Flat : System.Windows.Media.PenLineCap.Round; + } + case "System.Windows.Media.PenLineJoin" : + { + return (firstOption) ? System.Windows.Media.PenLineJoin.Miter : System.Windows.Media.PenLineJoin.Round; + } + + case "System.Windows.Media.Geometry" : + { + System.Windows.Media.TranslateTransform tt = new System.Windows.Media.TranslateTransform (17.0, 3.0); + return new System.Windows.Media.EllipseGeometry (new System.Windows.Point(10.0,10.0), 20.0, 150.0, tt); + } + case "System.Windows.Media.Geometry[]": + { + System.Windows.Media.Geometry[] retval = new System.Windows.Media.Geometry[1]; + retval[0] = new System.Windows.Media.EllipseGeometry (new System.Windows.Rect (10.0, 20.0, 150.0, 90.0)); + return retval; + } + case "System.Windows.Media.GradientStop": + { + return new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.7f, 0.55f, 1.0f, 0.1f), 0.0); + } + case "System.Windows.Media.GradientStop[]": + { + System.Windows.Media.GradientStop[] retval = new System.Windows.Media.GradientStop[1]; + + retval[0] = new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.7f, 0.55f, 1.0f, 0.1f), 0.0); + return retval; + } + + case "System.Windows.Media.GradientStopCollection": + { + System.Windows.Media.GradientStopCollection retval = new System.Windows.Media.GradientStopCollection (); + + retval.Add (new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.7f, 1.0f, 0.0f, 0.1f), 0.0)); + retval.Add (new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.2f, 0.0f, 1.0f, 0.7f), 1.0)); + return retval; + } + + case "System.Windows.Media.PathSegmentCollection": + { + return MakePathSegmentCollection (); + } + + case "System.Windows.Media.PathSegment": + { + return new System.Windows.Media.LineSegment (new System.Windows.Point (10.0, 20.0), true); + } + case "System.Windows.Media.PathSegment[]": + { + System.Windows.Media.PathSegment[] retval = new System.Windows.Media.PathSegment[1]; + retval[0] = new System.Windows.Media.LineSegment (new System.Windows.Point (10.0, 20.0), true); + return retval; + } + case "System.Windows.Media.PathFigureCollection": + { + System.Windows.Media.PathFigureCollection retval = new System.Windows.Media.PathFigureCollection (); + + retval.Add (new System.Windows.Media.PathFigure (new System.Windows.Point(0, 0), MakePathSegmentCollection (), false)); + return retval; + } + + case "System.Windows.Media.PathFigure": + { + return new System.Windows.Media.PathFigure(new System.Windows.Point(0, 0), MakePathSegmentCollection(), false); + } + + case "System.Windows.Media.PathFigure[]": + { + System.Windows.Media.PathFigure[] retval = new System.Windows.Media.PathFigure[1]; + + retval[0] = new System.Windows.Media.PathFigure(new System.Windows.Point(0, 0), MakePathSegmentCollection(), false); + return retval; + } + case "System.Windows.Media.PathGeometry" : + { + System.Windows.Media.PathFigure[] tmp = new System.Windows.Media.PathFigure[1]; + + tmp[0] = new System.Windows.Media.PathFigure(new System.Windows.Point(0, 0), MakePathSegmentCollection(), false); + return new System.Windows.Media.PathGeometry(tmp); + } + case "System.Windows.PointCollection": + { + return MakePointCollection(); + } + + case "System.Collections.ICollection": + { + return null; + } + case "System.Windows.Media.ColorContext": + { + return new System.Windows.Media.ColorContext(System.Windows.Media.PixelFormats.Bgra32); + } + case "System.Windows.Media.PixelFormat": + { + return System.Windows.Media.PixelFormats.Pbgra32; + } + case "System.IO.Stream": + { + try + { + return new FileStream(s_jpegFile, FileMode.Open, FileAccess.Read, FileShare.Read); + } + catch (System.IO.IOException e) + { + GlobalLog.LogEvidence("Images on av-image could not be accesssed: {0}", e.Message); + return null; + } + } + case "System.Windows.Length": + { + return 3.0; + } + case "System.Windows.Thickness": + { + return new System.Windows.Thickness(3.0); + } + case "System.Windows.Media.Imaging.CodecInfo": + { + System.Windows.Media.Imaging.JpegBitmapEncoder ie = new System.Windows.Media.Imaging.JpegBitmapEncoder(); + return ie.CodecInfo; + } + case "System.Windows.Media.Imaging.BitmapCacheOption": + { + return System.Windows.Media.Imaging.BitmapCacheOption.Default; + } + case "System.Windows.Media.Imaging.BitmapCreateOptions": + { + return System.Windows.Media.Imaging.BitmapCreateOptions.None; + } + case "System.Windows.Media.Imaging.BitmapPalette": + { + List colors = new List(); + colors.Add(System.Windows.Media.Color.FromScRgb(0.7f, 0.5f, 0.3f, 0.1f)); + colors.Add(System.Windows.Media.Color.FromScRgb(0.1f, 0.3f, 0.5f, 0.7f)); + return new System.Windows.Media.Imaging.BitmapPalette(colors); + } + + case "System.Windows.Media.Media3D.Geometry3D": + { + //Geometry3D is an abstact class, so use MeshGeometry3D instead + return new System.Windows.Media.Media3D.MeshGeometry3D(); + } + case "System.Windows.Media.Media3D.Quaternion": + { + return new System.Windows.Media.Media3D.Quaternion (0.0, 1.0, 2.0, 3.0); + } + case "System.Windows.Media.Media3D.Material": + { + return new System.Windows.Media.Media3D.DiffuseMaterial(); + } + + case "System.Windows.Media.Media3D.Model3D": + { + return new System.Windows.Media.Media3D.AmbientLight(); + } + + case "System.Windows.Media.Media3D.Model3D[]": + { + System.Windows.Media.Media3D.Model3D[] retval = new System.Windows.Media.Media3D.Model3D[1]; + + retval[0] = new System.Windows.Media.Media3D.AmbientLight(); + return retval; + } + + case "System.Windows.Media.Media3D.Point3D": + { + return new System.Windows.Media.Media3D.Point3D(1.0, 2.0, 3.0); + } + + case "System.Windows.Media.Media3D.Point3D[]": + { + System.Windows.Media.Media3D.Point3D[] retval = new System.Windows.Media.Media3D.Point3D[1]; + + retval[0] = new System.Windows.Media.Media3D.Point3D(1.0, 2.0, 3.0); + return retval; + } + + case "System.Windows.Media.Media3D.Vector3D": + { + return new System.Windows.Media.Media3D.Vector3D (100.0, 200.0, 3.0); + } + case "System.Windows.Media.Media3D.Vector3D[]": + { + System.Windows.Media.Media3D.Vector3D[] retval = new System.Windows.Media.Media3D.Vector3D[1]; + retval[0] = new System.Windows.Media.Media3D.Vector3D(100.0, 200.0, 3.0); + return retval; + } + case "System.Windows.Media.Media3D.Matrix3D": + { + return new System.Windows.Media.Media3D.Matrix3D (0.5, 1.2, 1.1, 0.0, 0.5, 1.2, 1.1, 0.0, 0.5, 1.2, 1.1, 0.0, 0.5, 1.2, 1.1, 0.0); + } + + case "System.Windows.Media.Media3D.Transform3D": + { + return new System.Windows.Media.Media3D.TranslateTransform3D (new System.Windows.Media.Media3D.Vector3D (10.0, 20.0, 3.0)); + } + case "System.Windows.Media.Media3D.Transform3D[]": + { + System.Windows.Media.Media3D.Transform3D[] retval = new System.Windows.Media.Media3D.Transform3D[1]; + + retval[0] = new System.Windows.Media.Media3D.TranslateTransform3D (new System.Windows.Media.Media3D.Vector3D (10.0, 20.0, 3.0)); + return retval; + } + + case "System.Windows.Media.Media3D.MeshGeometry3D": + { + return new System.Windows.Media.Media3D.MeshGeometry3D (); + } + case "System.Windows.Media.Imaging.BitmapCodecInfo": + { + Stream imageStream = new System.IO.FileStream (s_jpegFile, FileMode.Open, FileAccess.Read, FileShare.Read); + System.Windows.Media.Imaging.BitmapDecoder dec = System.Windows.Media.Imaging.BitmapDecoder.Create(imageStream, System.Windows.Media.Imaging.BitmapCreateOptions.None, System.Windows.Media.Imaging.BitmapCacheOption.Default); + System.Windows.Media.Imaging.BitmapCodecInfo ci = dec.CodecInfo; + imageStream.Close(); + return ci; + } + + case "System.Windows.Media.Imaging.BitmapSource": + { + try + { + Stream imageStream = new FileStream(s_jpegFile, FileMode.Open, FileAccess.Read, FileShare.Read); + System.Windows.Media.Imaging.BitmapSource bsrc = System.Windows.Media.Imaging.BitmapFrame.Create(imageStream); + + return bsrc; + } + catch (System.IO.IOException e) + { + GlobalLog.LogEvidence("Images on av-image could not be accesssed: {0}", e.Message); + return null; + } + } + case "System.Windows.Media.Imaging.BitmapSizeOptions": + { + return System.Windows.Media.Imaging.BitmapSizeOptions.FromWidthAndHeight(100, 100); + } + + case "System.Windows.Media.Imaging.Rotation": + { + return System.Windows.Media.Imaging.Rotation.Rotate0; + } + + case "System.Windows.Int32Rect" : + { + return new System.Windows.Int32Rect(0, 0, 100, 100); + } + + case "System.Windows.Media.Animation.AnimationEffect": + { + // + return null; + } + case "System.Windows.Media.Animation.BooleanKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteBooleanKeyFrame(true); + } + case "System.Windows.Media.Animation.BooleanKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteBooleanKeyFrame [] bkf = new System.Windows.Media.Animation.DiscreteBooleanKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteBooleanKeyFrame(true); + return bkf; + } + case "System.Windows.Media.Animation.ByteKeyFrame": + { + return new System.Windows.Media.Animation.LinearByteKeyFrame(Convert.ToByte("1", System.Globalization.CultureInfo.InvariantCulture)); + } + case "System.Windows.Media.Animation.ByteKeyFrame[]": + { + System.Windows.Media.Animation.LinearByteKeyFrame [] retval = new System.Windows.Media.Animation.LinearByteKeyFrame[1]; + retval[0] = new System.Windows.Media.Animation.LinearByteKeyFrame(Convert.ToByte("1", System.Globalization.CultureInfo.InvariantCulture)); + return retval; + } + case "System.Windows.Media.Animation.CharKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteCharKeyFrame('a'); + } + case "System.Windows.Media.Animation.CharKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteCharKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteCharKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteCharKeyFrame('a'); + return bkf; + } + case "System.Windows.Media.Animation.Clock": + { + System.Windows.Media.Animation.DoubleAnimation timeline = new System.Windows.Media.Animation.DoubleAnimation(); + return timeline.CreateClock(); + } + case "System.Windows.Media.Animation.ClockGroup": + { + System.Windows.Media.Animation.ParallelTimeline timeline = new System.Windows.Media.Animation.ParallelTimeline(); + System.Windows.Media.Animation.ClockGroup cg = timeline.CreateClock(); + return cg; + } + case "System.Windows.Media.Animation.ClockController": + { + System.Windows.Media.Animation.DoubleAnimation timeline = new System.Windows.Media.Animation.DoubleAnimation(); + System.Windows.Media.Animation.Clock clock = timeline.CreateClock(); + return clock.Controller; + } + case "System.Windows.Media.Animation.ColorKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteColorKeyFrame(System.Windows.Media.Color.FromScRgb(1.0f, 0.2f, 0.2f, 0.4f)); + } + case "System.Windows.Media.Animation.ColorKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteColorKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteColorKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteColorKeyFrame(System.Windows.Media.Color.FromScRgb(1.0f, 0.2f, 0.2f, 0.4f)); + return bkf; + } + case "System.Windows.Media.Animation.DecimalKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteDecimalKeyFrame(Convert.ToDecimal("0", System.Globalization.CultureInfo.InvariantCulture)); + } + case "System.Windows.Media.Animation.DecimalKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteDecimalKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteDecimalKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteDecimalKeyFrame(Convert.ToDecimal("0", System.Globalization.CultureInfo.InvariantCulture)); + return bkf; + } + case "System.Windows.Media.Animation.DoubleKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteDoubleKeyFrame(2.0); + } + case "System.Windows.Media.Animation.DoubleKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteDoubleKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteDoubleKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteDoubleKeyFrame(2.0); + return bkf; + } + case "System.Windows.Media.Animation.HandoffBehavior": + { + return System.Windows.Media.Animation.HandoffBehavior.Compose; + } + case "System.Windows.Media.Animation.Int16KeyFrame": + { + return new System.Windows.Media.Animation.DiscreteInt16KeyFrame(Convert.ToInt16("0", System.Globalization.CultureInfo.InvariantCulture)); + } + case "System.Windows.Media.Animation.Int16KeyFrame[]": + { + System.Windows.Media.Animation.DiscreteInt16KeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteInt16KeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteInt16KeyFrame(Convert.ToInt16("0", System.Globalization.CultureInfo.InvariantCulture)); + return bkf; + } + case "System.Windows.Media.Animation.Int32KeyFrame": + { + return new System.Windows.Media.Animation.DiscreteInt32KeyFrame(0); + } + case "System.Windows.Media.Animation.Int32KeyFrame[]": + { + System.Windows.Media.Animation.DiscreteInt32KeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteInt32KeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteInt32KeyFrame(0); + return bkf; + } + case "System.Windows.Media.Animation.Int64KeyFrame": + { + return new System.Windows.Media.Animation.DiscreteInt64KeyFrame(Convert.ToInt64("0", System.Globalization.CultureInfo.InvariantCulture)); + } + case "System.Windows.Media.Animation.Int64KeyFrame[]": + { + System.Windows.Media.Animation.DiscreteInt64KeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteInt64KeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteInt64KeyFrame(Convert.ToInt64("0", System.Globalization.CultureInfo.InvariantCulture)); + return bkf; + } + case "System.Windows.Media.Animation.MatrixKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteMatrixKeyFrame(new System.Windows.Media.Matrix(1.0, 1.0, 2.0, 2.0, 1.0, 1.0)); + } + case "System.Windows.Media.Animation.MatrixKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteMatrixKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteMatrixKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteMatrixKeyFrame(new System.Windows.Media.Matrix(1.0, 1.0, 2.0, 2.0, 1.0, 1.0)); + return bkf; + } + case "System.Windows.Media.Animation.ObjectKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteObjectKeyFrame(new object()); + } + case "System.Windows.Media.Animation.ObjectKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteObjectKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteObjectKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteObjectKeyFrame(new object()); + return bkf; + } + case "System.Windows.Media.Animation.Point3DKeyFrame": + { + return new System.Windows.Media.Animation.DiscretePoint3DKeyFrame(); + } + case "System.Windows.Media.Animation.Point3DKeyFrame[]": + { + System.Windows.Media.Animation.DiscretePoint3DKeyFrame[] bkf = new System.Windows.Media.Animation.DiscretePoint3DKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscretePoint3DKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.PointKeyFrame": + { + return new System.Windows.Media.Animation.DiscretePointKeyFrame(); + } + case "System.Windows.Media.Animation.PointKeyFrame[]": + { + System.Windows.Media.Animation.DiscretePointKeyFrame[] bkf = new System.Windows.Media.Animation.DiscretePointKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscretePointKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.QuaternionKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteQuaternionKeyFrame(); + } + case "System.Windows.Media.Animation.QuaternionKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteQuaternionKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteQuaternionKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteQuaternionKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.RectKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteRectKeyFrame(); + } + case "System.Windows.Media.Animation.RectKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteRectKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteRectKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteRectKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.Rotation3DKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteRotation3DKeyFrame(); + } + case "System.Windows.Media.Animation.Rotation3DKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteRotation3DKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteRotation3DKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteRotation3DKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.SingleKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteSingleKeyFrame(); + } + case "System.Windows.Media.Animation.SingleKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteSingleKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteSingleKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteSingleKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.SizeKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteSizeKeyFrame(); + } + case "System.Windows.Media.Animation.SizeKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteSizeKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteSizeKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteSizeKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.StringKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteStringKeyFrame(); + } + case "System.Windows.Media.Animation.StringKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteStringKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteStringKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteStringKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.Storyboard": + { + return new System.Windows.Media.Animation.Storyboard(); + } + case "System.Windows.Media.Animation.ThicknessKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteThicknessKeyFrame(new System.Windows.Thickness(3.0)); + } + case "System.Windows.Media.Animation.ThicknessKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteThicknessKeyFrame [] tkf = new System.Windows.Media.Animation.DiscreteThicknessKeyFrame[1]; + tkf[0] = new System.Windows.Media.Animation.DiscreteThicknessKeyFrame(new System.Windows.Thickness(3.0)); + return tkf; + } + case "System.Windows.Media.Animation.TimeSeekOrigin": + { + return System.Windows.Media.Animation.TimeSeekOrigin.BeginTime; + } + case "System.Windows.Media.Animation.Vector3DKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteVector3DKeyFrame(); + } + case "System.Windows.Media.Animation.Vector3DKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteVector3DKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteVector3DKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteVector3DKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.VectorKeyFrame": + { + return new System.Windows.Media.Animation.DiscreteVectorKeyFrame(); + } + case "System.Windows.Media.Animation.VectorKeyFrame[]": + { + System.Windows.Media.Animation.DiscreteVectorKeyFrame[] bkf = new System.Windows.Media.Animation.DiscreteVectorKeyFrame[1]; + bkf[0] = new System.Windows.Media.Animation.DiscreteVectorKeyFrame(); + return bkf; + } + case "System.Windows.Media.Animation.KeySpline": + { + return new System.Windows.Media.Animation.KeySpline(0.1, 0.2, 0.3, 0.4); + } + + case "System.Windows.Media.Animation.KeyTime": + { + return System.Windows.Media.Animation.KeyTime.FromTimeSpan(new System.TimeSpan(0,0,0,0,4000)); + } + + case "System.Windows.Media.Animation.FillBehavior": + { + return System.Windows.Media.Animation.FillBehavior.Stop; + } + + case "System.Windows.Media.Animation.PathAnimationSource": + { + return System.Windows.Media.Animation.PathAnimationSource.Angle; + } + + case "System.Windows.Media.Animation.ParallelTimeline" : + { + return new System.Windows.Media.Animation.ParallelTimeline(); + } + + case "System.Windows.Media.Animation.PointAnimationBase": + { + return new PointModifier (new ModifierController (), 7.5, 13.2); + } + + case "System.Windows.Media.Animation.SizeAnimationBase": + { + return new SizeModifier (new ModifierController (), 7.5, 13.2); + } + case "System.Windows.Media.Animation.BooleanAnimationBase": + { + return (firstOption) ? new BooleanModifier(new ModifierController(), true) : new BooleanModifier(new ModifierController(), false); + } + case "System.Windows.Media.Animation.ByteAnimationBase": + { + return new ByteModifier(new ModifierController(), Convert.ToByte("0", System.Globalization.CultureInfo.InvariantCulture)); + } + case "System.Windows.Media.Animation.CharAnimationBase": + { + return new CharModifier(new ModifierController(), 'a'); + } + + case "System.Windows.Media.Animation.DecimalAnimationBase": + { + return new DecimalModifier(new ModifierController(), 7.5m); + } + + case "System.Windows.Media.Animation.DoubleAnimationBase": + { + return new DoubleModifier (new ModifierController (), 7.5); + } + case "System.Windows.Media.Animation.SingleAnimationBase": + { + return new SingleModifier(new ModifierController(), 7.5f); + } + + case "System.Windows.Media.Animation.Int32AnimationBase": + { + return new Int32Modifier(new ModifierController(), 1); + } + case "System.Windows.Media.Animation.Int64AnimationBase": + { + return new Int64Modifier(new ModifierController(), 1); + } + case "System.Windows.Media.Animation.Int16AnimationBase": + { + return new Int16Modifier(new ModifierController(), 1); + } + case "System.Windows.Media.Animation.ColorAnimationBase": + { + return new ColorModifier (new ModifierController (), 0.2f, 0.1f, 0.1f, 0.1f); + } + case "System.Windows.Media.Animation.MatrixAnimationBase": + { + return new MatrixModifier (new ModifierController (), 1.1, 0.2, 0.1, 2.0, 0.3, 0.4); + } + case "System.Windows.Media.Animation.RectAnimationBase": + { + return new RectModifier (new ModifierController (), 7.5, 13.2, 12.4, 66.7); + } + case "System.Windows.Media.Animation.SlipBehavior": + { + return System.Windows.Media.Animation.SlipBehavior.Grow; + } + case "System.Windows.Media.Animation.StringAnimationBase": + { + return new StringModifier(new ModifierController(), "a"); + } + case "System.Windows.Media.Animation.VectorAnimationBase": + { + return new VectorModifier(new ModifierController(), 7.5, 13.2); + } + case "System.Windows.Media.Animation.Point3DAnimationBase": + { + return new Point3DModifier (new ModifierController (), 7.5, 13.2, 12.4); + } + case "System.Windows.Media.Animation.Timeline": + { + return new System.Windows.Media.Animation.DoubleAnimation(); + } + case "System.Windows.Media.Animation.Timeline[]": + { + System.Windows.Media.Animation.Timeline[] timeline = new System.Windows.Media.Animation.Timeline[1]; + timeline[0] = new System.Windows.Media.Animation.DoubleAnimation(); + return timeline; + } + case "System.Windows.Media.Animation.Vector3DAnimationBase": + { + return new Vector3DModifier (new ModifierController (), 7.5, 13.2, 12.4); + } + case "System.Windows.Media.TextEffect": + { + return new System.Windows.Media.TextEffect(); + } + case "System.Windows.Media.TextEffect[]": + { + System.Windows.Media.TextEffect [] retval = new System.Windows.Media.TextEffect[1]; + retval[0] = new System.Windows.Media.TextEffect(); + return retval; + } + case "System.Windows.Duration": + { + return (firstOption) ? new System.Windows.Duration(TimeSpan.FromSeconds(0)):new System.Windows.Duration(TimeSpan.FromSeconds(1)); + } + case "System.Windows.Media.Media3D.Rotation3D": + { + return new System.Windows.Media.Media3D.AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(20, 30, 40), 50); + } + case "System.Windows.Media.Animation.RepeatBehavior": + { + return (firstOption) ? new System.Windows.Media.Animation.RepeatBehavior(TimeSpan.FromSeconds(1)):new System.Windows.Media.Animation.RepeatBehavior(2); + } + default: + { + GlobalLog.LogStatus ("************* Do not know how to make object for " + name); + return null; + } + } + } + + + + //---------------------------------------------------------- + public static System.Windows.Media.PathSegmentCollection MakePathSegmentCollection () + { + System.Windows.Media.PathSegmentCollection retval = new System.Windows.Media.PathSegmentCollection (); + + retval.Add (new System.Windows.Media.LineSegment (new System.Windows.Point (10.0, 20.0), false)); + retval.Add (new System.Windows.Media.LineSegment (new System.Windows.Point (100.0, 20.0), true)); + return retval; + } + //---------------------------------------------------------- + public static System.Windows.Media.PointCollection MakePointCollection() + { + // 6 points will do both for PolyQuadratic and PolyCubic Beziers + System.Windows.Media.PointCollection retval = new System.Windows.Media.PointCollection(); + + retval.Add(new System.Windows.Point(0.0, 0.0)); + retval.Add(new System.Windows.Point(10.0, 0.0)); + retval.Add(new System.Windows.Point(0.0, 10.0)); + retval.Add(new System.Windows.Point(0.0, 0.0)); + retval.Add(new System.Windows.Point(10.0, 0.0)); + retval.Add(new System.Windows.Point(0.0, 10.0)); + return retval; + } + + public static object MakeCollection (string name) + { + switch (name) + { + case "System.Windows.Media.Animation.BooleanKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteBooleanKeyFrame bokf = new System.Windows.Media.Animation.DiscreteBooleanKeyFrame(); + System.Windows.Media.Animation.BooleanKeyFrameCollection retval = new System.Windows.Media.Animation.BooleanKeyFrameCollection(); + + retval.Add(bokf); + return retval; + } + + case "System.Windows.Media.Animation.ByteKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteByteKeyFrame bykf = new System.Windows.Media.Animation.DiscreteByteKeyFrame(); + System.Windows.Media.Animation.ByteKeyFrameCollection retval = new System.Windows.Media.Animation.ByteKeyFrameCollection(); + + retval.Add(bykf); + return retval; + } + + case "System.Windows.Media.Animation.CharKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteCharKeyFrame chkf = new System.Windows.Media.Animation.DiscreteCharKeyFrame(); + System.Windows.Media.Animation.CharKeyFrameCollection retval = new System.Windows.Media.Animation.CharKeyFrameCollection(); + + retval.Add(chkf); + return retval; + } + case "System.Windows.Media.Animation.ClockCollection": + { + System.Windows.Media.Animation.ParallelTimeline timeline = new System.Windows.Media.Animation.ParallelTimeline(); + System.Windows.Media.Animation.ClockGroup cg = timeline.CreateClock(); + System.Windows.Media.Animation.ClockCollection cc = cg.Children; + return cc; + } + + + case "System.Windows.Media.Animation.ColorKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteColorKeyFrame cokf = new System.Windows.Media.Animation.DiscreteColorKeyFrame(); + System.Windows.Media.Animation.ColorKeyFrameCollection retval = new System.Windows.Media.Animation.ColorKeyFrameCollection(); + + retval.Add(cokf); + return retval; + } + + case "System.Windows.Media.Animation.DecimalKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteDecimalKeyFrame dekf = new System.Windows.Media.Animation.DiscreteDecimalKeyFrame(); + System.Windows.Media.Animation.DecimalKeyFrameCollection retval = new System.Windows.Media.Animation.DecimalKeyFrameCollection(); + + retval.Add(dekf); + return retval; + } + + case "System.Windows.Media.Animation.DoubleKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteDoubleKeyFrame dukf = new System.Windows.Media.Animation.DiscreteDoubleKeyFrame(); + System.Windows.Media.Animation.DoubleKeyFrameCollection retval = new System.Windows.Media.Animation.DoubleKeyFrameCollection(); + + retval.Add(dukf); + return retval; + } + + case "System.Windows.Media.Animation.Int16KeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteInt16KeyFrame i16kf = new System.Windows.Media.Animation.DiscreteInt16KeyFrame(); + System.Windows.Media.Animation.Int16KeyFrameCollection retval = new System.Windows.Media.Animation.Int16KeyFrameCollection(); + + retval.Add(i16kf); + return retval; + } + + case "System.Windows.Media.Animation.Int32KeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteInt32KeyFrame i32kf = new System.Windows.Media.Animation.DiscreteInt32KeyFrame(); + System.Windows.Media.Animation.Int32KeyFrameCollection retval = new System.Windows.Media.Animation.Int32KeyFrameCollection(); + + retval.Add(i32kf); + return retval; + } + + case "System.Windows.Media.Animation.Int64KeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteInt64KeyFrame i64kf = new System.Windows.Media.Animation.DiscreteInt64KeyFrame(); + System.Windows.Media.Animation.Int64KeyFrameCollection retval = new System.Windows.Media.Animation.Int64KeyFrameCollection(); + + retval.Add(i64kf); + return retval; + } + + case "System.Windows.Media.Animation.MatrixKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteMatrixKeyFrame mkf = new System.Windows.Media.Animation.DiscreteMatrixKeyFrame(); + System.Windows.Media.Animation.MatrixKeyFrameCollection retval = new System.Windows.Media.Animation.MatrixKeyFrameCollection(); + + retval.Add(mkf); + return retval; + } + + case "System.Windows.Media.Animation.ObjectKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteObjectKeyFrame okf = new System.Windows.Media.Animation.DiscreteObjectKeyFrame(); + System.Windows.Media.Animation.ObjectKeyFrameCollection retval = new System.Windows.Media.Animation.ObjectKeyFrameCollection(); + + retval.Add(okf); + return retval; + } + + case "System.Windows.Media.Animation.PointKeyFrameCollection": + { + System.Windows.Media.Animation.DiscretePointKeyFrame pkf = new System.Windows.Media.Animation.DiscretePointKeyFrame(); + System.Windows.Media.Animation.PointKeyFrameCollection retval = new System.Windows.Media.Animation.PointKeyFrameCollection(); + + retval.Add(pkf); + return retval; + } + + case "System.Windows.Media.Animation.Point3DKeyFrameCollection": + { + System.Windows.Media.Animation.DiscretePoint3DKeyFrame p3dkf = new System.Windows.Media.Animation.DiscretePoint3DKeyFrame(); + System.Windows.Media.Animation.Point3DKeyFrameCollection retval = new System.Windows.Media.Animation.Point3DKeyFrameCollection(); + + retval.Add(p3dkf); + return retval; + } + + case "System.Windows.Media.Animation.QuaternionKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteQuaternionKeyFrame qkf = new System.Windows.Media.Animation.DiscreteQuaternionKeyFrame(); + System.Windows.Media.Animation.QuaternionKeyFrameCollection retval = new System.Windows.Media.Animation.QuaternionKeyFrameCollection(); + + retval.Add(qkf); + return retval; + } + + case "System.Windows.Media.Animation.RectKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteRectKeyFrame rkf = new System.Windows.Media.Animation.DiscreteRectKeyFrame(); + System.Windows.Media.Animation.RectKeyFrameCollection retval = new System.Windows.Media.Animation.RectKeyFrameCollection(); + + retval.Add(rkf); + return retval; + } + + case "System.Windows.Media.Animation.Rotation3DKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteRotation3DKeyFrame r3dkf = new System.Windows.Media.Animation.DiscreteRotation3DKeyFrame(); + System.Windows.Media.Animation.Rotation3DKeyFrameCollection retval = new System.Windows.Media.Animation.Rotation3DKeyFrameCollection(); + + retval.Add(r3dkf); + return retval; + } + + + case "System.Windows.Media.Animation.SingleKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteSingleKeyFrame sikf = new System.Windows.Media.Animation.DiscreteSingleKeyFrame(); + System.Windows.Media.Animation.SingleKeyFrameCollection retval = new System.Windows.Media.Animation.SingleKeyFrameCollection(); + + retval.Add(sikf); + return retval; + } + + case "System.Windows.Media.Animation.SizeKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteSizeKeyFrame szkf = new System.Windows.Media.Animation.DiscreteSizeKeyFrame(); + System.Windows.Media.Animation.SizeKeyFrameCollection retval = new System.Windows.Media.Animation.SizeKeyFrameCollection(); + + retval.Add(szkf); + return retval; + } + + case "System.Windows.Media.Animation.StringKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteStringKeyFrame stkf = new System.Windows.Media.Animation.DiscreteStringKeyFrame(); + System.Windows.Media.Animation.StringKeyFrameCollection retval = new System.Windows.Media.Animation.StringKeyFrameCollection(); + + retval.Add(stkf); + return retval; + } + case "System.Windows.Media.Animation.ThicknessKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteThicknessKeyFrame thkf = new System.Windows.Media.Animation.DiscreteThicknessKeyFrame(); + System.Windows.Media.Animation.ThicknessKeyFrameCollection retval = new System.Windows.Media.Animation.ThicknessKeyFrameCollection(); + + retval.Add(thkf); + return retval; + } + + case "System.Windows.Media.Animation.TimelineCollection": + { + System.Windows.Media.Animation.ParallelTimeline ptl = new System.Windows.Media.Animation.ParallelTimeline(); + System.Windows.Media.Animation.TimelineCollection retval = new System.Windows.Media.Animation.TimelineCollection(); + + retval.Add(ptl); + return retval; + } + + case "System.Windows.Media.Animation.VectorKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteVectorKeyFrame vkf = new System.Windows.Media.Animation.DiscreteVectorKeyFrame(); + System.Windows.Media.Animation.VectorKeyFrameCollection retval = new System.Windows.Media.Animation.VectorKeyFrameCollection(); + + retval.Add(vkf); + return retval; + } + + case "System.Windows.Media.Animation.Vector3DKeyFrameCollection": + { + System.Windows.Media.Animation.DiscreteVector3DKeyFrame v3dkf = new System.Windows.Media.Animation.DiscreteVector3DKeyFrame(new System.Windows.Media.Media3D.Vector3D(1.0,2.0,3.0)); + System.Windows.Media.Animation.Vector3DKeyFrameCollection retval = new System.Windows.Media.Animation.Vector3DKeyFrameCollection(); + + retval.Add(v3dkf); + return retval; + } + + case "System.Windows.Media.DoubleCollection": + { + System.Windows.Media.DoubleCollection retval = new System.Windows.Media.DoubleCollection(); + retval.Add(2.0); + return retval; + } + case "System.Windows.Media.Int32Collection": + { + System.Windows.Media.Int32Collection retval = new System.Windows.Media.Int32Collection(); + retval.Add(1); + return retval; + } + + case "System.Windows.Media.TransformCollection": + { + System.Windows.Media.TransformCollection retval = new System.Windows.Media.TransformCollection (); + + retval.Add (new System.Windows.Media.TranslateTransform (17.0, 3.0)); + retval.Add (new System.Windows.Media.RotateTransform (30.0)); + return retval; + } + + case "System.Windows.Media.GeometryGroup": + { + System.Windows.Media.GeometryGroup retval = new System.Windows.Media.GeometryGroup(); + retval.Children.Add(new System.Windows.Media.EllipseGeometry(new System.Windows.Rect(10.0, 20.0, 150.0, 90.0))); + retval.Children.Add(new System.Windows.Media.EllipseGeometry(new System.Windows.Rect(20.0, 30.9, 150.1, 99.9))); + return retval; + } + + case "System.Windows.Media.CombinedGeometry": + { + System.Windows.Media.CombinedGeometry retval = new System.Windows.Media.CombinedGeometry( + System.Windows.Media.GeometryCombineMode.Xor, + new System.Windows.Media.EllipseGeometry(new System.Windows.Rect(10.0, 20.0, 150.0, 90.0)), + new System.Windows.Media.EllipseGeometry(new System.Windows.Rect(20.0, 30.9, 150.1, 99.9))); + return retval; + } + + case "System.Windows.Media.PathSegmentCollection": + { + return MakePathSegmentCollection (); + } + + case "System.Windows.Media.PathFigure": + { + return MakePathSegmentCollection (); + } + case "System.Windows.Media.PathFigureCollection": + { + System.Windows.Media.PathFigureCollection retval = new System.Windows.Media.PathFigureCollection (); + retval.Add(new System.Windows.Media.PathFigure(new System.Windows.Point(0, 0), MakePathSegmentCollection(), false)); + return retval; + } + case "System.Windows.Media.PathGeometry": + { + System.Windows.Media.PathFigureCollection retval = new System.Windows.Media.PathFigureCollection (); + + retval.Add(new System.Windows.Media.PathFigure(new System.Windows.Point(0, 0), MakePathSegmentCollection(), false)); + return retval; + } + case "System.Windows.Media.GradientStopCollection": + { + System.Windows.Media.GradientStopCollection retval = new System.Windows.Media.GradientStopCollection (); + + retval.Add (new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.7f, 1.0f, 0.0f, 0.1f), 0.0)); + retval.Add (new System.Windows.Media.GradientStop (System.Windows.Media.Color.FromScRgb (0.2f, 0.0f, 1.0f, 0.7f), 1.0)); + return retval; + } + case "System.Windows.Media.Media3D.Model3DCollection": + { + System.Windows.Media.Media3D.Model3DCollection retval = new System.Windows.Media.Media3D.Model3DCollection(); + // Model3D is an abstract class, so use AmbientLight instead + System.Windows.Media.Media3D.Model3D model3d = new System.Windows.Media.Media3D.AmbientLight(); + retval.Add(model3d); + return retval; + } + case "System.Windows.Media.Media3D.Model3DGroup": + { + System.Windows.Media.Media3D.Model3D[] model3d = new System.Windows.Media.Media3D.Model3D[1]; + + model3d[0] = new System.Windows.Media.Media3D.AmbientLight(); + System.Windows.Media.Media3D.Model3DGroup group = new System.Windows.Media.Media3D.Model3DGroup(); + group.Children = new System.Windows.Media.Media3D.Model3DCollection( model3d ); + return group; + } + + case "System.Windows.Media.Media3D.Transform3DCollection": + { + System.Windows.Media.Media3D.Transform3D[] tx3d = new System.Windows.Media.Media3D.Transform3D[1]; + + tx3d[0] = new System.Windows.Media.Media3D.TranslateTransform3D(new System.Windows.Media.Media3D.Vector3D(10.0, 20.0, 3.0)); + System.Windows.Media.Media3D.Transform3DCollection retval = new System.Windows.Media.Media3D.Transform3DCollection(); + retval.Add(tx3d[0]); + return retval; + } + case "System.Windows.Media.Media3D.Transform3DGroup": + { + System.Windows.Media.Media3D.Transform3D [] tx3d = new System.Windows.Media.Media3D.Transform3D[1]; + + tx3d[0] = new System.Windows.Media.Media3D.TranslateTransform3D(new System.Windows.Media.Media3D.Vector3D(10.0, 20.0, 3.0)); + System.Windows.Media.Media3D.Transform3DGroup group = new System.Windows.Media.Media3D.Transform3DGroup(); + group.Children = new System.Windows.Media.Media3D.Transform3DCollection(tx3d); + return group; + } + + // the below 3 cases can use the same data + case "System.Windows.Media.PolyBezierSegment": + case "System.Windows.Media.PolyLineSegment": + case "System.Windows.Media.PolyQuadraticBezierSegment": + { + System.Windows.Media.PointCollection retval = new System.Windows.Media.PointCollection(); + retval.Add(new System.Windows.Point(0.0, 0.0)); + retval.Add(new System.Windows.Point(10.0, 10.0)); + retval.Add(new System.Windows.Point(100.0, 100.0)); + retval.Add(new System.Windows.Point(50.0, 50.0)); + retval.Add(new System.Windows.Point(110.0, 110.0)); + retval.Add(new System.Windows.Point(150.0, 150.0)); + return retval; + } + case "System.Windows.PointCollection": + { + return MakePointCollection(); + } + + case "System.Windows.Media.Media3D.Point3DCollection": + { + System.Windows.Media.Media3D.Point3DCollection retval = new System.Windows.Media.Media3D.Point3DCollection(); + retval.Add(new System.Windows.Media.Media3D.Point3D(1.0, 2.0, 3.0)); + return retval; + } + + case "System.Windows.Media.TextEffectCollection": + { + System.Windows.Media.TextEffectCollection retval = new System.Windows.Media.TextEffectCollection(); + System.Windows.Media.TextEffect te = new System.Windows.Media.TextEffect(); + retval.Add(te); + return retval; + } + + case "System.Windows.Media.Media3D.Vector3DCollection": + { + System.Windows.Media.Media3D.Vector3DCollection retval = new System.Windows.Media.Media3D.Vector3DCollection(); + retval.Add(new System.Windows.Media.Media3D.Vector3D(100.0, 200.0, 3.0)); + return retval; + } + + case "System.Windows.Media.VectorCollection": + { + System.Windows.Media.VectorCollection retval = new System.Windows.Media.VectorCollection(); + retval.Add(new System.Windows.Vector(1.2, 3.7)); + return retval; + } + + default: + { + GlobalLog.LogEvidence ("************* Do not know how to make object collection for " + name); + return null; + } + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/RectModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/RectModifier.cs new file mode 100644 index 000000000..4940c2082 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/RectModifier.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked RectModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class RectModifier : System.Windows.Media.Animation.RectAnimationBase + { + //---------------------------------------------------------- + + public RectModifier ( ModifierController c, double dx, double dy, double dw, double dh ) + { + _controller = c; + _deltaX = dx; + _deltaY = dy; + _deltaW = dw; + _deltaH = dh; + } + protected RectModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + RectModifier rectModifier = (RectModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = rectModifier._controller; + _deltaX = rectModifier._deltaX; + _deltaY = rectModifier._deltaY; + _deltaW = rectModifier._deltaW; + _deltaH = rectModifier._deltaH; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + RectModifier rectModifier = (RectModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = rectModifier._controller; + _deltaX = rectModifier._deltaX; + _deltaY = rectModifier._deltaY; + _deltaW = rectModifier._deltaW; + _deltaH = rectModifier._deltaH; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + RectModifier rectModifier = (RectModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = rectModifier._controller; + _deltaX = rectModifier._deltaX; + _deltaY = rectModifier._deltaY; + _deltaW = rectModifier._deltaW; + _deltaH = rectModifier._deltaH; + + } + public new RectModifier GetAsFrozen() + { + return (RectModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new RectModifier(); + } + //---------------------------------------------------------- + + protected override System.Windows.Rect + GetCurrentValueCore(System.Windows.Rect defaultOriginValue, System.Windows.Rect baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if ( !_controller.UsesBaseValue ) + { + return new System.Windows.Rect ( _deltaX, _deltaY, _deltaW, _deltaH ); + } + else + { + return new System.Windows.Rect ( baseValue.X + _deltaX, baseValue.Y + _deltaY, baseValue.Width + _deltaW, baseValue.Height + _deltaH ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _deltaX; + private double _deltaY; + private double _deltaW; + private double _deltaH; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ShortModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ShortModifier.cs new file mode 100644 index 000000000..3de02a7d5 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/ShortModifier.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked Int16Modifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class Int16Modifier : System.Windows.Media.Animation.Int16AnimationBase + { + //---------------------------------------------------------- + + public Int16Modifier ( ModifierController c, short d ) + { + _controller = c; + _delta = d; + } + protected Int16Modifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + Int16Modifier int16Modifier = (Int16Modifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = int16Modifier._controller; + _delta = int16Modifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int16Modifier int16Modifier = (Int16Modifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = int16Modifier._controller; + _delta = int16Modifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Int16Modifier int16Modifier = (Int16Modifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = int16Modifier._controller; + _delta = int16Modifier._delta; + + } + public new Int16Modifier GetAsFrozen() + { + return (Int16Modifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new Int16Modifier(); + } + + + protected override short GetCurrentValueCore ( short defaultOriginValue, short baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return (short)(baseValue + _delta); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private short _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/SizeModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/SizeModifier.cs new file mode 100644 index 000000000..76bb081a4 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/SizeModifier.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked SizeModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class SizeModifier : System.Windows.Media.Animation.SizeAnimationBase + { + //---------------------------------------------------------- + + public SizeModifier ( ModifierController c, double dx, double dy ) + { + _controller = c; + _deltaX = dx; + _deltaY = dy; + } + + protected SizeModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + SizeModifier sizeModifier = (SizeModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = sizeModifier._controller; + _deltaX = sizeModifier._deltaX; + _deltaY = sizeModifier._deltaY; + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + SizeModifier sizeModifier = (SizeModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = sizeModifier._controller; + _deltaX = sizeModifier._deltaX; + _deltaY = sizeModifier._deltaY; + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + SizeModifier sizeModifier = (SizeModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = sizeModifier._controller; + _deltaX = sizeModifier._deltaX; + _deltaY = sizeModifier._deltaY; + } + public new SizeModifier GetAsFrozen() + { + return (SizeModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new SizeModifier(); + } + protected override System.Windows.Size + GetCurrentValueCore ( System.Windows.Size defaultOriginValue, System.Windows.Size baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return new System.Windows.Size ( _deltaX, _deltaY ); + } + else + { + return new System.Windows.Size ( baseValue.Width + _deltaX, baseValue.Height + _deltaY ); + } + } + + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _deltaX; + private double _deltaY; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/StringModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/StringModifier.cs new file mode 100644 index 000000000..7c9b97a3e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/StringModifier.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test-hooked StringModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class StringModifier : System.Windows.Media.Animation.StringAnimationBase + { + //---------------------------------------------------------- + + public StringModifier ( ModifierController c, string d ) + { + _controller = c; + _delta = d; + } + protected StringModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + StringModifier stringModifier = (StringModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = stringModifier._controller; + _delta = stringModifier._delta; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + StringModifier stringModifier = (StringModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = stringModifier._controller; + _delta = stringModifier._delta; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + StringModifier stringModifier = (StringModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = stringModifier._controller; + _delta = stringModifier._delta; + + } + public new StringModifier GetAsFrozen() + { + return (StringModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new StringModifier(); + } + + + protected override string GetCurrentValueCore(string defaultOriginValue, string baseValue, System.Windows.Media.Animation.AnimationClock clock ) + { + if ( !_controller.UsesBaseValue ) + { + return _delta; + } + else + { + return baseValue + _delta; + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private string _delta; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/TypeHelper.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/TypeHelper.cs new file mode 100644 index 000000000..d7415d295 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/TypeHelper.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: TypeHelper Class + + * + ************************************************************/ + +using System; +using System.Xml; +using System.Reflection; + + +namespace Microsoft.Test.ElementServices.Freezables.Objects +{ + //-------------------------------------------------------------- + + public class TypeHelper + { + public static bool IsDerivative(Type t, string name) + { + for (Type b = t.BaseType; b != null; b = b.BaseType) + { + if (b.ToString() == name) + { + return true; + } + } + return false; + } + + + //---------------------------------------------------------- + public static bool IsType(Type t, string checkedType) + { + return (t.ToString() == checkedType) ? true : false; + } + + public static bool IsFreezable(Type t) + { + return IsDerivative(t, "System.Windows.Freezable"); + } + + public static bool IsDependencyObject(Type t) + { + return IsDerivative(t, "System.Windows.DependencyObject"); + } + + public static bool IsMediaTimeline(Type t) + { + return (IsDerivative (t, "System.Windows.Media.MediaTimeline") || (t.ToString() == "System.Windows.Media.MediaTimeline")); + } + public static bool IsMedia3D(Type t) + { + return (t.ToString().StartsWith("System.Windows.Media.Media3D")); + } + + public static bool IsAnimatable(Type t) + { + return IsDerivative(t, "System.Windows.Media.Animation.Animatable"); + } + + public static bool IsAnimationCollection(Type t) + { + return IsDerivative(t, "System.Windows.Media.Animation.AnimationCollection"); + } + + // returns true if there are embedded freezable types; false otherwise + public static bool IsComplexChangeable(Type t) + { + // get the type's fields + System.Reflection.FieldInfo[] fi = t.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + + for (int i = 0; i < fi.Length; i++) + { + // check if any of the members are changeables + if (IsFreezable (fi[i].FieldType)) + { + return true; + } + } + return false; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Vector3DModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Vector3DModifier.cs new file mode 100644 index 000000000..7fc2d1054 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/Vector3DModifier.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked Vector3DModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + //-------------------------------------------------------------- + // The Freezable pattern is horribly violated by this class but I don't care + // since I am not testing interaction with Freezable yet. + + public class Vector3DModifier : System.Windows.Media.Animation.Vector3DAnimationBase + { + //---------------------------------------------------------- + + public Vector3DModifier ( ModifierController c, double dx, double dy, double dz ) + { + _controller = c; + _deltaX = dx; + _deltaY = dy; + _deltaZ = dz; + } + + protected Vector3DModifier() + { + } + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + Vector3DModifier vector3DModifier = (Vector3DModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = vector3DModifier._controller; + _deltaX = vector3DModifier._deltaX; + _deltaY = vector3DModifier._deltaY; + _deltaZ = vector3DModifier._deltaZ; + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Vector3DModifier vector3DModifier = (Vector3DModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = vector3DModifier._controller; + _deltaX = vector3DModifier._deltaX; + _deltaY = vector3DModifier._deltaY; + _deltaZ = vector3DModifier._deltaZ; + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + Vector3DModifier vector3DModifier = (Vector3DModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = vector3DModifier._controller; + _deltaX = vector3DModifier._deltaX; + _deltaY = vector3DModifier._deltaY; + _deltaZ = vector3DModifier._deltaZ; + } + public new Vector3DModifier GetAsFrozen() + { + return (Vector3DModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new Vector3DModifier(); + } + + + protected override System.Windows.Media.Media3D.Vector3D + GetCurrentValueCore(System.Windows.Media.Media3D.Vector3D defaultOriginValue, System.Windows.Media.Media3D.Vector3D baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if (!_controller.UsesBaseValue) + { + return new System.Windows.Media.Media3D.Vector3D ( _deltaX, _deltaY, _deltaZ ); + } + else + { + return new System.Windows.Media.Media3D.Vector3D ( baseValue.X + _deltaX, baseValue.Y + _deltaY, baseValue.Z + _deltaZ ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _deltaX; + private double _deltaY; + private double _deltaZ; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/VectorModifier.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/VectorModifier.cs new file mode 100644 index 000000000..7b6031b2f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/PredefinedObjects/VectorModifier.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test-hooked VectorModifier + + * + ************************************************************/ + +using System; + + +namespace Microsoft.Test.ElementServices.Freezables.Modifiers +{ + + public class VectorModifier : System.Windows.Media.Animation.VectorAnimationBase + { + //---------------------------------------------------------- + + public VectorModifier ( ModifierController c, double x, double y ) + { + _controller = c; + _x = x; + _y = y; + } + + protected VectorModifier() + { + } + + + //---------------------------------------------------------- + protected override void CloneCore(System.Windows.Freezable sourceFreezable) + { + VectorModifier vectorModifier = (VectorModifier)sourceFreezable; + base.CloneCore(sourceFreezable); + _controller = vectorModifier._controller; + _x = vectorModifier._x; + _y = vectorModifier._y; + + } + protected override void GetAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + VectorModifier vectorModifier = (VectorModifier)sourceFreezable; + base.GetAsFrozenCore(sourceFreezable); + _controller = vectorModifier._controller; + _x = vectorModifier._x; + _y = vectorModifier._y; + + } + protected override void GetCurrentValueAsFrozenCore(System.Windows.Freezable sourceFreezable) + { + VectorModifier vectorModifier = (VectorModifier)sourceFreezable; + base.GetCurrentValueAsFrozenCore(sourceFreezable); + _controller = vectorModifier._controller; + _x = vectorModifier._x; + _y = vectorModifier._y; + + } + public new VectorModifier GetAsFrozen() + { + return (VectorModifier)base.GetAsFrozen(); + } + protected override System.Windows.Freezable CreateInstanceCore() + { + return new VectorModifier(); + } + + + //---------------------------------------------------------- + + protected override System.Windows.Vector + GetCurrentValueCore(System.Windows.Vector defaultOriginValue, System.Windows.Vector baseValue, System.Windows.Media.Animation.AnimationClock clock) + { + if (!_controller.UsesBaseValue) + { + return new System.Windows.Vector ( _x, _y ); + } + else + { + return new System.Windows.Vector ( baseValue.X + _x, baseValue.Y + _y ); + } + } + + //---------------------------------------------------------- + + private ModifierController _controller; + private double _x; + private double _y; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Common/Utils/Result.cs b/src/Test/ElementServices/FeatureTests/Freezables/Common/Utils/Result.cs new file mode 100644 index 000000000..9cd52bfa4 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Common/Utils/Result.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2007 + * + * Program: Result class + * Author: + * + ************************************************************/ + +using System; +using System.Windows; +using System.Collections.Specialized; + + +namespace Microsoft.Test.ElementServices.Freezables.Utils +{ + /****************************************************************************** + * CLASS: Result + ******************************************************************************/ + public class Result + { + #region Result + + public Result() + { + failures = new StringCollection (); + passed = true; + } + + public StringCollection failures; + public bool passed; + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/25DPI.jpg b/src/Test/ElementServices/FeatureTests/Freezables/Data/25DPI.jpg new file mode 100644 index 000000000..552a15add Binary files /dev/null and b/src/Test/ElementServices/FeatureTests/Freezables/Data/25DPI.jpg differ diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/BORG.jpg b/src/Test/ElementServices/FeatureTests/Freezables/Data/BORG.jpg new file mode 100644 index 000000000..b24e6df0b Binary files /dev/null and b/src/Test/ElementServices/FeatureTests/Freezables/Data/BORG.jpg differ diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesBVT.xtc b/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesBVT.xtc new file mode 100644 index 000000000..5612d0ad0 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesBVT.xtc @@ -0,0 +1,168 @@ + +System.Windows.Media.Animation.Animatable +System.Windows.Media.Animation.KeySpline +System.Windows.Media.Animation.DoubleAnimationBase +System.Windows.Media.Animation.DoubleAnimationUsingPath +System.Windows.Media.Animation.MatrixAnimationBase +System.Windows.Media.Animation.MatrixAnimationUsingPath +System.Windows.Media.Animation.PointAnimationBase +System.Windows.Media.Animation.PointAnimationUsingPath +System.Windows.Media.PathSegment +System.Windows.Media.ArcSegment +System.Windows.Media.BezierSegment +System.Windows.Media.Brush +System.Windows.Media.CombinedGeometry +System.Windows.Media.Imaging.BitmapSource +System.Windows.Media.Drawing +System.Windows.Media.TileBrush +System.Windows.Media.DrawingBrush +System.Windows.Media.Geometry +System.Windows.Media.EllipseGeometry +System.Windows.Media.DoubleCollection +System.Windows.Media.GeometryGroup +System.Windows.Media.GradientBrush +System.Windows.Media.GradientStop +System.Windows.Media.GradientStopCollection +System.Windows.Media.LinearGradientBrush +System.Windows.Media.LineGeometry +System.Windows.Media.LineSegment +System.Windows.Media.Transform +System.Windows.Media.MatrixTransform +System.Windows.Media.PathFigure +System.Windows.Media.PathFigureCollection +System.Windows.Media.PathGeometry +System.Windows.Media.PathSegmentCollection +System.Windows.Media.Pen +System.Windows.Media.PointCollection +System.Windows.Media.PolyBezierSegment +System.Windows.Media.PolyLineSegment +System.Windows.Media.PolyQuadraticBezierSegment +System.Windows.Media.QuadraticBezierSegment +System.Windows.Media.RadialGradientBrush +System.Windows.Media.RectangleGeometry +System.Windows.Media.RotateTransform +System.Windows.Media.ScaleTransform +System.Windows.Media.SkewTransform +System.Windows.Media.SolidColorBrush +System.Windows.Media.TextEffect +System.Windows.Media.TextEffectCollection +System.Windows.Media.TransformGroup +System.Windows.Media.TransformCollection +System.Windows.Media.TranslateTransform +System.Windows.Media.VectorCollection +System.Windows.Media.Media3D.Point3DCollection +System.Windows.Media.Media3D.Vector3DCollection +System.Windows.Media.Animation.ColorAnimationBase +System.Windows.Media.Animation.DecimalAnimationBase +System.Windows.Media.Animation.Int16AnimationBase +System.Windows.Media.Animation.Int64AnimationBase +System.Windows.Media.Animation.Point3DAnimationBase +System.Windows.Media.Animation.RectAnimationBase +System.Windows.Media.Animation.SingleAnimationBase +System.Windows.Media.Animation.SizeAnimationBase +System.Windows.Media.Animation.VectorAnimationBase +System.Windows.Media.Animation.Vector3DAnimationBase +System.Windows.Media.Animation.DiscreteBooleanKeyFrame +System.Windows.Media.Animation.ByteKeyFrame +System.Windows.Media.Animation.DiscreteByteKeyFrame +System.Windows.Media.Animation.CharKeyFrame +System.Windows.Media.Animation.DiscreteCharKeyFrame +System.Windows.Media.Animation.ColorKeyFrame +System.Windows.Media.Animation.DiscreteColorKeyFrame +System.Windows.Media.Animation.DecimalKeyFrame +System.Windows.Media.Animation.DiscreteDecimalKeyFrame +System.Windows.Media.Animation.DoubleKeyFrame +System.Windows.Media.Animation.DiscreteDoubleKeyFrame +System.Windows.Media.Animation.Int16KeyFrame +System.Windows.Media.Animation.DiscreteInt16KeyFrame +System.Windows.Media.Animation.Int32KeyFrame +System.Windows.Media.Animation.DiscreteInt32KeyFrame +System.Windows.Media.Animation.Int64KeyFrame +System.Windows.Media.Animation.DiscreteInt64KeyFrame +System.Windows.Media.Animation.MatrixKeyFrame +System.Windows.Media.Animation.DiscreteMatrixKeyFrame +System.Windows.Media.Animation.PointKeyFrame +System.Windows.Media.Animation.DiscretePointKeyFrame +System.Windows.Media.Animation.Point3DKeyFrame +System.Windows.Media.Animation.DiscretePoint3DKeyFrame +System.Windows.Media.Animation.RectKeyFrame +System.Windows.Media.Animation.DiscreteRectKeyFrame +System.Windows.Media.Animation.SingleKeyFrame +System.Windows.Media.Animation.DiscreteSingleKeyFrame +System.Windows.Media.Animation.SizeKeyFrame +System.Windows.Media.Animation.DiscreteSizeKeyFrame +System.Windows.Media.Animation.StringKeyFrame +System.Windows.Media.Animation.DiscreteStringKeyFrame +System.Windows.Media.Animation.VectorKeyFrame +System.Windows.Media.Animation.DiscreteVectorKeyFrame +System.Windows.Media.Animation.Vector3DKeyFrame +System.Windows.Media.Animation.DiscreteVector3DKeyFrame +System.Windows.Media.Animation.BooleanAnimationBase +System.Windows.Media.Animation.BooleanAnimationUsingKeyFrames +System.Windows.Media.Animation.ByteAnimationUsingKeyFrames +System.Windows.Media.Animation.CharAnimationBase +System.Windows.Media.Animation.CharAnimationUsingKeyFrames +System.Windows.Media.Animation.ColorAnimationUsingKeyFrames +System.Windows.Media.Animation.DecimalAnimationUsingKeyFrames +System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames +System.Windows.Media.Animation.Int16AnimationUsingKeyFrames +System.Windows.Media.Animation.Int32AnimationUsingKeyFrames +System.Windows.Media.Animation.Int64AnimationUsingKeyFrames +System.Windows.Media.Animation.MatrixAnimationUsingKeyFrames +System.Windows.Media.Animation.PointAnimationUsingKeyFrames +System.Windows.Media.Animation.Point3DAnimationUsingKeyFrames +System.Windows.Media.Animation.RectAnimationUsingKeyFrames +System.Windows.Media.Animation.SingleAnimationUsingKeyFrames +System.Windows.Media.Animation.SizeAnimationUsingKeyFrames +System.Windows.Media.Animation.StringAnimationBase +System.Windows.Media.Animation.StringAnimationUsingKeyFrames +System.Windows.Media.Animation.VectorAnimationUsingKeyFrames +System.Windows.Media.Animation.Vector3DAnimationUsingKeyFrames +System.Windows.Media.Animation.BooleanKeyFrameCollection +System.Windows.Media.Animation.ByteKeyFrameCollection +System.Windows.Media.Animation.CharKeyFrameCollection +System.Windows.Media.Animation.ColorKeyFrameCollection +System.Windows.Media.Animation.DecimalKeyFrameCollection +System.Windows.Media.Animation.DoubleKeyFrameCollection +System.Windows.Media.Animation.Int16KeyFrameCollection +System.Windows.Media.Animation.Int32KeyFrameCollection +System.Windows.Media.Animation.Int64KeyFrameCollection +System.Windows.Media.Animation.MatrixKeyFrameCollection +System.Windows.Media.Animation.PointKeyFrameCollection +System.Windows.Media.Animation.Point3DKeyFrameCollection +System.Windows.Media.Animation.RectKeyFrameCollection +System.Windows.Media.Animation.SingleKeyFrameCollection +System.Windows.Media.Animation.SizeKeyFrameCollection +System.Windows.Media.Animation.StringKeyFrameCollection +System.Windows.Media.Animation.VectorKeyFrameCollection +System.Windows.Media.Animation.Vector3DKeyFrameCollection +System.Windows.Media.Animation.LinearByteKeyFrame +System.Windows.Media.Animation.LinearColorKeyFrame +System.Windows.Media.Animation.LinearDecimalKeyFrame +System.Windows.Media.Animation.LinearDoubleKeyFrame +System.Windows.Media.Animation.LinearInt16KeyFrame +System.Windows.Media.Animation.LinearInt32KeyFrame +System.Windows.Media.Animation.LinearInt64KeyFrame +System.Windows.Media.Animation.LinearPointKeyFrame +System.Windows.Media.Animation.LinearPoint3DKeyFrame +System.Windows.Media.Animation.LinearRectKeyFrame +System.Windows.Media.Animation.LinearSingleKeyFrame +System.Windows.Media.Animation.LinearSizeKeyFrame +System.Windows.Media.Animation.LinearVectorKeyFrame +System.Windows.Media.Animation.LinearVector3DKeyFrame +System.Windows.Media.Animation.SplineByteKeyFrame +System.Windows.Media.Animation.SplineColorKeyFrame +System.Windows.Media.Animation.SplineDecimalKeyFrame +System.Windows.Media.Animation.SplineDoubleKeyFrame +System.Windows.Media.Animation.SplineInt16KeyFrame +System.Windows.Media.Animation.SplineInt32KeyFrame +System.Windows.Media.Animation.SplineInt64KeyFrame +System.Windows.Media.Animation.SplinePointKeyFrame +System.Windows.Media.Animation.SplinePoint3DKeyFrame +System.Windows.Media.Animation.SplineRectKeyFrame +System.Windows.Media.Animation.SplineSingleKeyFrame +System.Windows.Media.Animation.SplineSizeKeyFrame +System.Windows.Media.Animation.SplineVectorKeyFrame +System.Windows.Media.Animation.SplineVector3DKeyFrame + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesPatterns.xtc b/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesPatterns.xtc new file mode 100644 index 000000000..720eecba9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Data/FreezablesPatterns.xtc @@ -0,0 +1,561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/PropertiesToSkip.xml b/src/Test/ElementServices/FeatureTests/Freezables/Data/PropertiesToSkip.xml new file mode 100644 index 000000000..80d0ebd0a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Data/PropertiesToSkip.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/Freezables/Data/insertrect.xml b/src/Test/ElementServices/FeatureTests/Freezables/Data/insertrect.xml new file mode 100644 index 000000000..c1b8c7171 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/Data/insertrect.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesBVT/FreezablesBVT.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesBVT/FreezablesBVT.cs new file mode 100644 index 000000000..d562c35a9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesBVT/FreezablesBVT.cs @@ -0,0 +1,418 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test freezable object + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Collections.Specialized; +using System.Windows; +using System.Xml; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; +using Microsoft.Test.ElementServices.Freezables.Objects; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\BVT + + /// 0 + /// + /// BVT tests for Freezables + /// + /// + + [Test(0, "Freezables.BVT", "FreezablesBVT", SupportFiles=@"FeatureTests\ElementServices\FreezablesBVT.xtc")] + + /********************************************************************************** + * CLASS: FreezablesBVT + **********************************************************************************/ + public class FreezablesBVT : AvalonTest + { + #region Test case members + + private bool _passed; + private StringCollection _failures; + private string _testName = ""; + private string _xtcFileName = ""; + + #endregion + + + #region Constructor + + [Variation("TestCopy", "FreezablesBVT.xtc", Keywords = "MicroSuite")] + [Variation("TestIsFreezable", "FreezablesBVT.xtc")] + [Variation("TestMakeUnfreezable", "FreezablesBVT.xtc", Keywords = "MicroSuite")] + + + /****************************************************************************** + * Function: FreezablesBVT Constructor + ******************************************************************************/ + // Input Parameters: + // FreezablesBVT.exe assembly TestName ScriptName + // (note: don't specify .dll in assembly) + // e.g.,: FreezablesBVT.exe PresentationCore TestCopy FreezablesBVT.xtc + public FreezablesBVT(string inputValue0, string inputValue1) + { + _testName = inputValue0; + _xtcFileName = inputValue1; + InitializeSteps += new TestStep(Initialize); + RunSteps += new TestStep(StartTestCase); + RunSteps += new TestStep(Verify); + } + + #endregion + + + #region Private Members + + /****************************************************************************** + * Function: Initialize + ******************************************************************************/ + /// + /// Sets global variables. + /// + /// Returns TestResult=True + private TestResult Initialize() + { + _failures = new StringCollection(); + _passed = true; + + return TestResult.Pass; + } + + /****************************************************************************** + * Function: StartTestCase + ******************************************************************************/ + /// + /// Carries out a series of basic Freezables tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult StartTestCase() + { + XmlDocument doc = new XmlDocument(); + + try + { + doc.Load(_xtcFileName); + } + catch (Exception) + { + throw new ApplicationException("Unable to load script file:" + _xtcFileName); + } + + XmlElement changeableTest = (XmlElement)doc["FreezablesTest"]; + if (changeableTest == null) + { + throw new ApplicationException("The script needs FreezablesTest element"); + } + for (XmlNode classNode = changeableTest["ClassName"]; classNode != null; classNode = classNode.NextSibling) + { + Assembly dll = typeof(UIElement).Assembly; + Type t = dll.GetType(classNode.InnerText); + + if (t == null) + { + _passed &= false; + _failures.Add(classNode.InnerText + ": invalid class in FreezablesBVT"); + GlobalLog.LogEvidence("FAIL:" + classNode.InnerText + "invalid class in Freezable.xtc"); + } + else + { + Test(t, _testName); + } + } + + return TestResult.Pass; + } + + /****************************************************************************** + * Function: Test + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// Name of the test to be executed. + /// + private void Test(Type t, string TestName) + { + if (TypeHelper.IsMediaTimeline (t)) + { // skip media data objects testing for now + // + return; + } + if (TypeHelper.IsMedia3D(t)) + { // skip Media3D objects testing for now + // + return; + } + + GlobalLog.LogEvidence(t.ToString ()); + + switch (TestName) + { + case "TestCopy": + TestCopy(t); + break; + + case "TestIsFreezable": + TestIsFreezable(t); + break; + + case "TestMakeUnfreezable": + TestMakeUnfreezable(t); + break; + + default: + throw new ApplicationException("Unknown TestName: " + TestName); + } + } + + /****************************************************************************** + * Function: CreateNewFreezable + ******************************************************************************/ + /// + /// Obtain a Freezable. + /// + /// The Type of the Freezable object to be tested. + /// an instance of the specified type + private System.Windows.Freezable CreateNewFreezable(Type t) + { + if (t.IsAbstract) + { + return null; + } + + System.Windows.Freezable retval = null; + ConstructorInfo[] ci = t.GetConstructors(); + + // for each constructor + for (int i = 0; i < ci.Length; i++) + { + try + { + ParameterInfo[] pi = ci[i].GetParameters(); + Object[] objects = new Object[pi.Length]; // the constructor arguments + + // for each parameter + for (int j = 0; j < pi.Length; j++) + { + if (j == pi[j].Position) // verify the position of the arguments + { + if (pi[j].ParameterType.FullName.ToString () == "System.Collections.ICollection" + || pi[j].ParameterType.FullName.StartsWith("System.Collections.Generic.IEnumerable")) + { + objects[j] = PredefinedObjects.MakeCollection (t.FullName.ToString ()); + if (objects[j] == null) + { + return null; + } + + } + else + { + objects[j] = PredefinedObjects.MakeValue (pi[j].ParameterType); + } + } + } + + MakeObjectIfSpecialCase(t, pi, objects); + System.Windows.Freezable obj = (System.Windows.Freezable)t.InvokeMember (null, BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, objects); + + if (obj != null) + { + retval = obj; + } + } + catch (System.Reflection.TargetInvocationException e) + { + if (!e.InnerException.ToString ().StartsWith ("System.ArgumentNullException")) + { + GlobalLog.LogEvidence(" !!! NewObject: Exception: {0}", e.InnerException.ToString ()); + } + + return null; + } + } + return retval; + } + + + /****************************************************************************** + * Function: MakeObjectIfSpecialCase + ******************************************************************************/ + /// + /// Create a Freezable object for special-case types. + /// + /// The Type of the Freezable object to be tested. + /// Parameter values. + /// Array of objects. + /// + private void MakeObjectIfSpecialCase(Type t, ParameterInfo[] pi, Object[] objects) + { + if (t.ToString() == "System.Windows.Media.Imaging.BitmapImage" && pi.Length == 10) + { + // The 8th parameter (stride) of BitmapImage constructor needs value stride = Width * BytePerPixel + // Ctor forImageData: + // (Int32 pixelWidth, Int32 pixelHeight, Double dpiX, Double dpiY, PixelFormat pixelFormat, BitmapPalette imagePalette, Byte[] pixels, Int32 stride, Int32Rect sourceRect, BitmapSizeOptions sizeOptions) + System.Windows.Media.PixelFormat p = (System.Windows.Media.PixelFormat)objects[4]; + objects[6] = new byte[32]; + objects[7] = (Int32)objects[0] * p.BitsPerPixel / 8; + } + else if (t.ToString() == "System.Windows.Media.Animation.KeySpline" && pi.Length == 2 && pi[0].ParameterType.FullName.ToString() == "System.Windows.Point" && pi[1].ParameterType.FullName.ToString() == "System.Windows.Point") + { + // For Keyspline, points must be betwen 0.0 and 1.0 + objects[0] = new Point(0.1, 0.2); + objects[1] = new Point(0.2, 0.7); + + } + else if (t.ToString() == "System.Windows.Media.Animation.Setter" && pi.Length == 3) + { + // For animation Setter, generic objects from PredefinesObject will not work. + objects[0] = new System.Windows.Media.LineGeometry(new Point(10, 10), new Point(20, 20)); //DependencyObject(); + objects[1] = System.Windows.Media.LineGeometry.StartPointProperty; + objects[2] = new System.Windows.Point(1.0, 2.0); + } + } + + + /****************************************************************************** + * Function: TestIsFreezable + ******************************************************************************/ + /// + /// Verify a Freezable object's IsFrozen property. + /// + /// The Type of the Freezable object tested. + /// + private void TestIsFreezable(Type t) + { + Freezable obj = CreateNewFreezable(t); + + if (obj != null) + { + // Test !IsFrozen property + if (obj.IsFrozen) + { + _passed &= false; + _failures.Add(t.ToString() + ": !IsFrozen is false"); + GlobalLog.LogEvidence("FAIL:" + t.ToString() + " !IsFrozen is false, expected true"); + } + } + } + + + /****************************************************************************** + * Function: TestMakeUnfreezable + ******************************************************************************/ + /// + /// Verify a Freezable object's IsFrozen property, after freezing it. + /// + /// The Type of the Freezable object tested. + /// + private void TestMakeUnfreezable(Type t) + { + // create an instance of this type + Freezable obj = CreateNewFreezable(t); + + if (obj != null && obj.CanFreeze) + { + obj.Freeze(); + + // Verify that !IsFrozen is false + if (!obj.IsFrozen) + { + _passed &= false; + _failures.Add(t.ToString() + ": !IsFrozen is true, expected false"); + GlobalLog.LogEvidence("FAIL:" + t.ToString() + " !IsFrozen true, expected false"); + } + } + } + + + /****************************************************************************** + * Function: TestCopy + ******************************************************************************/ + /// + /// Verify a Freezable object's IsFrozen property, after cloning it. + /// + /// The Type of the Freezable object tested. + /// + private void TestCopy(System.Type t) + { + // + if (t.ToString() == "System.Windows.Media.Imaging.BitmapSource+BitmapSourceNull") + { + // + return; + } + + // create an instance of this type + Freezable obj = CreateNewFreezable(t); + + if (obj!= null) + { + Freezable objCopy = obj.Clone() ; + if (objCopy.IsFrozen) + { + _passed &= false; + _failures.Add(t.ToString() + ": !IsFrozen is true, expeced false"); + GlobalLog.LogEvidence("FAIL:" + t.ToString() + " !IsFrozen true, expected false"); + } + // Skip Animation classes since + if (TypeHelper.IsAnimatable(t) || TypeHelper.IsAnimationCollection(t)) + { + return; + } + } + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// A TestResult, indicating whether the test passes or fails. + private TestResult Verify() + { + // report the failures all together + if (!_passed) + { + GlobalLog.LogEvidence("-------------------------------------------------"); + GlobalLog.LogEvidence("FAILURE REPORT"); + for (int i = 0; i < _failures.Count; i++) + { + GlobalLog.LogEvidence (_failures[i]); + } + } + + if (_passed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + + #endregion + } + +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/BrushCollectionTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/BrushCollectionTest.cs new file mode 100644 index 000000000..28ad079d4 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/BrushCollectionTest.cs @@ -0,0 +1,134 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: BrusheCollection Test + + * + ************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Media3D; +using System.Windows.Controls; +using System.Windows.Data; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + internal class BrushCollectionTest : FreezableCollectionTest + { + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal BrushCollectionTest() + { + _bogusCollection = new List(); + collection.Add(new SolidColorBrush()); + collection.Add(new LinearGradientBrush()); + _objects = new List(); + _objects.Add(new SolidColorBrush()); + _objects.Add(new LinearGradientBrush()); + + _bogusCollection.Add(10); + _bogusCollection.Add(new Point3D()); + _bogusCollection.Add(null); + _bogusCollection.Add(new Point()); + _bogusCollection.Add(new Vector3D()); + _bogusCollection.Add(new Matrix3D()); + _bogusCollection.Add(true); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override Microsoft.Test.ElementServices.Freezables.Utils.Result Perform() + { + TestDefaultConstructor(); + TestConstructorWith(464); + FreezableCollection coll = PopulateCollection(); + TestConstructorWith(coll); + TestAdd(_objects); + TestAddBadType(_bogusCollection); + TestAddFromAnotherThread(); + TestAddToFrozenCollection(); + TestChangedEvent(_objects); + TestClear(); + TestContains(); + TestCopyTo(); + TestCount(); + TestDataBinding(); + TestEnumerator(); + TestGetAsFrozen(); + TestGetCurrentValueAsFrozen(); + TestIndexOf(); + TestInsert(); + TestIsReadOnly(); + TestItem(); + TestRemove(); + TestRemoveAt(); + + return result; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override FreezableCollection PopulateCollection() + { + FreezableCollection coll = new FreezableCollection(); + coll.Add(new SolidColorBrush()); + coll.Add(new LinearGradientBrush()); + return coll; + } + //------------------------------------------- + internal override void TestDataBinding() + { + GlobalLog.LogStatus("Testing TestDataBinding for Brush..."); + // First do basic binding outside of a collection + Binding binding = new Binding(); + binding.Path = new PropertyPath("Height"); + Button button = new Button(); + button.Height = 23; + button.DataContext = button; + + SolidColorBrush scb = new SolidColorBrush(); + button.Tag = scb; + BindingOperations.SetBinding(scb, Brush.OpacityProperty, binding); + if (scb.Opacity != 23) + { + result.passed = false; + result.failures.Add("TestBinding fail for Brush. Expected opacity = 23, Actual: " + scb.Opacity); + GlobalLog.LogStatus("TestBinding fail for Brush. Expected opacity = 23, Actual: " + scb.Opacity); + } + Binding binding2 = new Binding(); + binding2.Path = new PropertyPath("Width"); + Button button2 = new Button(); + button2.Width = 345; + button2.DataContext = button2; + collection = PopulateCollection(); + button2.Tag = collection; + foreach (DependencyObject d in collection) + { + BindingOperations.SetBinding(d, Brush.OpacityProperty, binding2); + Brush brush = (Brush)d; + if (brush.Opacity != 345) + { + result.passed = false; + result.failures.Add("TestBinding fail for Brush. Expected opacity = 345, Actual: " + brush.Opacity); + GlobalLog.LogStatus("TestBinding fail for Brush. Expected opacity = 345, Actual: " + brush.Opacity); + } + // reset + brush.Opacity = 1; + } + } + + //--------------------------------------------- + private List _bogusCollection; + private List _objects; + } + } diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollectionTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollectionTest.cs new file mode 100644 index 000000000..e5fef9831 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollectionTest.cs @@ -0,0 +1,857 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: Base class for Freezable Collection tests + + * + ************************************************************/ + +using System; +using System.Threading; +using System.Windows; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; + +using Microsoft.Test; +using Microsoft.Test.Graphics; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: FreezableCollectionTest + **********************************************************************************/ + internal abstract class FreezableCollectionTest where T: DependencyObject + { + internal FreezableCollectionTest() + { + result = new Microsoft.Test.ElementServices.Freezables.Utils.Result(); + collection = new FreezableCollection(); + } + + internal FreezableCollection Make() + { + return new FreezableCollection(); + } + //--------------------------------------------------------- + internal abstract Microsoft.Test.ElementServices.Freezables.Utils.Result Perform(); + internal abstract FreezableCollection PopulateCollection(); + //--------------------------------------------------------- + + internal void TestDefaultConstructor() + { + FreezableCollection empty = new FreezableCollection(); + if (empty.Count != 0) + { + result.passed = false; + result.failures.Add("FAIL: " + empty.ToString() + ": TestDefaultConstructor - Expected count = 0, actual count = " + empty.Count); + GlobalLog.LogStatus("FAIL: " + empty.ToString() + ": TestDefaultConstructor - Expected count = 0, actual count = " + empty.Count); + } + } + + //--------------------------------------------------------- + internal void TestConstructorWith(int capacity) + { + FreezableCollection collection = new FreezableCollection(capacity); + if (collection.Count != 0) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = 0, actual count = " + collection.Count); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = 0, actual count = " + collection.Count); + } + } + //--------------------------------------------------------- + internal void TestConstructorWith(FreezableCollection freezables) + { + FreezableCollection collection = new FreezableCollection(freezables); + if (collection.Count != freezables.Count) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = " + freezables.Count + ", actual count = " + collection.Count); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = " + freezables.Count + ", actual count = " + collection.Count); + } + } + //--------------------------------------------------------- + internal void TestConstructorWith( IEnumerable freezables) + { + FreezableCollection collection = new FreezableCollection(freezables); + if (collection.Count != 0) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = 0, actual count = " + collection.Count); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestConstructorWith - Expected count = 0, actual count = " + collection.Count); + } + } + //--------------------------------------------------------- + internal void TestAdd(List objects) + { + foreach (object o in objects) + { + int oldCount = collection.Count; + collection.Add(o as T); + if (oldCount + 1 != collection.Count || !collection[oldCount].Equals(o)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestAdd - Expected count = " + (oldCount+1) + ", Object added = " + o + + " -Actual count = " + collection.Count + ", Object added = " + collection[oldCount]); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestAdd - Expected count = " + (oldCount + 1) + ", Object added = " + o + + " -Actual count = " + collection.Count + ", Object added = " + collection[oldCount]); + } + } + } + //--------------------------------------------------------- + internal void TestAddBadType(List bogusCollection) + { + foreach (object o in bogusCollection) + { + try + { + collection.Add(o as T); + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestAddBadType - Expected System.ArgumentExeption thrown"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestAddBadType - Expected System.ArgumentExeption thrown"); + + } + catch (System.ArgumentException e) + { + //Console.WriteLine(e.ToString()); + string s = e.ToString(); + } + } + } + //---------------------------------------------- + internal void TestAddFromAnotherThread() + { + GlobalLog.LogStatus("Testing AddFromAnotherThread...."); + bool threwInvalidOparationException = false; + collection = PopulateCollection(); + T objectFromOtherThread = default(T); + T item = collection[0]; + + Thread thread = new Thread((ThreadStart) + delegate + { + try + { + collection.Add(item); + } + catch (InvalidOperationException) + { + threwInvalidOparationException = true; + } + if (!threwInvalidOparationException) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestAddFromAnotherThread - case#1 :Expected InvalidOperationException thrown"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestAddFromAnotherThread - case#1 :Expected InvalidOperationException thrown"); + } + collection = PopulateCollection(); + objectFromOtherThread = collection[0]; + } + ); + + thread.Start(); + thread.Join(); + if (objectFromOtherThread == null) + { + throw new ApplicationException("objectFromAnohterThread should not be null"); + } + threwInvalidOparationException = false; + collection = PopulateCollection(); + try + { + collection.Add(objectFromOtherThread); + } + catch (InvalidOperationException) + { + threwInvalidOparationException = true; + } + if (!threwInvalidOparationException) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestAddFromAnotherThread - case#2 :Expected InvalidOperationException thrown"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestAddFromAnotherThread - case#2 :Expected InvalidOperationException thrown"); + } + } + + //---------------------------------------------- + internal void TestAddToFrozenCollection() + { + GlobalLog.LogStatus("Testing TestAddToFrozenCollection..."); + bool invalidOperationException = false; + collection = PopulateCollection(); + T item = collection[0]; + collection.Freeze(); + try + { + collection.Add(item); + } + catch (System.InvalidOperationException) + { + invalidOperationException = true; + } + if (!invalidOperationException) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestAddToFrozenCollection - Expected System.InvalidOperationException thrown"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestAddToFrozenCollection - Expected SSystem.InvalidOperationException"); + } + + } + //--------------------------------------------------------- + internal void TestChangedEvent(List objects) + { + GlobalLog.LogStatus("Testing changed event..."); + + TestChangedForAdd(objects); + TestChangedForInsert(objects); + TestChangedForRemove(); + TestChangedForRemoveAt(); + TestChangedForClear(); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForAdd(List objects) + { + collection = new FreezableCollection(); + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 0; + _objectsExpected = 0; + + foreach (object o in objects) + { + _callbacksExpected++; + _objectsExpected++; + collection.Add(o as T); + } + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + + foreach (object o in objects) + { + // No more callbacks expected + _objectsExpected++; + collection.Add(o as T); + } + VerifyCallbacksProcessed(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForClear() + { + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 1; + _objectsExpected = 0; + collection.Clear(); + + _callbacksExpected++; + collection.Clear(); + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + // No more callbacks expected + collection.Clear(); + VerifyCallbacksProcessed(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForInsert(List objects) + { + collection = new FreezableCollection(); + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 0; + _objectsExpected = 0; + + foreach (object obj in objects) + { + _callbacksExpected++; + _objectsExpected++; + collection.Insert(0, obj as T); + } + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + + foreach (object obj in objects) + { + // No more callbacks expected + _objectsExpected++; + collection.Insert(0, obj as T); + } + VerifyCallbacksProcessed(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForItem(List objects) + { + collection = PopulateCollection(); + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 1; + _objectsExpected = objects.Count; + + collection[0] = objects[objects.Count - 1]; + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + + // No more callbacks expected + collection[0] = objects[objects.Count - 1]; + VerifyCallbacksProcessed(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForRemove() + { + collection = PopulateCollection(); + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 1; + _objectsExpected = collection.Count -1 ; + + // This should not invoke the changed handler + collection.Remove(null); + collection.Remove(collection[0]); + + // This should not invoke the changed handler + collection.Remove(null); + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + collection = PopulateCollection(); + _objectsExpected = collection.Count; + + // This should not invoke the changed handler + collection.Remove(null); + collection.Remove(collection[0]); + VerifyCallbacksProcessed(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void TestChangedForRemoveAt() + { + collection = PopulateCollection(); + collection.Changed += ChangedHandler; + + _callbacksProcessed = 0; + _callbacksExpected = 1; + _objectsExpected = collection.Count - 1; + + collection.RemoveAt(0); + VerifyCallbacksProcessed(); + + collection.Changed -= ChangedHandler; + collection = PopulateCollection(); + collection.RemoveAt(0); + VerifyCallbacksProcessed(); + } + private void ChangedHandler(object sender, EventArgs args) + { + _callbacksProcessed++; + + // Do this partially because I want to verify "sender" + // and partially so I don't have to create a new collection variable + // and cast from "sender" + if (!object.ReferenceEquals(sender, collection)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestChangedEvent - Expected = " + collection + ", Actual = " + sender); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestChangedEvent - Expected = " + collection + ", Actual = " + sender); + } + + if (collection.Count != _objectsExpected) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + ": TestChangedEven # objects in collection is not many as we expected"); + result.failures.Add("Expected: " + _objectsExpected + ", Actual: "+ collection.Count); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + ": TestChangedEven # objects in collection is not many as we expected"); + GlobalLog.LogStatus("Expected: " + _objectsExpected + ", Actual: " + collection.Count); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + private void VerifyCallbacksProcessed() + { + if (_callbacksProcessed != _callbacksExpected) + { + result.passed = false; + result.failures.Add("Callbacks processed and callbacks expected do not match"); + result.failures.Add("Expected: " + _callbacksExpected + ", Actual: " + _callbacksProcessed); + GlobalLog.LogStatus("Callbacks processed and callbacks expected do not match"); + GlobalLog.LogStatus("Expected: " + _callbacksExpected + ", Actual: " + _callbacksProcessed); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + internal void TestClear() + { + GlobalLog.LogStatus("Testing Clear..."); + + // Call Clear on a list with items in it + collection = PopulateCollection(); + collection.Clear(); + if (collection.Count != 0) + { + result.passed = false; + result.failures.Add("FAIL: TestClear() for " + collection.ToString()); + result.failures.Add("Expected count = 0, actual count = " + collection.Count); + GlobalLog.LogStatus("FAIL: TestClear() for " + collection.ToString()); + GlobalLog.LogStatus("Expected count = 0, actual count = " + collection.Count); + } + foreach (object o in collection) + { + result.passed = false; + result.failures.Add("There shouldn't be any objects in the collection despite what \"Count\" says"); + GlobalLog.LogStatus("There shouldn't be any objects in the collection despite what \"Count\" says"); + break; + } + + // Call clear on an empty list + collection = new FreezableCollection(); + collection.Clear(); + if (collection.Count != 0) + { + result.passed = false; + result.failures.Add("FAIL: TestClear() for " + collection.ToString()); + result.failures.Add("Expected count = 0, actual count = " + collection.Count); + GlobalLog.LogStatus("FAIL: TestClear() for " + collection.ToString()); + GlobalLog.LogStatus("Expected count = 0, actual count = " + collection.Count); + } + foreach (object o in collection) + { + result.passed = false; + result.failures.Add("There shouldn't be any objects in the collection despite what \"Count\" says"); + GlobalLog.LogStatus("There shouldn't be any objects in the collection despite what \"Count\" says"); + break; + } + } + //--------------------------------------------- + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + internal void TestContains() + { + GlobalLog.LogStatus("Testing Contains..."); + collection = PopulateCollection(); + + foreach (object obj in collection) + { + if (!collection.Contains(obj as T)) + { + result.passed = false; + result.failures.Add("Contains() failed, Could not locate " + obj + "in my collection"); + GlobalLog.LogStatus("Contains() failed, Could not locate " + obj + "in my collection"); + } + } + T temp = collection[0]; + collection.Remove(collection[0]); + if (collection.Contains(temp)) + { + result.passed = false; + result.failures.Add("Contains() failed, should not have located " + temp + "in my collection"); + GlobalLog.LogStatus("Contains() failed, should not have located " + temp + "in my collection"); + } + + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + internal void TestCopyTo() + { + GlobalLog.LogStatus("Testing CopyTo()..."); + collection = PopulateCollection(); + + T[] array = new T[collection.Count]; + collection.CopyTo(array, 0); + + for (int i = 0; i < collection.Count; i++) + { + if (!collection[i].Equals(array[i])) + { + result.passed = false; + result.failures.Add("CopyTo() failed, Expected: " + collection[i] + " Actual: " + array[i]); + GlobalLog.LogStatus("CopyTo() failed, Expected: " + collection[i] + " Actual: " + array[i]); + break; + } + } + + } + + //------------------------------------------------- + internal void TestCount() + { + GlobalLog.LogStatus("Testing Count..."); + collection = PopulateCollection(); + + int count = 0; + int theirAnswer = collection.Count; + + foreach (object o in collection) + { + count++; + } + if (count != theirAnswer ) + { + result.passed = false; + result.failures.Add("Count failed, Expected count: " + count + " Actual: " + theirAnswer); + GlobalLog.LogStatus("Count failed, Expected count: " + count + " Actual: " + theirAnswer); + } + + // Make sure list really is cleared and that Count is updated + collection.Clear(); + count = 0; + theirAnswer = collection.Count; + + foreach (object o in collection) + { + count++; + } + if (count != theirAnswer) + { + result.passed = false; + result.failures.Add("Count failed, Expected count: " + count + " Actual: " + theirAnswer); + GlobalLog.LogStatus("Count failed, Expected count: " + count + " Actual: " + theirAnswer); + } + } + //--------------------------------------- + internal virtual void TestDataBinding() + { + throw new ApplicationException("TestDataBinding() - derived class needs to implement this method"); + } + + //--------------------------------------- + internal void TestEnumerator() + { + GlobalLog.LogStatus("Testing Enumerator..."); + collection = PopulateCollection(); + int i = 0; + foreach (T coll in collection) + { + if (!object.ReferenceEquals(coll, collection[i++])) + { + result.passed = false; + result.failures.Add("FAIL: Enumerator for " + collection.ToString()); + result.failures.Add("Expected: " + collection[i++] + "Actual: " + coll); + GlobalLog.LogStatus("FAIL: Enumerator for " + collection.ToString()); + GlobalLog.LogStatus("Expected: " + collection[i++] + "Actual: " + coll); + } + } + } + + //--------------------------------- + internal void TestGetAsFrozen() + { + GlobalLog.LogStatus("Testing GetAsFrozen..."); + + collection = PopulateCollection(); + + // We clone the collection first so that the test objects are not permanently frozen + FreezableCollection copy = collection.Clone(); + + if (object.ReferenceEquals(copy, collection) || + !ObjectUtils.DeepEqualsToAnimatable(copy, collection)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + " Clone should always return a deep copy"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + " Clone should always return a deep copy"); + } + + Freezable frozen = copy.GetAsFrozen(); + if (object.ReferenceEquals(frozen, copy) || + !ObjectUtils.DeepEqualsToAnimatable(frozen, copy)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + "GetAsFrozen should return a deep copy if the collection is not frozen"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + "GetAsFrozen should return a deep copy if the collection is not frozen"); + } + + copy.Freeze(); + frozen = copy.GetAsFrozen(); + if (!object.ReferenceEquals(frozen, copy)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + "GetAsFrozen should return a shallow copy if the collection is frozen"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + "GetAsFrozen should return a shallow copy if the collection is frozen"); + } + + } + //-------------------------------------------- + internal void TestGetCurrentValueAsFrozen() + { + GlobalLog.LogStatus("Testing GetCurrentValueAsFrozen..."); + + collection = PopulateCollection(); + // We clone the collection first so that the test objects are not permanently frozen + FreezableCollection copy = collection.Clone(); + + if (object.ReferenceEquals(copy, collection) || + !ObjectUtils.DeepEqualsToAnimatable(copy, collection)) + + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + "Clone should always return a deep copy"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + "Clone should always return a deep copy"); + } + + Freezable frozen = copy.GetCurrentValueAsFrozen(); + if (object.ReferenceEquals(frozen, copy) || + !ObjectUtils.DeepEqualsToAnimatable(frozen, copy)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + "GetCurrentValueAsFrozen should return a deep copy if the collection is not frozen"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + "GetCurrentValueAsFrozen should return a deep copy if the collection is not frozen"); + } + + copy.Freeze(); + frozen = copy.GetCurrentValueAsFrozen(); + if (!object.ReferenceEquals(frozen, copy)) + { + result.passed = false; + result.failures.Add("FAIL: " + collection.ToString() + "GetCurrentValueAsFrozen should return a shallow copy if the collection is frozen"); + GlobalLog.LogStatus("FAIL: " + collection.ToString() + "GetCurrentValueAsFrozen should return a shallow copy if the collection is frozen"); + } + } + //------------------------------------- + internal void TestIndexOf() + { + GlobalLog.LogStatus("Testing IndexOf( )..."); + collection = PopulateCollection(); + T [] objects = new T[collection.Count]; + for (int index = 0; index < collection.Count; index++) + { + objects[index] = collection[index]; + } + for (int i = 0; i < collection.Count; i++) + { + int position = collection.IndexOf(objects[i]); + if (position != i ) + { + result.passed = false; + result.failures.Add("FAIL: IndexOf for " + collection.ToString()); + result.failures.Add("Expected: " + objects[i] + " at postion " + i); + result.failures.Add("Actual: " + objects[i] + " at postion " + position); + GlobalLog.LogStatus("FAIL: IndexOf for " + collection.ToString()); + GlobalLog.LogStatus("Expected: " + objects[i] + " at postion " + i); + GlobalLog.LogStatus("Actual: " + objects[i] + " at postion " + position); + } + } + } + //------------------------------------- + internal void TestInsert() + { + GlobalLog.LogStatus("Testing Insert..."); + collection = PopulateCollection(); + FreezableCollection cloned = collection.Clone(); + int count = collection.Count; + collection.Insert(0, cloned[cloned.Count - 1]); + + if (count + 1 != collection.Count || + !collection[0].Equals(cloned[cloned.Count - 1])) + { + result.passed = false; + result.failures.Add("FAIL: Insert for " + collection.ToString()); + result.failures.Add("Expected count: " + (count+1) + "first object = " + cloned[cloned.Count - 1]); + result.failures.Add("Actual count: " + collection.Count + "first object = " + collection[0]); + GlobalLog.LogStatus("FAIL: Insert for " + collection.ToString()); + GlobalLog.LogStatus("Expected count: " + (count + 1) + "first object = " + cloned[cloned.Count - 1]); + GlobalLog.LogStatus("Actual count: " + collection.Count + "first object = " + collection[0]); + } + + collection = PopulateCollection(); + cloned = collection.Clone(); + collection.Insert(count - 1, cloned[0]); + + if (count + 1 != collection.Count || + !collection[collection.Count - 2].Equals(cloned[0])) + { + result.passed = false; + result.failures.Add("FAIL: Insert for " + collection.ToString()); + result.failures.Add("Expected count: " + (count + 1) + "2nd to last object = " + cloned[0]); + result.failures.Add("Actual count: " + collection.Count + "first object = " + collection[collection.Count -2]); + GlobalLog.LogStatus("FAIL: Insert for " + collection.ToString()); + GlobalLog.LogStatus("Expected count: " + (count + 1) + "2nd to last object = " + cloned[0]); + GlobalLog.LogStatus("Actual count: " + collection.Count + "first object = " + collection[collection.Count - 2]); + } + + } + /* + internal void TestIsFixedSize() + { + GlobalLog.LogStatus("Testing IsFixedSize..."); + collection = PopulateCollection(); + + bool theirAnswer = ((ICollection)collection).IsFixedSize; + if (theirAnswer) + { + result.passed = false; + result.failures.Add("FAIL: IsFixedSize for " + collection.ToString()); + result.failures.Add("A growing collection should not have a fixed size"); + GlobalLog.LogStatus("FAIL: Insert for " + collection.ToString()); + GlobalLog.LogStatus("A growing collection should not have a fixed size"); + } + + collection.Freeze(); + theirAnswer = ((ICollection)collection).IsFixedSize; + if (!theirAnswer) + { + result.passed = false; + result.failures.Add("FAIL: IsFixedSize for " + collection.ToString()); + result.failures.Add("A frozen collection should be fixed in size"); + GlobalLog.LogStatus("FAIL: Insert for " + collection.ToString()); + GlobalLog.LogStatus("A frozen collection should be fixed in size"); + } + } + */ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + internal void TestIsReadOnly() + { + GlobalLog.LogStatus("Testing IsReadOnly..."); + collection = PopulateCollection(); + bool theirAnswer = ((ICollection)collection).IsReadOnly; + if (theirAnswer) + { + result.passed = false; + result.failures.Add("FAIL: IsFixedSize for " + collection.ToString()); + result.failures.Add("A growing collection should not be read-only"); + GlobalLog.LogStatus("FAIL: IsFixedSize for " + collection.ToString()); + GlobalLog.LogStatus("A growing collection should not be read-only"); + } + + collection.Freeze(); + theirAnswer = ((ICollection)collection).IsReadOnly; + if (!theirAnswer) + { + result.passed = false; + result.failures.Add("FAIL: IsFixedSize for " + collection.ToString()); + result.failures.Add("A frozen collection should be read-only"); + GlobalLog.LogStatus("FAIL: IsFixedSize for " + collection.ToString()); + GlobalLog.LogStatus("A frozen collection should be read-only"); + } + } + + //------------------------------------- + internal void TestItem() + { + GlobalLog.LogStatus("Testing IList.get/set_Item..."); + collection = PopulateCollection(); + FreezableCollection objects = collection.Clone(); + collection[0] = objects[objects.Count-1]; + if (!collection[0].Equals(objects[objects.Count - 1])) + { + result.passed = false; + result.failures.Add("IList.get/set_Item failed for " + collection.ToString()); + result.failures.Add("Expected: item[0] = " + objects[objects.Count -1]); + result.failures.Add("Actual: item[0] = " + collection[0]); + GlobalLog.LogStatus("IList.get/set_Item failed for " + collection.ToString()); + GlobalLog.LogStatus("Expected: item[0] = " + objects[objects.Count - 1]); + GlobalLog.LogStatus("Actual: item[0] = " + collection[0]); + } + + } + //------------------------------------- + + internal void TestRemove() + { + GlobalLog.LogStatus("Testing Remove..."); + collection = PopulateCollection(); + T temp = collection[0]; + int count = collection.Count; + collection.Remove(temp); + if (count - 1 != collection.Count || collection.IndexOf(temp) != -1) + { + result.passed = false; + result.failures.Add("Remove failed for " + collection.ToString()); + result.failures.Add("Expected: item[0] = " + collection[collection.Count - 1]); + result.failures.Add("Actual: item[0] = " + collection[0]); + result.failures.Add("Expected: count = "+ (count-1) + " and object should not be found"); + if (count - 1 == collection.Count) + { + result.failures.Add("Actual: count = " + collection.Count + " and object was not removed"); + } + else + { + result.failures.Add("Actual: count = " + collection.Count); + } + } + } + + internal void TestRemoveAt() + { + GlobalLog.LogStatus("Testing RemoveAt..."); + collection = PopulateCollection(); + + T[] myCollection = new T[collection.Count]; + collection.CopyTo(myCollection, 0); + + collection.RemoveAt(0); + myCollection[0] = null; + + VerifyRemoveAt(myCollection); + + collection = PopulateCollection(); + collection.CopyTo(myCollection, 0); + collection.RemoveAt(collection.Count - 1); + myCollection[myCollection.Length - 1] = null; + + VerifyRemoveAt(myCollection); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + internal void VerifyRemoveAt(T [] myList) + { + int myIterator = 0; + int theirIterator = 0; + while (theirIterator < collection.Count) + { + if (myList[myIterator] == null) + { + myIterator++; + } + if (!collection[theirIterator].Equals(myList[myIterator])) + { + result.passed = false; + result.failures.Add("RemoveAt failed for " + collection.ToString()); + result.failures.Add("Expected: object # " + theirIterator + " == " + myList[myIterator]); + result.failures.Add("Expected: object # " + theirIterator + " == " + collection[myIterator]); + GlobalLog.LogStatus("RemoveAt failed for " + collection.ToString()); + GlobalLog.LogStatus("Expected: object # " + theirIterator + " == " + myList[myIterator]); + GlobalLog.LogStatus("Expected: object # " + theirIterator + " == " + collection[myIterator]); + break; + } + myIterator++; + theirIterator++; + } + } + private int _callbacksProcessed; + private int _objectsExpected; + private int _callbacksExpected; + protected Microsoft.Test.ElementServices.Freezables.Utils.Result result; + protected FreezableCollection collection; + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollections.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollections.cs new file mode 100644 index 000000000..1624e3e57 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/FreezableCollections.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: Test freezable collections + + * + ************************************************************/ + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Effects; +using System.Windows.Media.Media3D; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.ElementServices.Freezables.Utils; + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\Collections + + /// 2 + /// + /// Freezables collection tests + /// + /// + + [Test(2, "Freezables.Collections", "FreezablesCollections")] + + /********************************************************************************** + * CLASS: FreezablesCollections + **********************************************************************************/ + public class FreezablesCollections : AvalonTest + { + #region Private Data + + public Microsoft.Test.ElementServices.Freezables.Utils.Result result; + private string _testName = ""; + + #endregion + + + #region Constructors + + [Variation("Brush")] + [Variation("Geometry")] + [Variation("Transform")] + + /****************************************************************************** + * Function: FreezablesCollections Constructor + ******************************************************************************/ + public FreezablesCollections(string inputValue) + { + _testName = inputValue; + + InitializeSteps += new TestStep(Initialize); + RunSteps += new TestStep(StartTestCase); + RunSteps += new TestStep(Verify); + } + + #endregion + + + #region Private Members + + /****************************************************************************** + * Function: Initialize + ******************************************************************************/ + /// + /// Initializing. + /// + /// Returns TestResult=True + private TestResult Initialize () + { + result = new Microsoft.Test.ElementServices.Freezables.Utils.Result(); + + return TestResult.Pass; + } + + /****************************************************************************** + * Function: StartTestCase + ******************************************************************************/ + /// + /// Carries out a series of Freezables Collection tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult StartTestCase () + { + // + + + switch (_testName) + { + case "Brush": + { + BrushCollectionTest b = new BrushCollectionTest(); + result = b.Perform(); + break; + } + case "Geometry": + { + GeometryCollectionTest g = new GeometryCollectionTest(); + result = g.Perform(); + break; + } + case "Transform": + { + TransformCollectionTest t = new TransformCollectionTest(); + result = t.Perform(); + break; + } + default: + throw new ApplicationException("Unknown class: " + _testName); + } + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// Returns TestResult=True + private TestResult Verify() + { + // report the failures all together + if (!result.passed) + { + GlobalLog.LogEvidence("------------------------------------------"); + GlobalLog.LogEvidence("FAILURE REPORT"); + GlobalLog.LogEvidence("------------------------------------------"); + for (int i = 0; i < result.failures.Count; i++) + { + GlobalLog.LogEvidence (result.failures[i]); + } + } + + if (result.passed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/GeometryCollectionTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/GeometryCollectionTest.cs new file mode 100644 index 000000000..7deeb141c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/GeometryCollectionTest.cs @@ -0,0 +1,194 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: FreezableCollection Test + + * + ************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Media3D; + +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + internal class GeometryCollectionTest : FreezableCollectionTest + { + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal GeometryCollectionTest() + { + _bogusCollection = new List(); + collection.Add(new LineGeometry()); + collection.Add(new EllipseGeometry()); + _objects = new List(); + _objects.Add(new RectangleGeometry()); + _objects.Add(new PathGeometry()); + _objects.Add(Geometry.Empty); + + _bogusCollection.Add(10); + _bogusCollection.Add(new TranslateTransform()); + _bogusCollection.Add(new Point3D()); + _bogusCollection.Add(null); + _bogusCollection.Add(new Point()); + _bogusCollection.Add(new Vector3D()); + _bogusCollection.Add(new Matrix3D()); + _bogusCollection.Add(true); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override Microsoft.Test.ElementServices.Freezables.Utils.Result Perform() + { + TestDefaultConstructor(); + TestConstructorWith(464); + FreezableCollection coll = PopulateCollection(); + TestConstructorWith(coll); + TestConstructorWith(new NonCollectionEnumerable()); + TestConstructorWith(new FakeEnumerable()); + TestAdd(_objects); + TestAddBadType(_bogusCollection); + TestAddFromAnotherThread(); + TestAddToFrozenCollection(); + TestChangedEvent(_objects); + TestClear(); + TestContains(); + TestCopyTo(); + TestCount(); + TestEnumerator(); + TestGetAsFrozen(); + TestGetCurrentValueAsFrozen(); + TestIndexOf(); + TestInsert(); + TestIsReadOnly(); + TestItem(); + TestRemove(); + TestRemoveAt(); + + return result; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override FreezableCollection PopulateCollection() + { + FreezableCollection coll = new FreezableCollection(); + coll.Add(new RectangleGeometry()); + coll.Add(new PathGeometry()); + coll.Add(Geometry.Empty); + return coll; + } + //--------------------------------------------- + private List _bogusCollection; + // private FreezableCollection geometries; + private List _objects; + } + #region NonCollectionEnumerable + + public class NonCollectionEnumerable : IEnumerable + { + public IEnumerator GetEnumerator() + { + return new Enumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(); + } + + public class Enumerator : IEnumerator + { + public Geometry Current + { + get { return null; } + } + public void Dispose() + { + } + public bool MoveNext() + { + return false; + } + public void Reset() + { + } + object IEnumerator.Current + { + get { return null; } + } + } + } + + #endregion + #region FakeEnumerable + + public class FakeEnumerable : IEnumerable, ICollection + { + public void Add(Geometry p) + { + } + public void Clear() + { + } + public bool Contains(Geometry p) + { + return false; + } + public void CopyTo(Geometry[] points, int index) + { + } + public bool Remove(Geometry p) + { + return false; + } + public int Count + { + get { return 0; } + } + public bool IsReadOnly + { + get { return true; } + } + public IEnumerator GetEnumerator() + { + return new Enumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(); + } + + private class Enumerator : IEnumerator + { + public Geometry Current + { + get { return null; } + } + public void Dispose() + { + } + public bool MoveNext() + { + return false; + } + public void Reset() + { + } + object IEnumerator.Current + { + get { return null; } + } + } + } + + #endregion + + +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/TransformCollectionTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/TransformCollectionTest.cs new file mode 100644 index 000000000..e38af531d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesCollections/TransformCollectionTest.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: Freezableinternal Test + + * + ************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Media3D; + +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + //-------------------------------------------------------------- + + internal class TransformCollectionTest : FreezableCollectionTest + { + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal TransformCollectionTest() + { + _bogusCollection = new List(); + collection.Add(new TranslateTransform()); + collection.Add(new RotateTransform()); + _objects = new List(); + _objects.Add(new TranslateTransform()); + _objects.Add(new RotateTransform()); + + _bogusCollection.Add(10); + _bogusCollection.Add(new Point3D()); + _bogusCollection.Add(null); + _bogusCollection.Add(new Point()); + _bogusCollection.Add(new Vector3D()); + _bogusCollection.Add(new Matrix3D()); + _bogusCollection.Add(true); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override Microsoft.Test.ElementServices.Freezables.Utils.Result Perform() + { + TestDefaultConstructor(); + TestConstructorWith(464); + FreezableCollection coll = PopulateCollection(); + TestConstructorWith(coll); + TestAdd(_objects); + TestAddBadType(_bogusCollection); + TestAddFromAnotherThread(); + TestAddToFrozenCollection(); + TestChangedEvent(_objects); + TestClear(); + TestContains(); + TestCopyTo(); + TestCount(); + TestEnumerator(); + TestGetAsFrozen(); + TestGetCurrentValueAsFrozen(); + TestIndexOf(); + TestInsert(); + TestIsReadOnly(); + TestItem(); + TestRemove(); + TestRemoveAt(); + + return result; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal override FreezableCollection PopulateCollection() + { + FreezableCollection coll = new FreezableCollection(); + coll.Add(new TranslateTransform()); + coll.Add(new RotateTransform()); + return coll; + } + //--------------------------------------------- + private List _bogusCollection; + private List _objects; + } + } diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesMicroBVT/FreezablesMicroBVT.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesMicroBVT/FreezablesMicroBVT.cs new file mode 100644 index 000000000..760498234 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesMicroBVT/FreezablesMicroBVT.cs @@ -0,0 +1,199 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test freezable object + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Collections.Specialized; +using System.Windows; +using System.Windows.Media; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; +using Microsoft.Test.ElementServices.Freezables.Objects; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\MicroBVT + + /// 0 + /// + /// MicroBVT tests for Freezables + /// + /// + + [Test(0, "Freezables.MicroBVT", "FreezablesMicroBVT")] + + /********************************************************************************** + * CLASS: FreezablesMicroBVT + **********************************************************************************/ + public class FreezablesMicroBVT : AvalonTest + { + #region Private Data + + private bool _passed; + private StringCollection _failures; + private bool _eventfired; + + #endregion + + + #region Constructor + /****************************************************************************** + * Function: FreezablesMicroBVT Constructor + ******************************************************************************/ + public FreezablesMicroBVT() + { + InitializeSteps += new TestStep(Initialize); + RunSteps += new TestStep(StartTestCase); + RunSteps += new TestStep(Verify); + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: Initialize + ******************************************************************************/ + /// + /// Sets global variables. + /// + /// Returns TestResult=True + private TestResult Initialize() + { + _failures = new StringCollection(); + _eventfired = false; + _passed = true; + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: StartTestCase + ******************************************************************************/ + /// + /// Carries out a series of basic Freezables tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult StartTestCase() + { + //------------------------------------------------ + GlobalLog.LogStatus("Case #1: When Freezable is created, make sure !IsFrozen"); + MyFreezable mc = new MyFreezable(); + + if (mc.IsFrozen) + { + _passed &= false; + _failures.Add("Case#1 - !IsFrozen is false, expected true"); + GlobalLog.LogEvidence("Case#1 - FAIL: !IsFrozen is false, expected true"); + } + + //------------------------------------------------ + GlobalLog.LogStatus("Case #2: Call Freeze(), make sure IsFozen == true;"); + mc.Freeze(); + if (!mc.IsFrozen) + { + _passed &= false; + _failures.Add("Case#2 - !IsFrozen is true, expected false"); + GlobalLog.LogEvidence("Case#2 - FAIL: !IsFrozen is true, expected false"); + } + + //------------------------------------------------ + GlobalLog.LogStatus("Case #4: Make sure UIContext == null, since !IsFrozen is false"); + if (mc.Dispatcher != null) + { + _passed &= false; + _failures.Add("Case#4 - Dispatcher should be be null"); + GlobalLog.LogEvidence("Case#4 -FAIL: Dispatcher should be null"); + } + + //------------------------------------------------ + GlobalLog.LogStatus("Case #5: When Freezable is copied, make sure !IsFrozen"); + Freezable mc2 = mc.Clone(); + if (mc2.IsFrozen) + { + _passed &= false; + _failures.Add("Case#5 - !IsFrozen is false, expected true"); + GlobalLog.LogEvidence("Case#5 - FAIL: !IsFrozen is false, expected true"); + } + + //------------------------------------------------ + GlobalLog.LogStatus("Case #6: Test Changed event"); + LineGeometry line = new LineGeometry(); + MyFreezable mc3 = new MyFreezable(line); + mc3.Changed += new EventHandler(SimpleEventTest); + mc3.FreezableObj = null; + if (!_eventfired) + { + _passed &= false; + _failures.Add("Case#6 - Event not fired"); + GlobalLog.LogEvidence("Case#6 - FAIL: Event not fired"); + } + + //------------------------------------------------ + // Report the failures all together + if (!_passed) + { + GlobalLog.LogStatus("-------------------------------------------------"); + GlobalLog.LogEvidence("FAILURE REPORT"); + for (int i = 0; i < _failures.Count; i++) + { + GlobalLog.LogEvidence(_failures[i]); + } + } + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: SimpleEventTest + ******************************************************************************/ + /// + /// Event handler for Changed event. + /// + /// The object involved with the event. + /// Event args. + /// + private void SimpleEventTest(Object sender, EventArgs args) + { + _eventfired = true; + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// A TestResult, indicating whether or not the test passed. + private TestResult Verify() + { + if (_passed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/AttachedDPTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/AttachedDPTest.cs new file mode 100644 index 000000000..95e787379 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/AttachedDPTest.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2005 + * + * Program: AttachedDPTest - DP == DependencyProperty + + * + ************************************************************/ +//***************************************************************************************** +//This test does the following things: +//For each freezable created from the script (xtc) +// Perform set/get attachedDP, and verify +// Perform copy and verify +// Perform freeze and verify +// Perform set on freezableDP, and verify the changed event +// If freezable is also animatable, then perform CloneCurrentValue and verify +//****************************************************************************************** +using System; +using System.Xml; +using System.Security; +using System.Windows; +using System.Windows.Media; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: AttachedDPTest + **********************************************************************************/ + public class AttachedDPTest: FreezablesObjectsBase + { + #region Private Data + private bool _isEventFired; + private DependencyProperty _booAP; + private DependencyProperty _referenceAP; + private DependencyProperty _freezableAP; + #endregion + + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public AttachedDPTest(string testName, string objName) : base(testName, objName) + { + // setup attached properties + + _booAP = DependencyProperty.RegisterAttached( + "Bool", + typeof(bool), + typeof(AttachedDPTest) + ); + _referenceAP = DependencyProperty.RegisterAttached( + "Reference", + typeof(object), + typeof(AttachedDPTest) + ); + + _freezableAP = DependencyProperty.RegisterAttached( + "Freezable", + typeof(Pen), + typeof(AttachedDPTest) + ); + + Perform(); + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + foreach (Freezable freezable in freezables) + { + // SetGet test + freezable.SetValue(_booAP, true); + bool b = (bool)freezable.GetValue(_booAP); + + if (!b) + { + LogFailure("GetValue(booAP) should return true: ", freezable); + } + + freezable.SetValue(_referenceAP, new object()); + object obj = freezable.GetValue(_referenceAP); + + if (obj.GetType().ToString() != "System.Object") + { + LogFailure(" :GetValue(referenceAP should return System.Object", freezable); + } + + freezable.SetValue(_freezableAP, new Pen()); + object pen = freezable.GetValue(_freezableAP); + if (pen.GetType().ToString() != "System.Windows.Media.Pen") + { + LogFailure(": GetValue should return System.Windows.Media.Pen: ", freezable); + } + + // Test event + _isEventFired = false; + freezable.Changed += new EventHandler(FreezableEventHandler); + ((Pen)freezable.GetValue(_freezableAP)).Thickness = 5.0; + + if (!_isEventFired) + { + LogFailure(": Changed event not fired when setting attached freezable DP on a freezable: ", freezable); + } + + // Copy test + Freezable freezableCopy = freezable.Clone(); + if (freezableCopy.GetValue(_booAP) != freezable.GetValue(_booAP)) + { + LogFailure(": GetValue(booAP) should be equal to the copied object: ", freezable); + } + // Reference properties should be the same reference after a copy + if (!ReferenceEquals(freezableCopy.GetValue(_referenceAP), freezable.GetValue(_referenceAP))) + { + LogFailure(": GetValue(referenceAP) should be equal to the copied object: ", freezable); + } + + // Freezable properties should be different instances after a copy + if (ReferenceEquals(freezableCopy.GetValue(_freezableAP), freezable.GetValue(_freezableAP))) + { + LogFailure(": GetValue(freezableAP) should NOT be equal to the copied object ", freezable); + } + + // Check a sub property to verify the deep copy + if (!ReferenceEquals( + ((Pen)freezableCopy.GetValue(_freezableAP)).Brush, + ((Pen)freezable.GetValue(_freezableAP)).Brush) + ) + { + LogFailure(": GetValue(freezableAP) on sub property should be equal to the copied object ", freezable); + } + // Freeze test + freezable.Freeze(); + Freezable f = (Freezable)freezable.GetValue(_freezableAP); + if (!f.IsFrozen) + { + LogFailure(": freezableAP should be frozen after calling Freeze() ", freezable); + } + + // Test CloneCurrentValue + Freezable freezableCopyCurrentValue = freezableCopy.CloneCurrentValue(); + // Value properties should be the same value after a copy + if (freezableCopyCurrentValue.GetValue(_booAP) != freezableCopy.GetValue(_booAP)) + { + LogFailure(": freezableCopyCurrentValue.CloneCurrentValue(booAP) should be equal to the original object ", freezable); + } + // Reference properties should be the same reference after copy + if (!ReferenceEquals(freezableCopyCurrentValue.GetValue(_referenceAP), freezableCopy.GetValue(_referenceAP))) + { + LogFailure(": freezableCopyCurrentValue.CloneCurrentValue(ReferencelAP) should be reference equal to the original object ", freezable); + } + // Freezable properties should be different instances after a copy + if (ReferenceEquals(freezableCopyCurrentValue.GetValue(_freezableAP), freezableCopy.GetValue(_freezableAP))) + { + LogFailure(": freezableCopyCurrentValue.CloneCurrentValue(freezableAP) should be reference equal to the original object ", freezable); + } + } + } + + /****************************************************************************** + * Function: FreezableEventHandler + ******************************************************************************/ + public void FreezableEventHandler(Object sender, EventArgs args) + { + _isEventFired = true; + } + + /****************************************************************************** + * Function: LogFailure + ******************************************************************************/ + // default value for result.Status == Pass + private void LogFailure(string message, Freezable freezable) + { + GlobalLog.LogEvidence(freezable.GetType().ToString() + message); + failures.Add(freezable.GetType().ToString() + message); + passed = false; + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/CopyTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/CopyTest.cs new file mode 100644 index 000000000..343f4132b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/CopyTest.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2005 + * + * Program: Test Copy for freezable + * Description: This test does the following: + * 1. Freeze the object, then do the copy + * 2. Enumerate the properities of the copy object recursively, get the freezable property + * verify that if the freezable property is frezen, fail the test. + + * + ************************************************************/ +using System; +using System.Xml; +using System.Reflection; +using System.Collections; +using System.Diagnostics; +using System.Security; +using System.Security.Policy; +using System.Windows; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: CopyTest + **********************************************************************************/ + public class CopyTest : FreezablesObjectsBase + { + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public CopyTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + foreach (Freezable freezable in freezables) + { + // Verify the copied object and it subobjects are unfrozen + freezable.Freeze(); + + Freezable copiedObj = freezable.Clone(); + + VerifyIsFrozen(copiedObj); + } + } + + /****************************************************************************** + * Function: VerifyIsFrozen + ******************************************************************************/ + private void VerifyIsFrozen(Freezable freezable) + { + Verify(freezable); + + Type t = freezable.GetType(); + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo prop in pi) + { + if (DoesCauseStackOverflow(freezable, prop)) + { + // When GetValue from some object (ex: MatrixTransform) + // The property value that I get is the same object as it class + // This will cause stack overflow, as this process is going thru + // Infinite loop. So I have to do this to prevent stack overflow from + // happening. + continue; + } + + if (TypeHelper.IsFreezable(prop.PropertyType)) + { + if (freezable is IEnumerable) + { + // This means that the current Freezable is a collection + foreach (Freezable f in (IEnumerable) freezable) + { + VerifyIsFrozen(f); + } + } + else + { + Freezable subFreezable = (Freezable)prop.GetValue(freezable, null); + VerifyIsFrozen(subFreezable); + + } + } + } + } + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + private void Verify(Freezable freezable) + { + if (freezable.IsFrozen) + { + GlobalLog.LogEvidence(freezable.GetType().ToString() + " should not be frozen "); + failures.Add(freezable.GetType().ToString() + " should not be frozen "); + passed &= false; + } + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingFactory.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingFactory.cs new file mode 100644 index 000000000..c5c5dbbe8 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingFactory.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2005 + * + * Program: DataBinding Object Factory + + * + ************************************************************/ + +using System; +using System.Xml; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: DataBindingFactory + **********************************************************************************/ + public class DataBindingFactory + { + /****************************************************************************** + * Function: DataBindingBase + ******************************************************************************/ + public static DataBindingBase Make(Type t) + { + if (t == null) + { + throw new ApplicationException("ERROR -- DataBindingBase Make: Type is null."); + } + else + { + string type = t.ToString(); + + switch (type) + { + case "System.Windows.Media.Brush": + return new BrushDataBinding(); + + case "System.Windows.Media.Geometry": + return new GeometryDataBinding(); + + case "System.Windows.Media.Pen": + return new PenDataBinding(); + + default: + throw new ApplicationException("This DataBinding type is not supported yet: " + type); + } + } + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingObject.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingObject.cs new file mode 100644 index 000000000..2bfa9eab5 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingObject.cs @@ -0,0 +1,186 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Security; +using System.Security.Policy; +using System.Windows; +using System.Windows.Media; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: PenDataBinding + **********************************************************************************/ + public class PenDataBinding : DataBindingBase + { + private SolidColorBrush _brush; + + /****************************************************************************** + * Function: UpdateFreezableProperty + ******************************************************************************/ + public override void UpdateFreezableProperty() + { + DataProperty = new SolidColorBrush(Colors.White); + } + + //--------------------------------------------------------------- + public override DependencyProperty DP + { + get + { + return Pen.BrushProperty; + } + } + //------------------------------------------------- + + public PenDataBinding() + { + _brush = new SolidColorBrush(Colors.Blue); + } + + //------------------------------------------------- + public SolidColorBrush DataProperty + { + get + { + return _brush; + } + set + { + _brush = value; + OnPropertyChanged("DataProperty"); + } + } + } + + + /********************************************************************************** + * CLASS: GeometryDataBinding + **********************************************************************************/ + public class GeometryDataBinding : DataBindingBase + { + private Transform _transform; + + /****************************************************************************** + * Function: UpdateFreezableProperty + ******************************************************************************/ + public override void UpdateFreezableProperty() + { + DataProperty = new TranslateTransform(22, 33); + } + //------------------------------------------------- + public override DependencyProperty DP + { + get + { + return Geometry.TransformProperty; + } + } + + //------------------------------------------------- + public GeometryDataBinding() + { + _transform = new TranslateTransform(20, 20); + } + + //------------------------------------------------- + public Transform DataProperty + { + get + { + return _transform; + } + set + { + _transform = value; + OnPropertyChanged("DataProperty"); + } + } + } + + + /********************************************************************************** + * CLASS: BrushDataBinding + **********************************************************************************/ + public class BrushDataBinding : DataBindingBase + { + private double _opacity; + + /****************************************************************************** + * Function: UpdateFreezableProperty + ******************************************************************************/ + public override void UpdateFreezableProperty() + { + DataProperty = 0.6; + } + + //------------------------------------------------ + public override DependencyProperty DP + { + get + { + return Brush.OpacityProperty; + } + } + + //------------------------------------------------- + public BrushDataBinding() + { + _opacity = 0.4; + } + + //------------------------------------------------- + public double DataProperty + { + get + { + return _opacity; + } + set + { + _opacity = value; + OnPropertyChanged("DataProperty"); + } + } + } + + + /********************************************************************************** + * CLASS: DataBindingBase + **********************************************************************************/ + public abstract class DataBindingBase : INotifyPropertyChanged + { + // Declare event + public event PropertyChangedEventHandler PropertyChanged; + + /****************************************************************************** + * Function: OnPropertyChanged + ******************************************************************************/ + // OnPropertyChanged event handler to update property value in binding + public void OnPropertyChanged(string info) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(info)); + } + } + + /****************************************************************************** + * Function: UpdateFreezableProperty + ******************************************************************************/ + public abstract void UpdateFreezableProperty(); + + public abstract DependencyProperty DP + { + get; + } + + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingTest.cs new file mode 100644 index 000000000..5cd76ba3a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/DataBindingTest.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Security; +using System.Windows; +using System.Windows.Data; + +using Microsoft.Test.Logging; + +namespace Microsoft.Test.ElementServices.Freezables +{ + public class DataBindingTest : FreezablesObjectsBase + { + #region Private Data + private bool _isEventFired; + #endregion + + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public DataBindingTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + int i = 0; + foreach (Freezable freezable in freezables) + { + DataBindingBase dataObject = (DataBindingBase)dataBindingObjs[i]; + i++; + Binding binding = new Binding("DataProperty"); + binding.Source = dataObject; + freezable.Changed += new EventHandler(FreezableEventHandler); + + // TestEvent - event should fire whe call SetBinding() on a freezable + _isEventFired = false; + BindingOperations.SetBinding(freezable, dataObject.DP, binding); + if (!_isEventFired) + { + GlobalLog.LogEvidence("Changed event not fired when called SetBinding() on " + freezable.GetType().ToString()); + failures.Add("Changed event not fired when called SetBinding() on " + freezable.GetType().ToString()); + passed = false; + } + + // Verify that CanFreeze == false since a data-bound freezable can not be frozen + if (freezable.CanFreeze) + { + GlobalLog.LogEvidence("A data-bound freezable can not be frozen. Expect: CanFreeze == false, Actual CanFreeze == " + freezable.CanFreeze); + failures.Add("A data-bound freezable can not be frozen. Expect: CanFreeze == false, Actual CanFreeze == " + freezable.CanFreeze); + passed = false; + + } + + // TestEvent - when changing a freezable property inside DataBinding object + // Changed event should fired. + _isEventFired = false; + dataObject.UpdateFreezableProperty(); + if (!_isEventFired) + { + GlobalLog.LogEvidence("Changed event not fired when changing property value on a freezable in DataBinding object " + freezable.GetType().ToString()); + failures.Add("Changed event not fired when changing proerty value on a freezable in DataBinding object " + freezable.GetType().ToString()); + passed = false; + } + } + } + + /****************************************************************************** + * Function: FreezableEventHandler + ******************************************************************************/ + public void FreezableEventHandler(Object sender, EventArgs args) + { + _isEventFired = true; + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/EventTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/EventTest.cs new file mode 100644 index 000000000..10207587a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/EventTest.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Reflection; +using System.Security; +using System.Security.Policy; +using System.Windows; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: EventTest + **********************************************************************************/ + public class EventTest : FreezablesObjectsBase + { + #region Private Data + private bool _isEventFired; + #endregion + + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public EventTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + foreach (Freezable freezable in freezables) + { + if (freezable.IsFrozen) + { + //Cannot modify a frozen object, so bail out + return; + } + + Type t = freezable.GetType(); + + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + freezable.Changed += new EventHandler(FreezableEventHandler); + for (int i = 0; i < pi.Length; i++) + { + if (pi[i].CanWrite) + { + Object arg = new Object(); + arg = PredefinedObjects.MakeValue(pi[i].PropertyType); + if (arg != null) + { + Object[] index = null; + // collection + if (pi[i].Name == "Item" || pi[i].Name.ToString().EndsWith(".Item")) + { + index = new Object[] { 0 }; + } + // we need to get the mathching DP for this property + // and if the value (arg in this case) is the default value + // we don't need to call SetValue, since event won't fire + // when setting default value. + DependencyProperty dp = GetMatchingDP(pi[i], freezable); + if (dp != null) + { + if (arg.Equals(dp.DefaultMetadata.DefaultValue)) + { + return; + } + } + + _isEventFired = false; + + object value = pi[i].GetValue(freezable, null); + pi[i].SetValue(freezable, arg, index); + if (!_isEventFired) + { + GlobalLog.LogEvidence("Event not fired when setting value into " + t.FullName + "." + pi[i].Name); + failures.Add("Event not fired when setting value into " + t.FullName + pi[i].Name); + passed &= false; + + } + } + } + } + } + } + + /****************************************************************************** + * Function: FreezableEventHandler + ******************************************************************************/ + public void FreezableEventHandler(Object sender, EventArgs args) + { + _isEventFired = true; + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/ExceptionTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/ExceptionTest.cs new file mode 100644 index 000000000..6bb3e9715 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/ExceptionTest.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Collections.Generic; +using System.Security; +using System.Security.Policy; +using System.Windows; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: ExceptionTest + **********************************************************************************/ + public class ExceptionTest : FreezablesObjectsBase + { + #region Constructors + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public ExceptionTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + // Create freezable objects + foreach (Freezable freezable in freezables) + { + if (freezable.CanFreeze) + { + return; + } + try + { + freezable.Freeze(); + // log failure if there is no exception + GlobalLog.LogEvidence("No exception thrown when trying to freeze an object where CanFreeze==false"); + failures.Add("No exception thrown when trying to freeze an object where CanFreeze==false"); + passed &= false; + } + catch (System.InvalidOperationException e) + { + if (!e.InnerException.ToString().Contains("This Freezable can not be frozen")) + { + GlobalLog.LogEvidence("Bad exception message: " + e.InnerException.ToString()); + failures.Add("Bad exception message: " + e.InnerException.ToString()); + passed &= false; + + } + } + catch (System.Exception e) + { + GlobalLog.LogEvidence("Expected InvalidOperationException thrown, but get this exception instread: " + e.ToString()); + failures.Add("Expected InvalidOperationException thrown, but get this exception instread: " + e.ToString()); + passed &= false; + } + } + } + #endregion + } +} + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezableFactory.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezableFactory.cs new file mode 100644 index 000000000..05759b025 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezableFactory.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Xml; +using System.Security; +using System.Security.Policy; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; + +using Microsoft.Test.ElementServices.Freezables.Objects; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: FreezableFactory + **********************************************************************************/ + public class FreezableFactory + { + public static Freezable Make(Type t) + { + if (t == null) + { + throw new ApplicationException("ERROR -- Make: Type is null."); + } + else + { + string type = t.ToString(); + + switch (type) + { + case "System.Windows.Media.Brush": + Brush brush = (Brush)PredefinedObjects.MakeValue(t); + return brush; + + case "System.Windows.Media.Geometry": + Geometry geo = (Geometry)PredefinedObjects.MakeValue(t); + return geo; + + case "System.Windows.Media.Pen": + Pen pen = (Pen)PredefinedObjects.MakeValue(t); + return pen; + + case "System.Windows.Media.Transform": + Transform transform = (Transform)PredefinedObjects.MakeValue(t); + return transform; + + default: + throw new ApplicationException("Unknown type " + type); + } + } + } + + } +} + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjects.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjects.cs new file mode 100644 index 000000000..c4dc1c791 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjects.cs @@ -0,0 +1,193 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test freezable objects + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Collections.Specialized; +using System.Windows; +using System.Xml; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\Objects + + /// 3 + /// + /// BVT tests for Freezables + /// + /// + + [Test(3, "Freezables.Objects", "FreezablesObjects")] + + /********************************************************************************** + * CLASS: FreezableObjects + **********************************************************************************/ + public class FreezablesObjects : AvalonTest + { + #region Private Data + + public static bool testPassed = false; + private string _testName = ""; + private string _objName = ""; + + #endregion + + + #region Constructor + // [DISABLE WHILE PORTING] + // [Variation("AttachedDPTest", "Brush")] + // [Variation("AttachedDPTest", "Geometry")] + // [Variation("AttachedDPTest", "Pen")] + [Variation("AttachedDPTest", "Transform")] + +//BUG-BUG: [Variation("CopyTest", "Brush")] // get "MatrixTransform should not be frozen" error, whether or not one is assigned to the Brush. +//BUG-BUG: [Variation("CopyTest", "Pen")] // get several "should not be frozen" errors. + [Variation("CopyTest", "Geometry")] // avoid "MatrixTransform should not be frozen" error by assigning a Transform to the Geometry. + [Variation("CopyTest", "Transform")] + + [Variation("DataBindingTest", "Brush", Priority=2)] + [Variation("DataBindingTest", "Geometry", Priority=2)] + [Variation("DataBindingTest", "Pen", Priority=2)] + + [Variation("EventTest", "Brush", Priority=0)] + [Variation("EventTest", "Geometry", Priority=1)] + [Variation("EventTest", "Pen", Priority=1)] + [Variation("EventTest", "Transform", Priority=1)] + + [Variation("ExceptionTest", "Brush", Priority=1)] + [Variation("ExceptionTest", "Geometry", Priority=0)] + [Variation("ExceptionTest", "Pen", Priority=1)] + [Variation("ExceptionTest", "Transform", Priority=1)] + + [Variation("GetAsFrozenTest", "Brush")] + [Variation("GetAsFrozenTest", "Geometry")] + [Variation("GetAsFrozenTest", "Pen")] + [Variation("GetAsFrozenTest", "Transform")] + + [Variation("MultiThreadsTest", "Brush")] + [Variation("MultiThreadsTest", "Geometry")] + [Variation("MultiThreadsTest", "Pen")] + [Variation("MultiThreadsTest", "Transform")] + + [Variation("SetAndClearDPTest", "Brush")] + [Variation("SetAndClearDPTest", "Geometry")] + [Variation("SetAndClearDPTest", "Pen")] + [Variation("SetAndClearDPTest", "Transform")] + + + /****************************************************************************** + * Function: FreezablesObjects Constructor + ******************************************************************************/ + public FreezablesObjects(string inputValue0, string inputValue1) + { + _testName = inputValue0; + _objName = inputValue1; + RunSteps += new TestStep(StartTestCase); + RunSteps += new TestStep(Verify); + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: StartTestCase + ******************************************************************************/ + /// + /// Carries out a series of basic Freezables tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult StartTestCase () + { + FreezablesObjectsBase freezableBase = null; + + switch (_testName) + { + case "AttachedDPTest": + { + freezableBase = new AttachedDPTest(_testName, _objName); + break; + } + case "CopyTest": + { + freezableBase = new CopyTest(_testName, _objName); + break; + } + case "DataBindingTest": + { + freezableBase = new DataBindingTest(_testName, _objName); + break; + } + case "ExceptionTest": + { + freezableBase = new ExceptionTest(_testName, _objName); + break; + } + case "EventTest": + { + freezableBase = new EventTest(_testName, _objName); + break; + } + case "GetAsFrozenTest": + { + freezableBase = new GetAsFrozenTest(_testName, _objName); + break; + } + case "MultiThreadsTest": + { + freezableBase = new MultiThreadsTest(_testName, _objName); + break; + } + case "SetAndClearDPTest": + { + freezableBase = new SetAndClearDPTest(_testName, _objName); + break; + } + default: + throw new ApplicationException("Unknown test name: " + _testName); + } + + freezableBase.Perform(); + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// + private TestResult Verify() + { + if (testPassed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + #endregion + } + +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjectsBase.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjectsBase.cs new file mode 100644 index 000000000..c9392a879 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/FreezablesObjectsBase.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Animation; + +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Objects; + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: FreezablesObjectsBase + **********************************************************************************/ + public abstract class FreezablesObjectsBase + { + #region Private Data + + protected string testName; + protected string objName; + protected StringCollection failures; + protected bool passed; + protected List freezables; + protected ArrayList dataBindingObjs; + + #endregion + + + #region Constructors + /****************************************************************************** + * Function: FreezablesObjectsBase + ******************************************************************************/ + public FreezablesObjectsBase(string test, string obj) + { + testName = test; + objName = obj; + failures = new StringCollection(); + passed = true; + + GlobalLog.LogStatus("---Testing: " + testName + " -- Object: " + objName); + } + #endregion + + + #region Public and Protected Members + + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + public bool Perform() + { + freezables = new List(); + dataBindingObjs = new ArrayList(); + + Assembly dll = typeof(Animatable).Assembly; + Type t = dll.GetType("System.Windows.Media." + objName); + + if (t == null) + { + throw new ApplicationException("ERROR -- Perform: Type is null."); + } + else + { + freezables.Add(FreezableFactory.Make(t)); + + if (testName == "DataBindingTest") + { + dataBindingObjs.Add(DataBindingFactory.Make(t)); + } + + RunTest(); + + LogResult(); + } + return true; + } + + /****************************************************************************** + * Function: GetMatchingDP + ******************************************************************************/ + protected DependencyProperty GetMatchingDP(PropertyInfo pi, Freezable freezable) + { + FieldInfo[] fi = pi.DeclaringType.GetFields(); + for (int i = 0; i < fi.Length; i++) + { + if (fi[i].FieldType.IsPublic + && fi[i].FieldType.ToString() == "System.Windows.DependencyProperty" + && fi[i].Name == pi.Name + "Property") + { + return (DependencyProperty)fi[i].GetValue(freezable); + } + } + return null; + } + + /****************************************************************************** + * Function: DoesCauseStackOverflow + ******************************************************************************/ + protected bool DoesCauseStackOverflow(Freezable freezable, PropertyInfo property) + { + if (freezable.GetType().ToString() == "System.Windows.Media.MatrixTransform" && property.Name == "Inverse") + { + return true; + } + return false; + } + + /****************************************************************************** + * Function: LogResult + ******************************************************************************/ + protected void LogResult() + { + if (!passed) + { + GlobalLog.LogEvidence("---------------------------------------------------------------------"); + GlobalLog.LogEvidence("TestName = " + testName + " (" + objName + ") - FAILURE REPORT"); + GlobalLog.LogEvidence("---------------------------------------------------------------------"); + for (int i = 0; i < failures.Count; i++) + { + GlobalLog.LogEvidence(failures[i]); + } + } + + FreezablesObjects.testPassed = passed; + } + + + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public abstract void RunTest(); + + /****************************************************************************** + * Function: Dispose + ******************************************************************************/ + public void Dispose() { } + + #endregion + } +} + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/GetAsFrozenTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/GetAsFrozenTest.cs new file mode 100644 index 000000000..58bf81032 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/GetAsFrozenTest.cs @@ -0,0 +1,146 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Reflection; +using System.Security; +using System.Security.Policy; +using System.Collections; +using System.Windows; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: GetAsFrozenTest + **********************************************************************************/ + public class GetAsFrozenTest : FreezablesObjectsBase + { + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public GetAsFrozenTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + foreach (Freezable freezable in freezables) + { + VerifyGetAsFrozen(freezable); + } + } + + + /****************************************************************************** + * Function: VerifyGetAsFrozen + ******************************************************************************/ + private void VerifyGetAsFrozen(Freezable freezable) + { + Type t = freezable.GetType(); + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo property in pi) + { + if (!TypeHelper.IsFreezable(property.PropertyType)) + { + // no need to verify + continue; + } + if (DoesCauseStackOverflow(freezable, property)) + { + // When GetValue from some object (ex: MatrixTransform) + // The property value that I get is the same object as it class + // This will cause stack overflow, as this process is going thru + // Infinite loop. So I have to do this to prevent stack overflow from + // happening. + continue; + } + if (property.Name == "Item" ) + { + if (freezable is IEnumerable) + { + // This means that the current Freezable is a collection + VerifyForCollection((IEnumerable)freezable, property); + } + } + else + { + Freezable obj = (Freezable)property.GetValue(freezable, null); + if (obj != null) + { + VerifyGetAsFrozen(obj); + } + Verify(freezable, property, false, 0); + } + } + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + private void Verify(Freezable freezable, PropertyInfo pi, bool isCollection, int index) + { + object[] indexObj = null; + if (isCollection) + { + indexObj = new object[] { index }; + } + // Get a subobject, and freeze it, so that we can test GetAsFrozenTest + Freezable obj = (Freezable)pi.GetValue(freezable, indexObj); + if (obj == null) + { + return; + } + + obj.Freeze(); + + Freezable clonedObj = freezable.GetAsFrozen(); + Freezable clonedSubObj = (Freezable)pi.GetValue(clonedObj, indexObj); + if (pi.Name == "Inverse" && TypeHelper.IsDerivative(freezable.GetType(), "System.Windows.Media.Transform")) + { + // This is by design, Transform.Inverse return a new instance everytime. + return; + } + if (clonedSubObj != obj || !clonedObj.IsFrozen) + { + GlobalLog.LogEvidence(freezable.GetType().ToString() + " does not stop cloning when sub object " + pi.Name + " is frozen"); + failures.Add(freezable.GetType().ToString() + " does not stop cloning when sub object " + pi.Name + " is frozen"); + passed &= false; + + } + } + + + /****************************************************************************** + * Function: VerifyForCollection + ******************************************************************************/ + private void VerifyForCollection(IEnumerable freezable, PropertyInfo pi) + { + int i = 0; + foreach (Freezable f in freezable) + { + VerifyGetAsFrozen(f); + Verify((Freezable)freezable, pi, true, i); + i++; + } + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/MultiThreadsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/MultiThreadsTest.cs new file mode 100644 index 000000000..85545f4b4 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/MultiThreadsTest.cs @@ -0,0 +1,278 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Security; +using System.Security.Policy; +using System.Windows; +using System.Windows.Threading; + +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: CopyTest + **********************************************************************************/ + public class MultiThreadsTest : FreezablesObjectsBase + { + #region Private Data + private Type _freezablePropertyType; + private Freezable _freezable; + private DispatcherFrame _dispatcherFrameInRunTest; + private DispatcherFrame _dispatcherFrameInCreateNewThread; + #endregion + + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public MultiThreadsTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + // This test does the following: + // For each freezable that we get from the base class do the followng: + // -Enumerate property of a feezable. For example Pen has Brush property + // -Create a freezable of that type. In this case Brush2 from another thread + // -Then try to modify or read the value and catch the exeception. + // -If the specific exception is caught with the correct message we pass, else we fail + // -If no exception raise, we fail. + public override void RunTest() + { + object result = null; + + Dispatcher.CurrentDispatcher.BeginInvoke( + DispatcherPriority.Normal, + new DispatcherOperationCallback(DoSetup), + (object)result + ); + _dispatcherFrameInRunTest = new DispatcherFrame(); + Dispatcher.PushFrame(_dispatcherFrameInRunTest); + + } + + /****************************************************************************** + * Function: DoSetup + ******************************************************************************/ + private object DoSetup(object result) + { + // We get freezables from the base class + foreach (Freezable f in freezables) + { + TestMultiThread(f); + } + return result; + } + + /****************************************************************************** + * Function: TestMultiThread + ******************************************************************************/ + private void TestMultiThread(Freezable f) + { + Type t = f.GetType(); + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo property in pi) + { + if (!TypeHelper.IsFreezable(property.PropertyType)) + { + continue; + } + if (DoesCauseStackOverflow(f, property)) + { + // When GetValue from some object (ex: MatrixTransform) + // The property value that I get is the same object as it class + // This will cause stack overflow, as this process is going thru + // Infinite loop. So I have to do this to prevent stack overflow from + // happening. + continue; + } + if (f is IEnumerable) + { + ModifyAndVerify(f, property); + // Test freeze, setvalue for each item in freezable collection + foreach (Freezable freezableItem in (IEnumerable)f) + { + TestMultiThread(freezableItem); + } + + } + else + { + Freezable subFreezable = (Freezable)property.GetValue(f, null); + if (subFreezable != null) + { + TestMultiThread(subFreezable); + } + ModifyAndVerify(f, property); + } + } + _dispatcherFrameInRunTest.Continue = false; + + } + + /****************************************************************************** + * Function: ModifyAndVerify + ******************************************************************************/ + private void ModifyAndVerify(Freezable f, PropertyInfo property) + { + + if (!TypeHelper.IsFreezable(property.PropertyType)) + { + goto Exit; + } + if (f is IEnumerable) + { + _freezablePropertyType = f.GetType(); + } + else + { + _freezablePropertyType = property.PropertyType; + } + // Make new thread to create freezable object of that property type then modify + System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(CreateNewThread)); + thread.Start(); + thread.Join(); + // This freezable is created from another thread - CreateNewThread() + if (_freezable == null) + { + goto Exit; + } + + try + { + if (!_freezable.IsFrozen) + { + // if no exception, fail the test + GlobalLog.LogEvidence("Reading freezable property " + _freezable.GetType().ToString() + " from another thread does not cause InvalidOperationException, expecting one"); + failures.Add("Reading freezable property " + _freezable.GetType().ToString() + " from another thread into does not cause InvalidOperationException, expecting one"); + passed &= false; + } + } + catch (System.InvalidOperationException e) + { + //GlobalLog.LogEvidence("Catch InvalidOperationException when Freeze()"); + LogTest(e, _freezable, "Freezing a freezable from anoter thread"); + + } + Exit: + _dispatcherFrameInRunTest.Continue = false; + } + + /****************************************************************************** + * Function: TestFreezableCollection + ******************************************************************************/ + private void TestFreezableCollection(Freezable sourceFreezable) + { + try + { + // Reading value from another tread should raise the exception. + foreach (Freezable f in (IEnumerable)sourceFreezable) + { + GlobalLog.LogEvidence("Reading freezable " + sourceFreezable.GetType().ToString() + " from another thread does not cause InvalidOperationException, expecting one"); + failures.Add("Reading freezable " + sourceFreezable.GetType().ToString() + " from another thread does not cause InvalidOperationException, expecting one"); + passed &= false; + } + } + catch (InvalidOperationException e) + { + // GlobalLog.LogEvidence("Catch InvalidOperationException when reading value"); + LogTest(e, sourceFreezable, "Reading value"); + } + } + + /****************************************************************************** + * Function: CreateNewThread + ******************************************************************************/ + private void CreateNewThread() + { + Dispatcher.CurrentDispatcher.BeginInvoke( + DispatcherPriority.ApplicationIdle, + new DispatcherOperationCallback(MakeFreezable), + null); + + _dispatcherFrameInCreateNewThread = new DispatcherFrame(); + Dispatcher.PushFrame(_dispatcherFrameInCreateNewThread); + + } + + /****************************************************************************** + * Function: MakeFreezable + ******************************************************************************/ + private object MakeFreezable(object arg) + { + if (_freezablePropertyType.ToString().EndsWith("Collection")) + { + _freezable = (Freezable)PredefinedObjects.MakeCollection(_freezablePropertyType.ToString()); + } + else + { + _freezable = (Freezable)PredefinedObjects.MakeValue(_freezablePropertyType); + } + _dispatcherFrameInCreateNewThread.Continue = false; + return arg; + } + + /****************************************************************************** + * Function: LogTest + ******************************************************************************/ + private void LogTest(InvalidOperationException e, Freezable freezable, Freezable f, string description) + { + + if (e.TargetSite.Name != "VerifyAccess") + { + GlobalLog.LogEvidence(description + freezable.GetType().ToString() + " from another thread into " + f.GetType().ToString() + " has different exception TargetSite: " + e.TargetSite.Name); + failures.Add(description + freezable.GetType().ToString() + " from another thread into " + f.GetType().ToString() + " has different exception TargetSite: " + e.TargetSite.Name); + passed &= false; + } + + } + + /****************************************************************************** + * Function: LogTest + ******************************************************************************/ + private void LogTest(InvalidOperationException e, Freezable freezable, string description) + { + + if (e.TargetSite.Name != "VerifyAccess") + { + GlobalLog.LogEvidence(description + freezable.GetType().ToString() + " has different exception TargetSite: " + e.TargetSite.Name); + failures.Add(description + freezable.GetType().ToString() + " has different exception TargetSite: " + e.TargetSite.Name); + passed &= false; + } + + } + /****************************************************************************** + * Function: LogTest + ******************************************************************************/ + private void LogTest(TargetInvocationException e, Freezable freezable, Freezable f, string description) + { + + if (e.InnerException.TargetSite.Name != "VerifyAccess" && e.InnerException.TargetSite.Name != "EnsureConsistentDispatchers" && e.InnerException.TargetSite.Name != "SetPrologue") + { + GlobalLog.LogEvidence(description + freezable.GetType().ToString() + " from another thread into " + f.GetType().ToString() + " has different exception TargetSite: " + e.InnerException.TargetSite.Name); + failures.Add(description + freezable.GetType().ToString() + " from another thread into " + f.GetType().ToString() + " has different exception TargetSite: " + e.InnerException.TargetSite.Name); + passed &= false; + } + + } + #endregion + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/SetAndClearDPTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/SetAndClearDPTest.cs new file mode 100644 index 000000000..6737a4578 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesObjects/SetAndClearDPTest.cs @@ -0,0 +1,134 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Xml; +using System.Reflection; +using System.Collections; +using System.Security; +using System.Security.Policy; +using System.Windows; +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.Logging; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: EventTest + **********************************************************************************/ + public class SetAndClearDPTest : FreezablesObjectsBase + { + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + public SetAndClearDPTest(string testName, string objName) : base(testName, objName) + { + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + public override void RunTest() + { + foreach (Freezable freezable in freezables) + { + Type type = freezable.GetType(); + FieldInfo[] fieldInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + foreach (FieldInfo field in fieldInfo) + { + if (field.FieldType.ToString() != "System.Windows.DependencyProperty") + { + continue; + } + DependencyProperty dp = (DependencyProperty)field.GetValue(freezable); + object dpValue = PredefinedObjects.MakeValue(dp.PropertyType); + if (dpValue == null) + { + // Nothing much the test can do + // This test depends on PredefineObject, if PredefinedObject + // cannot make the value, it returns null. + continue; + } + //GlobalLog.LogEvidence("FieldName " + field.Name); + TestSetDP(freezable, dp, dpValue); + TestClearDP(freezable, dp, dpValue); + } + } + } + + /****************************************************************************** + * Function: TestSetDP + ******************************************************************************/ + private void TestSetDP(Freezable freezable, DependencyProperty dp, object dpValue) + { + freezable.Freeze(); + try + { + // SetValue of DP to a frozen freezable should cause exception + freezable.SetValue(dp, dpValue); + + // fail, if not exception raise + FailTest(dp, freezable, "Setting value "); + } + catch (InvalidOperationException e) + { + LogTest(e, dp, freezable, "Setting Value "); + } + } + + /****************************************************************************** + * Function: TestClearDP + ******************************************************************************/ + private void TestClearDP(Freezable freezable, DependencyProperty dp, object dpValue) + { + // Make a copy, SetValue, freeze it, then ClearValue and expect the exception + freezable = freezable.Clone(); + freezable.SetValue(dp, dpValue); + freezable.Freeze(); + try + { + freezable.ClearValue(dp); + + // ClearValue of DP to a frozen freezable should cause exception + FailTest(dp, freezable, "Clearing value "); + } + catch (InvalidOperationException e) + { + LogTest(e, dp, freezable, "Clearing Value "); + } + } + + /****************************************************************************** + * Function: LogTest + ******************************************************************************/ + private void LogTest(InvalidOperationException e, DependencyProperty dp, Freezable freezable, string Message) + { + if (e.TargetSite.Name != "SetValueCommon" && e.TargetSite.Name != "ClearValueCommon") + { + FailTest(dp, freezable, Message); + } + // If no failure, Framework will handle the Log Pass + } + + /****************************************************************************** + * Function: FailTest + ******************************************************************************/ + private void FailTest(DependencyProperty dp, Freezable freezable, String Message) + { + GlobalLog.LogEvidence(Message + dp.GetType().ToString() + " into a frozen freezable " + freezable.GetType().ToString() + " does not cause causes InvalidOperationException, expecting one"); + failures.Add(Message + dp.GetType().ToString() + " into a frozen freezable " + freezable.GetType().ToString() + " does not cause causes InvalidOperationException, expecting one"); + passed &= false; + } + #endregion + + } +} + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CloneCurrentValuePatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CloneCurrentValuePatternsTest.cs new file mode 100644 index 000000000..f8d4026b0 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CloneCurrentValuePatternsTest.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test CloneCurrentValue + + * Description: This test call CloneCurrentValue() then does deep comparion + ************************************************************/ + +using System; +using System.Reflection; +using System.Windows; + +using Microsoft.Test; +using Microsoft.Test.Graphics; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: CloneCurrentValuePatternsTest + **********************************************************************************/ + internal class CloneCurrentValuePatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal CloneCurrentValuePatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result log) + : base(log) + { + testName = "CloneCurrentValuePatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (IsKnownIssue(t)) + { + return; + } + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + // create an instance of this type + Freezable freezable = null; + if (FreezablesPatternsHelper.IsSpecialFreezable(t)) + { + freezable = FreezablesPatternsHelper.CreateSpecialFreezable(t); + } + else + { + freezable = FreezablesPatternsHelper.CreateNewChangeable(t); + } + + if (freezable != null) + { + //Console.WriteLine("GoodFreezable: " + freezable.GetType().ToString()); + Type type = freezable.GetType(); + MethodInfo method = type.GetMethod("CloneCurrentValue", BindingFlags.Public | BindingFlags.Instance); + if (method == null) + { + + throw new ApplicationException("Could not find CloneCurrentValue method on " + type.Name); + } + + Freezable currentFreezable = (Freezable)method.Invoke(freezable, null); + // They should be equal + if (!ObjectUtils.DeepEquals(freezable, currentFreezable)) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": CloneCurrentValue for this object should be equal"); + } + // Freeze the freezable, then GetCurrentValue() again + // Objects should not be equal + freezable.Freeze(); + currentFreezable = (Freezable)method.Invoke(freezable, null); + if (ObjectUtils.DeepEquals(freezable, currentFreezable)) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": CloneCurrentValue from a frozen freeze should not be equal"); + } + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/ConstructorPatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/ConstructorPatternsTest.cs new file mode 100644 index 000000000..d0cf79fef --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/ConstructorPatternsTest.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test freezable Constructors + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Windows; +using System.Threading; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: ConstructorPatternsTest + **********************************************************************************/ + internal class ConstructorPatternsTest : FreezablesPatternsBase + { + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal ConstructorPatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "ConstructorPatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (t.IsAbstract || IsKnownIssue(t)) + { + return; + } + + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + ConstructorInfo[] ci = t.GetConstructors(); + if (t.ToString() == "System.Windows.Media.Imaging.RenderTargetBitmap") + GlobalLog.LogStatus(""); + + // for each constructor + for (int i = 0; i < ci.Length; i++) + { + try + { + System.Windows.Freezable obj = FreezablesPatternsHelper.MakeChangeableObject(t, ci, i); + + if (obj != null) + { + if (obj.CanFreeze) + { + if (obj.IsFrozen) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": IsFrozen is " + obj.IsFrozen ); + } + } + } + + } + catch (System.Reflection.TargetInvocationException e) + { + if (!e.InnerException.ToString().StartsWith("System.ArgumentNullException")) + { + GlobalLog.LogEvidence(" !!!CTOR: Exception: {0}", e.InnerException.ToString()); + result.failures.Add(t.ToString() + ": System.ArgumentNullException - " + e.InnerException.ToString()); + result.passed &= false; + } + } + catch (System.NotImplementedException e) + { + GlobalLog.LogEvidence(" !!!CTOR: Exception: {0}", e.ToString()); + result.failures.Add(t.ToString() + ": !!!CTOR Exception - " + e.ToString()); + result.passed &= false; + } + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CopyPatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CopyPatternsTest.cs new file mode 100644 index 000000000..7db5d0b01 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/CopyPatternsTest.cs @@ -0,0 +1,129 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test Copy + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Windows; + +using Microsoft.Test; +using Microsoft.Test.Graphics; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /********************************************************************************** + * CLASS: CopyPatternsTest + **********************************************************************************/ + internal class CopyPatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal CopyPatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "CopyPatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (IsKnownIssue(t)) + { + return; + } + + try + { + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + // check if they implement Copy method + MethodInfo mi = t.GetMethod("Clone", BindingFlags.Public | BindingFlags.Instance , null, new Type[0], new ParameterModifier[0]); + + if (mi == null) + { + // Copy method not found + result.passed &= false; + result.failures.Add(t.ToString() + ": Clone method not found"); + GlobalLog.LogEvidence(" !!!Clone method not found for type {0}", t.ToString()); + return; + } + + // create an instance of this type + Freezable freezable = null; + if (FreezablesPatternsHelper.IsSpecialFreezable(t)) + { + freezable = FreezablesPatternsHelper.CreateSpecialFreezable(t); + } + else + { + freezable = FreezablesPatternsHelper.CreateNewChangeable(t); + } + if (freezable != null) + { + //GlobalLog.LogEvidence("GoodFreezable: " + freezable.GetType().ToString()); + Type type = freezable.GetType(); + MethodInfo method = type.GetMethod("Clone", BindingFlags.Public | BindingFlags.Instance); + if (method == null) + { + + throw new ApplicationException("Could not find Clone method on " + type.Name); + + } + Freezable clonedFreezable = (Freezable)method.Invoke(freezable, null); + + if (clonedFreezable.IsFrozen) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": IsFrozen is " + clonedFreezable.IsFrozen); + + } + if (!ObjectUtils.DeepEqualsToAnimatable(freezable, clonedFreezable)) + { + + result.passed &= false; + result.failures.Add(t.ToString() + "Clone() did not produce exact copy"); + + } + } + } + catch (System.Reflection.TargetInvocationException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + "-!!!COPY: Exception: " + e.InnerException.ToString()); + GlobalLog.LogEvidence(" !!!COPY: Exception: {0}", e.InnerException.ToString()); + } + catch (System.Reflection.AmbiguousMatchException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": copy method not found"); + GlobalLog.LogEvidence(" !!!COPY method not found: Exception: {0}", e.ToString()); + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/EventPatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/EventPatternsTest.cs new file mode 100644 index 000000000..2422e9683 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/EventPatternsTest.cs @@ -0,0 +1,555 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test freezable Event + + * + ************************************************************/ + +using System; +using System.Reflection; +using System.Windows; +using System.Threading; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: EventPatternsTest + **********************************************************************************/ + internal class EventPatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal EventPatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "EventPatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (t.IsAbstract || IsKnownIssue(t) || t.IsNotPublic) + { + return; + } + if (t.ToString() == "System.Windows.Media.Imaging.BitmapMetadata") + { + return; + } + + // + if (t.ToString() == "System.Windows.Media.MediaPlayer") + { + return; + } + + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + // Add event handler to "Changed", + EventPatternsTestFiring(t, "TestSingleEventFiring"); + + // Call Freeze, Add event handler + // Expected Exception raised + TestAddOrRemoveEvent(t, "TestAddEvent"); + + // Call Freeze, then remove event from "Changed" + // Expected Exception raised + TestAddOrRemoveEvent(t, "TestRemoveEvent"); + + // Test event on Complex freezable + // with SONU=ChangeableReference + FreezablesPatternsBaseReferenceForECT(t); + + // Test event on Complex freezable + // with SONU=ChangeableCopy + FreezablesPatternsBaseCopyForECT(t); + + // Add/Remove event handler many time to Changed property + EventPatternsTestFiring(t, "TestMultiEventFiring"); + } + + /****************************************************************************** + * Function: EventPatternsTestFiring + ******************************************************************************/ + /// + /// Create a Freezable of Type t and register it. + /// + /// The Type of the Freezable object to be tested. + /// Test name. + /// + private void EventPatternsTestFiring(Type t, string name) + { + // create an instance of this type + Freezable obj = null; + + if (FreezablesPatternsHelper.IsSpecialFreezable(t)) + { + obj = FreezablesPatternsHelper.CreateSpecialFreezable(t); + } + else + { + obj = FreezablesPatternsHelper.CreateNewChangeable(t); + } + if (obj != null) + { + TestObj testobj = new TestObj(obj, result); + testobj.RegisterEvent(obj, name); + } + } + + + /****************************************************************************** + * Function: TestAddOrRemoveEvent + ******************************************************************************/ + /// + /// Adding/Remove event on an Unchangeable object should throw. + /// + /// The Type of the Freezable object to be tested. + /// Test name. + /// + private void TestAddOrRemoveEvent(Type t, string testName) + { + Freezable obj = FreezablesPatternsHelper.CreateNewChangeable(t); + + if (FreezablesPatternsHelper.IsSpecialCase(t, obj)) + { + return; + } + + if (obj != null && obj.CanFreeze) + { + TestObj testObj = new TestObj(obj, result); + try + { + obj.Freeze(); + // testName could be AddEvent or RemoveEvent + testObj.RegisterEvent(obj, testName); + + // if no exception thrown, fail the test now + GlobalLog.LogEvidence("An InvalidOperationException was expected, but was not thrown"); + } + catch (System.InvalidOperationException e) + { + // Expected InvalidOperationExpection, since we call + // Freeze before adding/removing event + //if (!e.ToString().Contains("must have IsFrozen")) + //{ + // result.passed &= false; + // result.failures.Add(t.ToString() + ": " + testName + " - Unexpected Exceptiion : " + e.ToString()); + // GlobalLog.LogEvidence("{0} - Unexpected Exception : {1}", testName, e.ToString()); + //} + string s = e.ToString(); + } + } + } + + /****************************************************************************** + * Function: FreezablesPatternsBaseReferenceForECT + ******************************************************************************/ + /// + /// ChangeableReference for Embedded Freezable Type (complex freezable). + /// + /// The Type of the Freezable object to be tested. + /// + private void FreezablesPatternsBaseReferenceForECT(Type t) + { + // create object2 and invoke the get properties on it + Freezable obj1 = FreezablesPatternsHelper.CreateNewChangeable(t); + Freezable obj2 = FreezablesPatternsHelper.CreateNewChangeable(t); + + if (FreezablesPatternsHelper.IsSpecialCase(t, obj1) || obj1 == null) + { + return; + } + + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + for (int i = 0; i < pi.Length; i++) + { + Freezable complexChangeable = FreezablesPatternsHelper.GetComplexChangeable(pi[i], obj1); + + if (complexChangeable == null) + { + continue; + } + + if (!complexChangeable.IsFrozen) + { + if (!pi[i].CanWrite) + { + return; + } + // need to attacht to obj2 + pi[i].SetValue(obj2, complexChangeable, null); + + TestObj testObj1 = new TestObj(obj1, result); + testObj1.RegisterEvent(obj1, "TestAddEventOnComplexChangeable1"); + + TestObj testObj2 = new TestObj(obj2, result); + testObj2.RegisterEvent(obj2, "TestAddEventOnComplexChangeable2"); + + TestObj testObj3 = new TestObj(complexChangeable, result); + testObj3.RegisterEvent(complexChangeable, "TestAddEventOnComplexChangeable3"); + + // This modification should trigger the events for all objects (obj1, complexChangeable) + ((Freezable)complexChangeable).Freeze(); + if (!testObj1.IsComplexTypeEvent1Fired || !testObj2.IsComplexTypeEvent2Fired || !testObj3.IsComplexTypeEvent3Fired) + { + result.passed &= false; + if (!testObj1.IsComplexTypeEvent1Fired) + { + result.failures.Add(obj1.GetType().ToString() + " : Event not fired on Complex Freezable"); + GlobalLog.LogEvidence(" {0} : Event did not fire on Complex Freezable", obj1.GetType().ToString()); + } + + if (!testObj2.IsComplexTypeEvent2Fired) + { + result.failures.Add(obj2.GetType().ToString() + " : Event not fired on Complex Freezable"); + GlobalLog.LogEvidence(" {0} : Event did not fire Complex Freezable", obj2.GetType().ToString()); + } + + if (!testObj3.IsComplexTypeEvent3Fired) + { + result.failures.Add(complexChangeable.GetType().ToString() + " : Event not fired on Complex Freezable"); + GlobalLog.LogEvidence(" {0} : Event did not fire Complex Freezable", complexChangeable.GetType().ToString()); + } + } + } + } + } + + /****************************************************************************** + * Function: FreezablesPatternsBaseCopyForECT + ******************************************************************************/ + /// + /// ChangeableCopy for Embedded Freezable Type (complex freezable). + /// + /// The Type of the Freezable object to be tested. + /// + private void FreezablesPatternsBaseCopyForECT(Type t) + { + Freezable obj1 = FreezablesPatternsHelper.CreateNewChangeable(t); + + if (FreezablesPatternsHelper.IsSpecialCase(t, obj1) || obj1 == null) + { + return; + } + + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + + for (int i = 0; i < pi.Length; i++) + { + Freezable complexChangeable = FreezablesPatternsHelper.GetComplexChangeable(pi[i], obj1); + if (complexChangeable == null) + { + continue; + } + if (!complexChangeable.IsFrozen) + { + if (!pi[i].CanWrite) + { + return; + } + + // need to attacht to obj1 + pi[i].SetValue(obj1, complexChangeable, null); + + // GetValue here + Freezable complexValue = (Freezable)pi[i].GetValue(obj1, null); + TestObj testObj1 = new TestObj(obj1, result); + + testObj1.RegisterEvent(obj1, "TestAddEventOnComplexChangeable1"); + + TestObj testObj2 = new TestObj(complexChangeable, result); + + testObj2.RegisterEvent(complexValue, "TestAddEventOnComplexChangeable3"); + + // This modification should trigger the events for all objects (obj1, complexChangeable) + ((Freezable)complexValue).Freeze(); + if (!testObj1.IsComplexTypeEvent1Fired || !testObj2.IsComplexTypeEvent3Fired) + { + result.passed &= false; + if (!testObj1.IsComplexTypeEvent1Fired) + { + result.failures.Add(obj1.GetType().ToString() + " : Event not fired on Complex Freezable"); + GlobalLog.LogEvidence(" {0} : Event did not fire on Complex Freezable", obj1.GetType().ToString()); + } + + if (!testObj2.IsComplexTypeEvent3Fired) + { + result.failures.Add(complexChangeable.GetType().ToString() + " : Event not fired on Complex Freezable"); + GlobalLog.LogEvidence(" {0} : Event did not fire Complex Freezable", complexChangeable.GetType().ToString()); + } + } + } + } + } + #endregion + } + + + /********************************************************************************** + * CLASS: EventPatternsTest + **********************************************************************************/ + internal class TestObj + { + #region Private Data + private string _className; + private Microsoft.Test.ElementServices.Freezables.Utils.Result _result; + internal bool IsEventFired; + internal bool IsComplexTypeEvent1Fired; + internal bool IsComplexTypeEvent2Fired; + internal bool IsComplexTypeEvent3Fired; + internal int numEventFired; + #endregion + + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal TestObj(Freezable obj, Microsoft.Test.ElementServices.Freezables.Utils.Result af) + { + _result = af; + _className = obj.GetType().ToString(); + IsEventFired = false; + IsComplexTypeEvent1Fired = false; + IsComplexTypeEvent2Fired = false; + IsComplexTypeEvent3Fired = false; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: RegisterEvent + ******************************************************************************/ + /// + /// Attach an event handler for the Changed event. In some cases, test event + /// firing when calling Freeze(). + /// + /// The Freezable object to be tested. + /// Test name. + /// + internal void RegisterEvent(Freezable obj, string testName) + { + switch (testName) + { + case "TestSingleEventFiring": + obj.Changed += new EventHandler(EventFiringHandler); + // Freeze to make the even fire + obj.Freeze(); + if (!IsEventFired) + { + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Event not fired"); + GlobalLog.LogEvidence(" {0} : Event did not fire", obj.GetType().ToString()); + } + + // reset + IsEventFired = false; + break; + case "TestMultiEventFiring": + // Add change handler 10000 time + // make sure it fired >= 10000 times + // This because some freezable may be nested + // and the nested freezable (children) may or may not + // fired the event to its parent. + AddEventFiringHandler(obj, 10000); + numEventFired = 0; + obj.Freeze(); + + if (numEventFired < 10000) + { + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Number of event fired is : " + numEventFired + " Expected: >= " + 10000); + GlobalLog.LogEvidence(" {0} : Number of event fired is {1} Expected >= " + 10000, obj.GetType().ToString(), numEventFired); + } + // Add change handler 10000 time + // Remove change hander 1 time + // make sure it fired >= 9999 times + obj = obj.Clone(); + AddEventFiringHandler(obj, 10000); + AddEventFiringHandler(obj, 1); + numEventFired = 0; + obj.Freeze(); + + if (numEventFired < 9999) + { + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Number of event fired is : " + numEventFired + " Expected: >= " + 9999); + GlobalLog.LogEvidence(" {0} : Number of event fired is {1} Expected >= " + 9999, obj.GetType().ToString(), numEventFired); + } + // Add change handler 100 + // Then remove 100 time + // Make sure event not fired + numEventFired = 0; + // Make unfrozen freezable + obj = obj.Clone(); + AddEventFiringHandler(obj, 100); + RemoveEventFiringHandler(obj, 100); + obj.Freeze(); + if (numEventFired != 0) + { + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Number of event fired is : " + numEventFired + " Expected: 0"); + GlobalLog.LogEvidence(" {0} : Number of event fired is {1} Expected 0", obj.GetType().ToString(), numEventFired); + } + // Add Event 100 time, + // Remove 101 time + // make sure it throw + + obj = obj.Clone(); + AddEventFiringHandler(obj, 100); + try + { + RemoveEventFiringHandler(obj, 101); + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Number of event fired is : " + numEventFired + " Expected: System.ArgumentException"); + GlobalLog.LogEvidence(" {0} : Number of event fired is {1} Expected an Exception", obj.GetType().ToString(), numEventFired); + } + catch (ArgumentException e) + { + Type expectedErrorType = typeof(System.ArgumentException); + + if (expectedErrorType != e.GetType() && !e.GetType().IsSubclassOf(expectedErrorType)) + { + _result.passed &= false; + _result.failures.Add(obj.GetType().ToString() + " : Number of event fired is : " + numEventFired + "RegisterEvent - Expected System.ArgumentException"); + } + } + break; + case "TestAddEvent": + obj.Changed += new EventHandler(AddEventHandler); + break; + + case "TestAddEventOnComplexChangeable1": + obj.Changed += new EventHandler(AddComplexTypeEventHandler1); + break; + + case "TestAddEventOnComplexChangeable2": + obj.Changed += new EventHandler(AddComplexTypeEventHandler2); + break; + + case "TestAddEventOnComplexChangeable3": + obj.Changed += new EventHandler(AddComplexTypeEventHandler3); + break; + + case "TestRemoveEvent": + obj.Changed -= new EventHandler(RemoveEventHandler); + break; + + default: + throw new ApplicationException("Unknown Test Name: " + testName); + } + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: DoNothingEventHandler + ******************************************************************************/ + private void DoNothingEventHandler(Object sender, EventArgs args) + { + } + + /****************************************************************************** + * Function: EventFiringHandler + ******************************************************************************/ + private void EventFiringHandler(Object sender, EventArgs args) + { + IsEventFired = true; + numEventFired++; + } + + /****************************************************************************** + * Function: AddEventHandler + ******************************************************************************/ + private void AddEventHandler(Object sender, EventArgs args) + { + GlobalLog.LogEvidence("This event should not fire"); + } + + /****************************************************************************** + * Function: AddComplexTypeEventHandler1 + ******************************************************************************/ + private void AddComplexTypeEventHandler1(Object sender, EventArgs args) + { + IsComplexTypeEvent1Fired = true; + } + + /****************************************************************************** + * Function: AddComplexTypeEventHandler2 + ******************************************************************************/ + private void AddComplexTypeEventHandler2(Object sender, EventArgs args) + { + IsComplexTypeEvent2Fired = true; + } + + /****************************************************************************** + * Function: AddComplexTypeEventHandler3 + ******************************************************************************/ + private void AddComplexTypeEventHandler3(Object sender, EventArgs args) + { + IsComplexTypeEvent3Fired = true; + } + + /****************************************************************************** + * Function: RemoveEventHandler + ******************************************************************************/ + private void RemoveEventHandler(Object sender, EventArgs args) + { + ((Freezable)sender).Freeze(); + ((Freezable)sender).Changed -= new EventHandler(DoNothingEventHandler); + } + + /****************************************************************************** + * Function: AddEventFiringHandler + ******************************************************************************/ + private void AddEventFiringHandler(Freezable freezable, int count) + { + for (int i = 0; i < count; i++) + { + freezable.Changed += new EventHandler(EventFiringHandler); + + } + } + /****************************************************************************** + * Function: RemoveEventFiringHandler + ******************************************************************************/ + private void RemoveEventFiringHandler(Freezable freezable, int count) + { + for (int i = 0; i < count; i++) + { + freezable.Changed -= new EventHandler(EventFiringHandler); + + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablePatternsBase.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablePatternsBase.cs new file mode 100644 index 000000000..b83496004 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablePatternsBase.cs @@ -0,0 +1,201 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +//************************************************************* +// +// +// Program: TestChangeble base class + + +//************************************************************* +using System; +using System.Xml; +using System.Windows; + +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: FreezablesPatternsBase + **********************************************************************************/ + internal abstract class FreezablesPatternsBase + { + + #region Private Data + internal Microsoft.Test.ElementServices.Freezables.Utils.Result result; + internal string testName; + #endregion + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal FreezablesPatternsBase(Microsoft.Test.ElementServices.Freezables.Utils.Result logResult) + { + result = logResult; + } + #endregion + + + #region Internal Members + + internal abstract void Perform(Type t); + + /****************************************************************************** + * Function: LoadChangeableFile + ******************************************************************************/ + /// + /// Create and load a new XmlDocument. + /// + /// An XmlDocument loaded from FreezablesPatterns.xtc. + internal XmlDocument LoadChangeableFile() + { + XmlDocument doc = new XmlDocument(); + try + { + doc.Load("FreezablesPatterns.xtc"); + } + catch (Exception) + { + throw new ApplicationException("Unable to load FreezablesPatterns.xtc file"); + } + return doc; + } + + /****************************************************************************** + * Function: IsKnownIssue + ******************************************************************************/ + /// + /// Check for presence of Name and IssueType. + /// + /// The Type of the Freezable object to be tested. + /// + internal virtual bool IsKnownIssue(Type t) + { + XmlDocument doc = LoadChangeableFile(); + XmlElement changeableTest = (XmlElement)doc["FreezablesTest"]; + for (XmlNode testNameNode = changeableTest["TestName"]; testNameNode != null; testNameNode = testNameNode.NextSibling) + { + XmlAttribute name = testNameNode.Attributes["Name"]; + // Throw exception on IssueType because I want to enforce tester to enter whether it is by design + // or a KnownBug, it has nothing to do with more with the code. + XmlAttribute issue = testNameNode.Attributes["IssueType"]; + if (name == null || issue == null) + { + throw new ApplicationException("TestName Element must have attributes Name=, IssueType="); + } + if (name.Value == testName) + { + for (XmlNode classNode = testNameNode["Class"]; classNode != null; classNode = classNode.NextSibling) + { + XmlAttribute className = classNode.Attributes["Name"]; + if (className == null) + { + throw new ApplicationException("Class element must have attribute Name="); + } + if (className.Value == t.ToString()) + { + return true; + } + } + } + + } + return false; + } + #endregion + } + + + /********************************************************************************** + * CLASS: TestGetAndSetChangeable + **********************************************************************************/ + internal abstract class TestGetAndSetChangeable : FreezablesPatternsBase + { + #region Private Data + protected System.Windows.Freezable obj = null; + protected string pName = null; + #endregion + + #region Constructor + /****************************************************************************** + * Function: TestGetAndSetChangeable + ******************************************************************************/ + internal TestGetAndSetChangeable(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: IsKnownIssue + ******************************************************************************/ + /// + /// Overrides check for presence of Name and IssueType. + /// + /// The Type of the Freezable object to be tested. + /// + internal override bool IsKnownIssue(Type t) + { + if (pName == "Item" && ((System.Collections.ICollection)obj).Count == 0) + { + // Some Animation collection classes does not have public constuctor + // that enable us to construct properly. This is the work around for + // the OutOfRange exception. + return true; + } + if (pName == "Context" || pName == "DependencyObjectType") + { + return true; + } + + XmlDocument doc = LoadChangeableFile(); + // + XmlElement changeableTest = (XmlElement)doc["FreezablesTest"]; + for (XmlNode testNameNode = changeableTest["TestName"]; testNameNode != null; testNameNode = testNameNode.NextSibling) + { + XmlAttribute name = testNameNode.Attributes["Name"]; + XmlAttribute issue = testNameNode.Attributes["IssueType"]; + if (name == null || issue == null) + { + throw new ApplicationException("TestName Element must have attributes Name=, IssueType="); + } + if (name.Value == testName) + { + for (XmlNode classNode = testNameNode["Class"]; classNode != null; classNode = classNode.NextSibling) + { + XmlAttribute className = classNode.Attributes["Name"]; + if (className == null) + { + throw new ApplicationException("Class element must have attribute Name="); + } + if (t.ToString().StartsWith(className.Value)) + { + for (XmlNode propertyNode = classNode["Property"]; propertyNode != null; propertyNode = propertyNode.NextSibling) + { + XmlAttribute propertyName = propertyNode.Attributes["Name"]; + if (propertyName == null) + { + throw new ApplicationException("Property element must have attribute Name="); + } + if (propertyName.Value == pName) + { + return true; + } + } + } + } + } + + } + return false; + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatterns.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatterns.cs new file mode 100644 index 000000000..700f2d370 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatterns.cs @@ -0,0 +1,227 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2003 + * + * Program: Test freezable object properties + + * + ************************************************************/ + +using System; +using System.Windows; +using System.Reflection; +using System.Collections.Specialized; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\Patterns + + /// 2 + /// + /// Freezables tests + /// + /// + + [Test(2, "Freezables.Patterns", "FreezablesPatterns", SupportFiles=@"FeatureTests\ElementServices\FreezablesPatterns.xtc,FeatureTests\ElementServices\25DPI.jpg,FeatureTests\ElementServices\BORG.jpg")] + + /********************************************************************************** + * CLASS: FreezablesPatterns + **********************************************************************************/ + public class FreezablesPatterns : AvalonTest + { + #region Private Data + + public Microsoft.Test.ElementServices.Freezables.Utils.Result result; + private string _testName = ""; + private Type[] _types; + + #endregion + + + #region Constructor + + ////////////////////////////////////////////////////////////////////////////////////////////������� + // DISABLEDUNSTABLETEST: + // TestName: FreezablesPatterns(CloneCurrentValuePatternsTest) + // Area: ElementServices �� SubArea: Freezables.Patterns + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// +// [Variation("CloneCurrentValuePatternsTest")] + + [Variation("ConstructorPatternsTest")] + + ////////////////////////////////////////////////////////////////////////////////////////////������� + // DISABLEDUNSTABLETEST: + // TestName: FreezablesPatterns(CopyPatternsTest) + // Area: ElementServices �� SubArea: Freezables.Patterns + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// +// [Variation("CopyPatternsTest")] + + ////////////////////////////////////////////////////////////////////////////////////////////������� + // DISABLEDUNSTABLETEST: + // TestName: FreezablesPatterns(EventPatternsTest) + // Area: ElementServices �� SubArea: Freezables.Patterns + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// +// [Variation("EventPatternsTest")] + +// [Variation("GetCurrentValueAsFrozenPatternsTest")] + + ////////////////////////////////////////////////////////////////////////////////////////////������� + // DISABLEDUNSTABLETEST: + // TestName: FreezablesPatterns(FreezePatternsTest) + // Area: ElementServices �� SubArea: Freezables.Patterns + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// +// [Variation("FreezePatternsTest")] + + ////////////////////////////////////////////////////////////////////////////////////////////������� + // DISABLEDUNSTABLETEST: + // TestName: FreezablesPatterns(FreezeCorePatternsTest) + // Area: ElementServices �� SubArea: Freezables.Patterns + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// +// [Variation("FreezeCorePatternsTest")] + + + /****************************************************************************** + * Function: FreezablesPatterns Constructor + ******************************************************************************/ + // Input Parameter: TestName + public FreezablesPatterns(string inputValue) + { + _testName = inputValue; + + InitializeSteps += new TestStep(Initialize); + RunSteps += new TestStep(SelectTest); + RunSteps += new TestStep(Verify); + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: Initialize + ******************************************************************************/ + /// + /// Determines the Type requested by a fiven test case. + /// + /// Returns TestResult=True + private TestResult Initialize() + { + result = new Microsoft.Test.ElementServices.Freezables.Utils.Result(); + + Assembly dll = typeof(UIElement).Assembly; + _types = dll.GetTypes(); + + return TestResult.Pass; + } + + /****************************************************************************** + * Function: SelectTest + ******************************************************************************/ + /// + /// Carries out the requested Freezables tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult SelectTest() + { + FreezablesPatternsBase test = null; + + switch (_testName) + { + case "CloneCurrentValuePatternsTest": + test = new CloneCurrentValuePatternsTest(result); + break; + + case "ConstructorPatternsTest": + test = new ConstructorPatternsTest(result); + break; + + case "CopyPatternsTest": + test = new CopyPatternsTest(result); + break; + + case "EventPatternsTest": + test = new EventPatternsTest(result); + break; + + case "GetCurrentValueAsFrozenPatternsTest": + test = new GetCurrentValueAsFrozenPatternsTest(result); + break; + + case "FreezePatternsTest": + test = new FreezePatternsTest(result); + break; + + case "FreezeCorePatternsTest": + test = new FreezeCorePatternsTest(result); + break; + + default: + throw new ApplicationException("!!!Unknown test name: " + _testName); + } + + foreach (Type t in _types) + { + + if (TypeHelper.IsFreezable(t)) + { + test.Perform(t); + } + } + + return TestResult.Pass; + } + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// A TestResult, indicating whether or not the test passed. + private TestResult Verify() + { + // report the failures all together + if (!result.passed) + { + GlobalLog.LogEvidence("-------------------------------------------------"); + GlobalLog.LogEvidence("FAILURE REPORT"); + for (int i = 0; i < result.failures.Count; i++) + { + GlobalLog.LogEvidence(result.failures[i]); + } + } + + if (result.passed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatternsHelper.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatternsHelper.cs new file mode 100644 index 000000000..bc339c22e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezablesPatternsHelper.cs @@ -0,0 +1,406 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: FreezablesPatternsHelper class + + * + ************************************************************/ + +using System; +using System.IO; +using System.Reflection; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Threading; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Objects; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: FreezablesPatternsHelper + **********************************************************************************/ + public class FreezablesPatternsHelper + { + + #region Static Members + /****************************************************************************** + * Function: CheckNotChangeable + ******************************************************************************/ + /// + /// Checks if the object is immutable (IsFrozen == true). + /// + /// The Freezable object to be tested. + /// A boolean indicating whether or not the Freezable is immutable. + internal static bool CheckNotChangeable(Freezable obj) + { + if (obj.IsFrozen) + { + return true; + } + else + { + GlobalLog.LogEvidence("%%% FAIL ON CHECK NotChangeable STATE:{0} %%%", obj.IsFrozen); + return false; + } + } + + /****************************************************************************** + * Function: CheckDispatcher + ******************************************************************************/ + /// + /// Checks Dispatcher context. + /// + /// The Type of the Freezable object to be tested. + /// The Freezable object to be tested. + /// The Dispatcher context. + /// A boolean indicating whether or not the Dispatcher matches the context passed in. + internal static bool CheckDispatcher(Type t, Freezable obj, Dispatcher context) + { + if (obj.Dispatcher == context) + { + return true; + } + else + { + GlobalLog.LogEvidence("%%% Fail on Comparing Dispatcher: {0} %%%", t); + return false; + } + } + + + /****************************************************************************** + * Function: CheckNullDispatcher + ******************************************************************************/ + /// + /// Checks for null Dispatcher. + /// + /// The Type of the Freezable object to be tested. + /// The Freezable object to be tested. + /// A boolean indicating whether or not the Dispatcher is null. + internal static bool CheckNullDispatcher(Type t, Freezable obj) + { + if (obj.Dispatcher == null) + { + return true; + } + else + { + GlobalLog.LogEvidence("%%% Dispatcher is not null, after calling Freeze: {0}, {1} %%%", t, obj.Dispatcher); + + return false; + } + } + + #endregion + + /****************************************************************************** + * Function: CreateNewChangeable + ******************************************************************************/ + /// + /// Creates a new Freezable object. + /// + /// The Type of the Freezable object to be tested. + /// A Freezable object. + internal static Freezable CreateNewChangeable (Type t) + { + if (t.IsAbstract) + { + return null; + } + + Freezable retval = null; + ConstructorInfo[] ci = t.GetConstructors (); + + // for each constructor try to construct the object + // if successfull, return the object, else keep trying + // unit the loop is terminated + for (int i = 0; i < ci.Length; i++) + { + try + { + retval = FreezablesPatternsHelper.MakeChangeableObject(t, ci , i); + if (retval != null) + { + return retval; + } + } + catch (System.Reflection.TargetInvocationException e) + { + if (!e.InnerException.ToString ().StartsWith ("System.ArgumentNullException")) + { + GlobalLog.LogEvidence (" !!! NewObject: Exception: {0}", e.InnerException.ToString ()); + } + + return null; + } + } + + return retval; + } + + /****************************************************************************** + * Function: MakeChangeableObject + ******************************************************************************/ + /// + /// Creates a new Freezable object, based on Predefined objects. + /// + /// The Type of the Freezable object to be tested. + /// Parameter info. + /// Index for the Parameter info. + /// A Freezable object. + internal static Freezable MakeChangeableObject(Type t, ConstructorInfo [] ci , int index) + { + ParameterInfo[] pi = ci[index].GetParameters(); + Object[] args = new Object[pi.Length]; // the constructor arguments + // for each parameter + + for (int j = 0; j < pi.Length; j++) + { + if (j == pi[j].Position) // verify the position of the arguments + { + GlobalLog.LogStatus("Object: " + j.ToString() + "--" + pi[j].ParameterType.FullName); + + if (pi[j].ParameterType.FullName.ToString() == "System.Collections.ICollection" + || pi[j].ParameterType.FullName.StartsWith("System.Collections.Generic.IEnumerable")) + { + args[j] = PredefinedObjects.MakeCollection(t.FullName.ToString()); + if (args[j] == null) + { + return null; + } + } + else + { + args[j] = PredefinedObjects.MakeValue(pi[j].ParameterType); + } + } + } + ModifyArgsIfSpecialCase(t, pi, args); + + Freezable obj = (Freezable)t.InvokeMember(null, BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, args); + + return obj; + } + + /****************************************************************************** + * Function: GetComplexChangeable + ******************************************************************************/ + /// + /// Creates a new 'complex' Freezable object. + /// + /// Property info. + /// A Freezable object. + /// A Freezable object. + internal static Freezable GetComplexChangeable(PropertyInfo pi, Freezable obj) + { + if (pi.CanRead && !TypeHelper.IsType(pi.DeclaringType, "Freezable")) + { + // if complex freezable ECT + if (TypeHelper.IsFreezable(pi.PropertyType)) + { + // Object[] index = null; + if (pi.Name == "Item" && ((System.Collections.ICollection)obj).Count == 0) + { + // Some Animation collection classes does not have public constuctor + // that enable us to construct properly. This is the work around for + // the OutOfRange exception. + return null; + } + + // get the object + Freezable complexChangeable = (Freezable)pi.GetValue(obj, null); + + return complexChangeable; + } + + return null; + } + + return null; + } + #region SpecialCases + + /****************************************************************************** + * Function: IsSpecialCase + ******************************************************************************/ + /// + /// Creates a new 'complex' Freezable object. + /// + /// The Type of a Freezable object. + /// A Freezable object. + /// A boolean, indicating whether or not the Freezable is a special case. + internal static bool IsSpecialCase(Type t, Freezable obj) + { + // Special case, Cannot call Freeze on the Setter object + // whose target and property are null + /*if (t.ToString() == "System.Windows.Media.Animation.Setter" && ((Animation.Setter)obj).Target == null && ((Animation.Setter)obj).Property == null) + { + return true; + } + else */ + if (t.ToString() == "System.Windows.Media.VisualTargetSource") + { + return true; + } + else if (t.ToString() == "System.Windows.Media.Imaging.BitmapSource+ImageSourceNull") + { + return true; + } + + return false; + } + + + /****************************************************************************** + * Function: ModifyArgsIfSpecialCase + ******************************************************************************/ + /// + /// Creates a new 'complex' Freezable object. + /// + /// The Type of a Freezable object. + /// Parameter info. + /// Ana array of objects. + /// + private static void ModifyArgsIfSpecialCase(Type t, ParameterInfo[] pi, Object[] args) + { + if (t.ToString() == "System.Windows.Media.Imaging.BitmapImage" && pi.Length == 10) + { + // The 8th paramter (stride) of BitmapImage constructor needs value stride = Width * BytePerpixel + // Ctor forImageData: + // (Int32 pixelWidth, Int32 pixelHeight, Double dpiX, Double dpiY, PixelFormat pixelFormat, BitmapPalette imagePalette, Byte[] pixels, Int32 stride, Int32Rect sourceRect, BitmapSizeOptions sizeOptions) + PixelFormat p = (PixelFormat)args[4]; + args[6] = new byte[32]; + args[7] = (Int32)args[0] * p.BitsPerPixel / 8; + } + else if (t.ToString() == "System.Windows.Media.Animation.KeySpline" && pi.Length == 2 && pi[0].ParameterType.FullName.ToString() == "System.Windows.Point" && pi[1].ParameterType.FullName.ToString() == "System.Windows.Point") + { + // For Keyspline, points must be betwen 0.0 and 1.0 + args[0] = new Point(0.1, 0.2); + args[1] = new Point(0.2, 0.7); + } + else if (t.ToString() == "System.Windows.Media.Animation.Setter" && pi.Length == 3) + { + // For animation Setter, generic objects from PredefinesObject will not work. + args[0] = new LineGeometry(new Point(10, 10), new Point(20, 20)); //DependencyObject(); + args[1] = LineGeometry.StartPointProperty; + args[2] = new Point(1.0, 2.0); + } + else if (t.ToString() == "System.Windows.Media.Imaging.BitmapMetadata") + { + // The format of the bitmap image, specified as "gif", "jpeg", "png", or "tiff". + args[0] = "jpeg"; + } + else if (t.ToString() == "System.Windows.Media.Imaging.RenderTargetBitmap" && pi.Length == 5) + { + // pixelWidth and pixelHeight must be greater then 0 + args[0] = 1; + args[1] = 1; + } + } + + /****************************************************************************** + * Function: IsSpecialFreezable + ******************************************************************************/ + /// + /// Checks if the Freezable falls into a 'SpecialFreezable' category. + /// + /// The Type of a Freezable object. + /// A boolean, indicating whether or not the Type is a 'Special Freezable'. + internal static bool IsSpecialFreezable(Type t) + { + switch (t.ToString()) + { + case "System.Windows.Media.DrawingImage": + case "System.Windows.Media.Imaging.BitmapImage": + case "System.Windows.Media.Imaging.CroppedBitmap": + case "System.Windows.Media.Imaging.FormatConvertedBitmap": + case "System.Windows.Media.Imaging.TransformedBitmap": + return true; + + default: + return false; + } + } + + /****************************************************************************** + * Function: CreateSpecialFreezable + ******************************************************************************/ + /// + /// Creates a 'SpecialFreezable'. + /// + /// The Type of a Freezable object. + /// A Freezable. + internal static Freezable CreateSpecialFreezable(Type t) + { + string jpegFile = "25DPI.jpg"; + switch (t.ToString()) + { + case "System.Windows.Media.DrawingImage": + { + DrawingGroup drawingGroup = new DrawingGroup(); + drawingGroup.Opacity = 0.5; + drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(new Point(-1.5, -1.5), new Point(1.5, 1.5))); + + DrawingImage drawingImage = new DrawingImage(); + drawingImage.Drawing = drawingGroup; + return (Freezable)drawingImage; + } + case "System.Windows.Media.Imaging.BitmapImage": + { + BitmapImage image = new BitmapImage(); + image.BeginInit(); + image.UriSource = new Uri(jpegFile, UriKind.RelativeOrAbsolute); + image.EndInit(); + return (Freezable)image; + } + case "System.Windows.Media.Imaging.CroppedBitmap": + { + BitmapImage image = new BitmapImage(new Uri(jpegFile, UriKind.RelativeOrAbsolute)); + CroppedBitmap crop = new CroppedBitmap(); + + Int32Rect rect = new Int32Rect(0, 0, 5, 5); + + crop.BeginInit(); + crop.SourceRect = rect; + crop.Source = image; + crop.EndInit(); + return (Freezable)crop; + } + case "System.Windows.Media.Imaging.FormatConvertedBitmap": + { + BitmapImage image = new BitmapImage(new Uri(jpegFile, UriKind.RelativeOrAbsolute)); + FormatConvertedBitmap fmt = new FormatConvertedBitmap(); + fmt.BeginInit(); + fmt.Source = image; + fmt.DestinationFormat = PixelFormats.Gray32Float; + fmt.EndInit(); + return (Freezable)fmt; + } + case "System.Windows.Media.Imaging.TransformedBitmap": + { + BitmapImage image = new BitmapImage(new Uri(jpegFile, UriKind.RelativeOrAbsolute)); + TransformedBitmap tb = new TransformedBitmap(); + tb.BeginInit(); + tb.Source = image; + tb.Transform = new RotateTransform(90); + tb.EndInit(); + return (Freezable)tb; + } + default: + throw new ApplicationException("Unknown Freezable object: " + t.ToString()); + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezeCorePatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezeCorePatternsTest.cs new file mode 100644 index 000000000..5212c796d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezeCorePatternsTest.cs @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test FreezeCore + + * + ************************************************************/ +using System; +using System.Reflection; +using System.Windows; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; +using Microsoft.Test.ElementServices.Freezables.Objects; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: FreezeCorePatternsTest + **********************************************************************************/ + internal class FreezeCorePatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal FreezeCorePatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "FreezeCorePatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (!TypeHelper.IsComplexChangeable(t) || IsKnownIssue(t)) + { + return; + } + + try + { + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + // check that a complex freezable type implements the FreezeCore method + // create an object and invoke the FreezeCore method on it + Freezable obj = FreezablesPatternsHelper.CreateNewChangeable(t); + + if (obj != null && obj.CanFreeze) + { + // invoke the FreezeCore method + Object[] args = new Object[1]; // the FreezeCore method arguments + + args[0] = false; + + // invoke the FreezeCore method + t.InvokeMember("FreezeCore", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, args); + } + } + catch (System.Reflection.TargetInvocationException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + "-!!!FreezeCore Exception: " + e.InnerException.ToString()); + GlobalLog.LogEvidence(" !!!FreezeCore: Exception: {0}", e.InnerException.ToString()); + } + catch (System.MissingMethodException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": FreezeCore method not found"); + GlobalLog.LogEvidence(" !!!FreezeCore method not found: Exception: {0}", e.ToString()); + } + catch (System.Reflection.AmbiguousMatchException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": FreezeCore method not found"); + GlobalLog.LogEvidence(" !!!FreezeCore method not found: Exception: {0}", e.ToString()); + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezePatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezePatternsTest.cs new file mode 100644 index 000000000..63e6cd74f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/FreezePatternsTest.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2004 + * + * Program: Test Freeze + + * + ************************************************************/ +using System; +using System.Reflection; +using System.Windows; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: FreezePatternsTest + **********************************************************************************/ + internal class FreezePatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal FreezePatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "FreezePatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (IsKnownIssue(t)) + { + return; + } + try + { + GlobalLog.LogStatus("ClassName: " + t.ToString()); + + Freezable obj = null; + + // create an instance of this type + obj = FreezablesPatternsHelper.CreateNewChangeable(t); + + // if the object can be in an immutable state, check for its Freeze method + if (obj != null && obj.CanFreeze) + { + + MethodInfo mi = t.GetMethod("Freeze", BindingFlags.Public | BindingFlags.Instance); + + try + { + mi.Invoke(obj, null); + result.passed &= FreezablesPatternsHelper.CheckNotChangeable(obj); + } + catch (System.Reflection.TargetInvocationException e) + { + if (!obj.CanFreeze && e.Message.ToString().StartsWith("Exception has been thrown by the target of an invocation")) + { + result.passed &= true; + } + else + { + result.failures.Add(t.ToString() + "!!!NewObject : Exception: " + e.ToString()); + GlobalLog.LogEvidence(" !!! NewObject: Exception: {0}", e.ToString()); + result.passed &= false; + } + } + } + + obj = null; + } + catch (System.Reflection.AmbiguousMatchException e) + { + result.passed &= false; + result.failures.Add(t.ToString() + ": Freeze method not found"); + GlobalLog.LogEvidence(" !!!Freeze method not found: Exception: {0}", e.ToString()); + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/GetCurrentValueAsFrozenPatternsTest.cs b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/GetCurrentValueAsFrozenPatternsTest.cs new file mode 100644 index 000000000..00af06f63 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/FreezablesPatterns/GetCurrentValueAsFrozenPatternsTest.cs @@ -0,0 +1,184 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: Test GetCurrentValueAsFrozen + + ************************************************************/ + +using System; +using System.Globalization; +using System.Reflection; +using System.Windows; + +using Microsoft.Test; +using Microsoft.Test.Graphics; +using Microsoft.Test.Logging; +using Microsoft.Test.ElementServices.Freezables.Utils; +using Microsoft.Test.ElementServices.Freezables.Objects; + +namespace Microsoft.Test.ElementServices.Freezables +{ + + /********************************************************************************** + * CLASS: GetCurrentValueAsFrozenPatternsTest + **********************************************************************************/ + internal class GetCurrentValueAsFrozenPatternsTest : FreezablesPatternsBase + { + + #region Constructor + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + internal GetCurrentValueAsFrozenPatternsTest(Microsoft.Test.ElementServices.Freezables.Utils.Result result) + : base(result) + { + testName = "GetCurrentValueAsFrozenPatternsTest"; + } + #endregion + + + #region Internal Members + /****************************************************************************** + * Function: Perform + ******************************************************************************/ + /// + /// Invoke the specific test case requested. + /// + /// The Type of the Freezable object to be tested. + /// + internal override void Perform(Type t) + { + if (IsKnownIssue(t)) + { + return; + } + + // create an instance of this type + Freezable freezable = null; + if (FreezablesPatternsHelper.IsSpecialFreezable(t)) + { + freezable = FreezablesPatternsHelper.CreateSpecialFreezable(t); + } + else + { + freezable = FreezablesPatternsHelper.CreateNewChangeable(t); + } + + if (freezable != null) + { + GlobalLog.LogStatus("ClassName: " + t.ToString()); + Type type = freezable.GetType(); + if (TypeHelper.IsComplexChangeable(type)) + { + // ComplexFreezable: Freezable with embedded freezable as its property + GetCurrentValueAsFrozenPatternsTestForComplexFreezable(type, freezable); + } + else + { + // SimpleFreezable: Freezable without embedded freezable as its property + GetCurrentValueAsFrozenPatternsTestForSimpleFreezable(type, freezable); + } + } + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: GetCurrentValueAsFrozenPatternsTestForComplexFreezable + ******************************************************************************/ + /// + /// Testing a Complex Freezable. + /// + /// The Type of the Freezable object to be tested. + /// The parent of a Freezable. + /// + private void GetCurrentValueAsFrozenPatternsTestForComplexFreezable(Type type, Freezable parent) + { + PropertyInfo[] pi = type.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + + for (int i = 0; i < pi.Length; i++) + { + Freezable child = FreezablesPatternsHelper.GetComplexChangeable(pi[i], parent); + + if (child == null) + { + continue; + } + + child.Freeze(); + + // The clone should not be the same instance since parent freezable wasn't frozen + Freezable frozenClone = parent.GetCurrentValueAsFrozen(); + + if (frozenClone == parent) + { + result.passed &= false; + result.failures.Add(type.ToString() + ": The clone should not be the same instance since parent (freezable) wasn't frozen"); + } + + // + if ( (type != typeof(System.Windows.Media.TransformGroup) ) + && (type.ToString().ToLower(CultureInfo.InvariantCulture).IndexOf("usingkeyframes") < 0) ) + { + // After calling GetCurrentValueAsFrozen(), frozenChild should be equal to child since the child is frozen + Freezable frozenChild = FreezablesPatternsHelper.GetComplexChangeable(pi[i], frozenClone); + if (frozenChild != child) + { + result.passed &= false; + result.failures.Add(type.ToString() + ": GetCurrentValueAsFrozen should not have made a clone of the child since it is already frozen"); + } + } + + // Make a new clone and test for SimpleFreezable + child = child.Clone(); + + GetCurrentValueAsFrozenPatternsTestForSimpleFreezable(type, child); + } + } + + /****************************************************************************** + * Function: GetCurrentValueAsFrozenPatternsTestForSimpleFreezable + ******************************************************************************/ + /// + /// Testing a Freezable, from a Complex Freezable. + /// + /// The Type of the Freezable object to be tested. + /// The Freezable object to be tested. + /// + private void GetCurrentValueAsFrozenPatternsTestForSimpleFreezable(Type type, Freezable freezable) + { + Freezable currentFrozen = freezable.GetCurrentValueAsFrozen(); + + //IsFrozen should be true + if (!currentFrozen.IsFrozen) + { + result.passed &= false; + result.failures.Add(type.ToString() + ": IsFrozen should be true after calling GetCurrentValueAsFrozen()"); + + } + + // They should not be deep equal + if (ObjectUtils.DeepEquals(freezable, currentFrozen)) + { + result.passed &= false; + result.failures.Add(type.ToString() + ": GetCurrentValueAsFrozen for this object should be equal"); + } + // Freeze() the freezable, then call GetCurrentValueAsFrozen() again + // Objects should be equal + freezable.Freeze(); + currentFrozen = freezable.GetCurrentValueAsFrozen(); + if (!ObjectUtils.DeepEquals(freezable, currentFrozen)) + { + result.passed &= false; + result.failures.Add(type.ToString() + ": GetCurrentValueAsFrozen from a frozen freeze should be equal"); + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Code/InsertDelete.cs b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Code/InsertDelete.cs new file mode 100644 index 000000000..49598fa5a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Code/InsertDelete.cs @@ -0,0 +1,573 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: TestLogicalTree + + * This test does the following: + * - Load xaml, then Insert or delete tree node base on user input defined in action file + * - Verify that if the parent node in the tree is frozen, then the children must be frozen. + * Note: xaml should have the following attributes: + * xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" + * xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + * mc:Ignorable="PresentationOptions" + * PresentationOptions:Freeze="True or False" + + ************************************************************/ + +using System; +using System.Xml; +using System.Reflection; +using System.IO; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +using Microsoft.Test; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Discovery; +using Microsoft.Test.ElementServices.Freezables.Objects; +using Microsoft.Test.ElementServices.Freezables.Utils; + +namespace Microsoft.Test.ElementServices.Freezables +{ + //////////////////////////////////////////////////////////////////////////////////////////// + // DISABLEDUNSTABLETEST: + // TestName:InsertDelete + // Area: ElementServices SubArea: Freezables.InsertDelete + // Disable this case due to high fail rate, will enable after fix it. + // to find all disabled tests in test tree, use: �findstr /snip DISABLEDUNSTABLETEST� + //////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// ElementServices\Freezables\InsertDelete + + /// 3 + /// + /// InsertDelete tests + /// + /// + [Test(3, "Freezables.InsertDelete", "InsertDelete", SupportFiles = @"FeatureTests\ElementServices\pathrect.xaml,FeatureTests\ElementServices\child.xaml,FeatureTests\ElementServices\insertrect.xml", Disabled = true)] + + public class InsertDelete : AvalonTest + { + #region Private Data + private string _xamlFile = ""; + private string _controlFile = ""; + private bool _found; + private List _objectsInTree; + private Microsoft.Test.ElementServices.Freezables.Utils.Result _result; + private string _action = ""; + private string _parentName = ""; + private string _childName = ""; + private string _actionFile = ""; + #endregion + + + #region Constructor + + /****************************************************************************** + * Function: InsertDelete Constructor + ******************************************************************************/ + public InsertDelete() + { + InitializeSteps += new TestStep(Initialize); + RunSteps += new TestStep(RunTest); + RunSteps += new TestStep(Verify); + } + #endregion + + + #region Private Members + + /****************************************************************************** + * Function: Initialize + ******************************************************************************/ + /// + /// Sets global variables. + /// + /// Returns TestResult=True + private TestResult Initialize() + { + _xamlFile = "pathrect.xaml"; + _controlFile = "insertrect.xml"; + + _result = new Microsoft.Test.ElementServices.Freezables.Utils.Result(); + + // Create hashtables contain objects in the current trees and later on add the + // objects into it. This is used to break loop + _objectsInTree = new List(); + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: RunTest + ******************************************************************************/ + /// + /// Carries out the requested InsertDelete tests. A global variable tracks pass/fail. + /// + /// Returns TestResult=True + private TestResult RunTest() + { + XmlDocument doc = new XmlDocument(); + try + { + doc.Load(_controlFile); + } + catch (Exception) + { + throw new ApplicationException("Unable to load " + _controlFile); + } + + XmlElement freezableTest = (XmlElement)doc["FreezableTest"]; + for (XmlNode actionNode = freezableTest["Action"]; actionNode != null; actionNode = actionNode.NextSibling) + { + XmlAttribute a = actionNode.Attributes["Type"]; + XmlAttribute p = actionNode.Attributes["ParentNode"]; + XmlAttribute c = actionNode.Attributes["ChildNode"]; + XmlAttribute f = actionNode.Attributes["FileName"]; + if (a == null || p == null || c == null || f == null) + { + throw new ApplicationException("Action Element must have attributes Type=, ChildNode=, ParentNode=, FileName="); + } + _action = Convert.ToString(a.Value); + _parentName = Convert.ToString(p.Value); + _childName = Convert.ToString(c.Value); + _actionFile = Convert.ToString(f.Value); + + PerformTest(); + } + + return TestResult.Pass; + } + + + /****************************************************************************** + * Function: PerformTest + ******************************************************************************/ + /// + /// Carries out the requested InsertDelete tests. A global variable tracks pass/fail. + /// + /// + private void PerformTest() + { + Stream xamlStream = File.OpenRead(_xamlFile); + object xaml = XamlReader.Load(xamlStream); + _found = false; + object parentNode = null; + GetNodeFromXaml(out parentNode, xaml, _parentName); + if (parentNode == null) + { + _result.passed = false; + _result.failures.Add("Cannot find " + _parentName + " in file: " + _actionFile); + GlobalLog.LogStatus("Cannot find " + _parentName + " in file: " + _actionFile); + return; + } + + Stream xmlStream = File.OpenRead(_actionFile); + object xml = XamlReader.Load(xmlStream); + _found = false; + object childNode = null; + GetNodeFromXaml(out childNode, xml, _childName); + if (childNode == null) + { + _result.passed = false; + _result.failures.Add("Cannot find " + _childName + " in file: " + _actionFile); + GlobalLog.LogStatus("Cannot find " + _childName + " in file: " + _actionFile); + return; + } + + switch (_action) + { + case "Delete": + { + TestDelete(parentNode, childNode); + break; + } + case "Insert": + { + TestInsert(parentNode, childNode); + break; + } + default: + { + throw new ApplicationException("Unknown action: " + _action); + } + } + } + + + /****************************************************************************** + * Function: TestInsert + ******************************************************************************/ + /// + /// Tests inserting a node. + /// + /// The parent of the node to be added + /// The child to be inserted into the tree + /// + private void TestInsert(object parentNode, object childNode) + { + //Console.WriteLine("{0} {1}", parentNode, childNode); + IAddChild parent = parentNode as IAddChild; + DependencyObject child = childNode as DependencyObject; + parent.AddChild((UIElement)child); + _objectsInTree.Clear(); + + VerifyFreezable((object)parent); + } + + + /****************************************************************************** + * Function: TestDelete + ******************************************************************************/ + /// + /// Tests deleting a node. + /// + /// The parent of the child to be deleted + /// The child to be deleted from the tree + /// + private void TestDelete(object parentNode, object childNode) + { + //Console.WriteLine("{0} {1}", parentNode, childNode); + if (parentNode is Panel) + { + ((Panel)parentNode).Children.Remove((UIElement)childNode); + } + else if (parentNode is ContentControl) + { + ((ContentControl)parentNode).Content = null; + } + else if (parentNode is ItemsControl) + { + ((ItemsControl)parentNode).Items.Remove(childNode); + } + else if (parentNode is Decorator) + { + ((Decorator)parentNode).Child = null; + } + else + { + _result.passed = false; + _result.failures.Add("Don't know how to remove " + childNode + " from " + parentNode); + GlobalLog.LogStatus("Don't know how to remove " + childNode + " from " + parentNode); + } + _objectsInTree.Clear(); + VerifyFreezable((object)parentNode); + } + + + /****************************************************************************** + * Function: GetNodeFromXaml + ******************************************************************************/ + /// + /// Retrieve a node. + /// + /// The node returned from Xaml + /// object from xaml or xml + /// The name of the node to be retrieved + /// + private void GetNodeFromXaml(out object node, object obj, string nodeName) + { + node = null; + if (_objectsInTree.Contains(obj.GetHashCode())) + { + return; + } + + _objectsInTree.Add(obj.GetHashCode()); + Type t = obj.GetType(); + if (t.ToString() == nodeName) + { + //Console.WriteLine("FOUND" + obj); + _found = true; + node = obj; + return; + } + else + { + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo property in pi) + { + if (_found) + { + break; + } + if (IsBadProperty(property.Name, obj)) + { + continue; + } + if (IsGenericTypeMember(property.GetType(), property.Name)) + { + continue; + } + //Console.WriteLine("Property: " + property); + if (property.PropertyType.ToString().Contains("Collection")) + { + object children = property.GetValue(obj, null); + //Console.WriteLine(children); + foreach (object child in (IEnumerable)children) + { + if (_found) + { + break; + } + GetNodeFromXaml(out node, child, nodeName); + } + } + else + { + object propObj = GetPropertyValue(obj, property); + if (propObj != null && !propObj.GetType().IsValueType) + { + GetNodeFromXaml(out node, propObj, nodeName); + } + } + } + } + } + + + /****************************************************************************** + * Function: GetPropertyValue + ******************************************************************************/ + /// + /// Retrieve a property value. + /// + /// The object possessing the requested property + /// The property whose value is returned + /// The value of the property requested + private object GetPropertyValue(object obj, PropertyInfo property) + { + object propObj = null; + ParameterInfo[] parms = property.GetIndexParameters(); + if (parms.Length > 0) + { + propObj = property.GetValue(obj, new object[1] { 0 }); + } + else + { + propObj = property.GetValue(obj, null); + } + return propObj; + } + + + /****************************************************************************** + * Function: VerifyFreezable + ******************************************************************************/ + /// + /// Retrieve a property value. + /// + /// The object possessing the requested property + /// + private void VerifyFreezable(object obj) + { + if (_objectsInTree.Contains(obj.GetHashCode())) + { + return; + } + if (TypeHelper.IsFreezable(obj.GetType())) + { + Freezable freezable = obj as Freezable; + //Console.WriteLine("Freezable Object: " + obj.ToString()); + // If a freezable is frozen + // freezable children must also be frozen + if (freezable.IsFrozen) + { + VerifyFreezableIsFrozen(freezable); + } + } + + _objectsInTree.Add(obj.GetHashCode()); + + Type t = obj.GetType(); + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo property in pi) + { + // Console.WriteLine("PropertyName: " + property.Name); + if (IsBadProperty(property.Name, obj)) + { + continue; + } + if (IsGenericTypeMember(property.GetType(), property.Name)) + { + continue; + } + + if (property.PropertyType.ToString().Contains("Collection")) + { + object children = property.GetValue(obj, null); + foreach (object child in (IEnumerable)children) + { + VerifyFreezable(child); + } + } + else + { + object propObj = GetPropertyValue(obj, property); + if (propObj != null) + { + VerifyFreezable(propObj); + } + } + } + } + + + /****************************************************************************** + * Function: VerifyFreezableIsFrozen + ******************************************************************************/ + /// + /// Retrieve a property value. + /// + /// The freezable object to be verified + /// + private void VerifyFreezableIsFrozen(Freezable freezable) + { + //Console.WriteLine("VerifyFreezableIsFrozen for : " + freezable); + // + if (!freezable.IsFrozen && freezable.GetType().ToString() != "System.Windows.Media.MatrixTransform") + { + _result.passed = false; + _result.failures.Add("Test action: " + _action + " - " + freezable.GetType().ToString() + " Expected IsFrozen=True"); + GlobalLog.LogStatus("Test action: " + _action + " - " + freezable.GetType().ToString() + " Expected IsFrozen=True"); + + } + Type t = freezable.GetType(); + PropertyInfo[] pi = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); + for (int i = 0; i < pi.Length; i++) + { + if (IsBadProperty(pi[i].Name, freezable)) + { + continue; + } + if (!TypeHelper.IsFreezable(pi[i].PropertyType)) + { + // no need to verify + continue; + } + if (pi[i].Name == "Item" || pi[i].Name.ToString().EndsWith(".Item")) + { + if (freezable is IEnumerable) + { + // This means that the current Freezable is a collection + foreach (System.Windows.Freezable f in (IEnumerable)freezable) + { + VerifyFreezableIsFrozen(f); + } + } + } + else + { + System.Windows.Freezable f = null; + f = (System.Windows.Freezable)pi[i].GetValue(freezable, null); + VerifyFreezableIsFrozen(f); + } + } + } + + + /****************************************************************************** + * Function: IsGenericTypeMember + ******************************************************************************/ + /// + /// Checks if the given type member is a generic-only member on a non-generic type. + /// + /// The freezable object to be verified + /// Member name + /// A boolean indicating whether or not the type is generic + private bool IsGenericTypeMember(Type type, string memberName) + { + return !type.IsGenericType + && (memberName == "GenericParameterPosition" + || memberName == "GenericParameterAttributes" + || memberName == "GetGenericArguments" + || memberName == "GetGenericParameterConstraints" + || memberName == "GetGenericTypeDefinition" + || memberName == "IsGenericTypeDefinition" + || memberName == "DeclaringMethod"); + } + + + /****************************************************************************** + * Function: IsBadProperty + ******************************************************************************/ + /// + /// Checks for to-be-skipped properties / objects. + /// + /// The property to be checked + /// The object associated with the to-be-checked property + /// A boolean indicating whether or not the property is acceptable + private bool IsBadProperty(string propertyName, object owner) + { + //GeneralTransform.Inverse property returns a GeneralTranform again, stuck in the loop + if (propertyName == "Inverse" && owner.GetType().ToString() == "GeneralTransform") + { + return true; + } + // stuck in the loop + else if (owner.GetType().ToString() == "System.Windows.Media.MatrixTransform") + { + return true; + } + // Get TargetInvocationException for some reason. + else if (owner.GetType().ToString() == "System.String" && propertyName == "Chars") + { + return true; + } + else if (owner.GetType().ToString() == "System.Globalization.CultureInfo") + { + return true; + } + else + { + return false; + } + } + + + /****************************************************************************** + * Function: Verify + ******************************************************************************/ + /// + /// Returns a Pass/Fail result for the test case. + /// + /// A TestResult, indicating whether or not the test passed. + private TestResult Verify() + { + // report the failures all together + if (!_result.passed) + { + GlobalLog.LogEvidence("------------------------------------------"); + GlobalLog.LogEvidence("FAILURE REPORT"); + GlobalLog.LogEvidence("------------------------------------------"); + for (int i = 0; i < _result.failures.Count; i++) + { + GlobalLog.LogStatus(_result.failures[i]); + } + } + + if (_result.passed) + { + return TestResult.Pass; + } + else + { + return TestResult.Fail; + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/child.xaml b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/child.xaml new file mode 100644 index 000000000..5db1cc46c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/child.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/pathrect.xaml b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/pathrect.xaml new file mode 100644 index 000000000..25846af74 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/InsertDelete/Markup/pathrect.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Code/RoundTrip.cs b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Code/RoundTrip.cs new file mode 100644 index 000000000..88f8e50d9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Code/RoundTrip.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*********************************************************** + * + * Copyright (c) Microsoft Corporation, 2006 + * + * Program: Perform a roundtrip test on a xaml + + * + ************************************************************/ + +using System; + +using Microsoft.Test; +using Microsoft.Test.Serialization; +using Microsoft.Test.Logging; +using Microsoft.Test.Discovery; + + +namespace Microsoft.Test.ElementServices.Freezables +{ + /// + /// ElementServices\Freezables\RoundTrip + + /// 3 + /// + /// RoundTrip tests - Serialization + /// + /// + + [Test(3, "Freezables.RoundTrip", "RoundTrip", SupportFiles=@"FeatureTests\ElementServices\png.png,FeatureTests\ElementServices\puppies.jpg")] + + /********************************************************************************** + * CLASS: RoundTrip + **********************************************************************************/ + public class RoundTrip + { + #region Private Data + private TestLog _log; + private string _xamlFile = ""; + #endregion + + + #region Constructor + [Variation(@"FeatureTests\ElementServices\brushes.xaml", SupportFiles = @"FeatureTests\ElementServices\brushes.xaml")] + [Variation(@"FeatureTests\ElementServices\databindingColorAnimToProperty.xaml", SupportFiles = @"FeatureTests\ElementServices\databindingColorAnimToProperty.xaml")] + [Variation(@"FeatureTests\ElementServices\drawingbrush.xaml", SupportFiles = @"FeatureTests\ElementServices\drawingbrush.xaml")] + [Variation(@"FeatureTests\ElementServices\geometries.xaml", SupportFiles = @"FeatureTests\ElementServices\geometries.xaml")] + [Variation(@"FeatureTests\ElementServices\Transforms.xaml", SupportFiles = @"FeatureTests\ElementServices\Transforms.xaml")] + + /****************************************************************************** + * Function: Constructor + ******************************************************************************/ + // Input Parameter: TestName + public RoundTrip(string inputValue) + { + _xamlFile = inputValue; + } + #endregion + + + #region Public and Protected Members + /****************************************************************************** + * Function: Run + ******************************************************************************/ + /// + /// Runs the Test and returns the Final Result of the Test. + /// + /// the Final Result of the Test + public TestLog Run() + { + _log = new TestLog("RoundTrip"); + + StartTest(); + + if (TestLog.Current != null) + { + TestLog.Current.Result = _log.Result; + } + + _log.Close(); //Must close the log to avoid a Failure. + + return _log; + } + #endregion + + + #region Private Members + /****************************************************************************** + * Function: StartTest + ******************************************************************************/ + /// + /// Carries out the requested RoundTrip tests. A global variable tracks pass/fail. + /// + /// + private void StartTest() + { + SerializationHelper helper = new SerializationHelper(); + + try + { + int indx = _xamlFile.LastIndexOf("\\"); + _xamlFile = _xamlFile.Substring(indx+1); + + GlobalLog.LogStatus("Starting test for " + _xamlFile); + helper.RoundTripTestFile(_xamlFile); + GlobalLog.LogStatus("No exception for " + _xamlFile); + + _log.Result = TestResult.Pass; + } + catch (Exception e) + { + GlobalLog.LogEvidence("Unexpected Exception occurred:\n" + e.ToString()); + _log.Result = TestResult.Fail; + } + } + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Geometries.xaml b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Geometries.xaml new file mode 100644 index 000000000..71745b83b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Geometries.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Transforms.xaml b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Transforms.xaml new file mode 100644 index 000000000..5600d34f9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/Transforms.xaml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/brushes.xaml b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/brushes.xaml new file mode 100644 index 000000000..a5abfcd93 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/brushes.xaml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + UniformToFill + + + Left + + + Top + + + 0,0,1,1 + + + RelativeToBoundingBox + + + + + + + + + + + + + + + + + + + + + + + + + + + 455 + 255 + 200 + 150 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/databindingColorAnimToProperty.xaml b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/databindingColorAnimToProperty.xaml new file mode 100644 index 000000000..606f51861 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/databindingColorAnimToProperty.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + Red + Green + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/drawingbrush.xaml b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/drawingbrush.xaml new file mode 100644 index 000000000..0adcd6432 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/RoundTrip/Markup/drawingbrush.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Freezables/dirs.proj b/src/Test/ElementServices/FeatureTests/Freezables/dirs.proj new file mode 100644 index 000000000..882b9596c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Freezables/dirs.proj @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Orcas/Orcas.nativeproj b/src/Test/ElementServices/FeatureTests/Orcas/Orcas.nativeproj new file mode 100644 index 000000000..9b4b03b79 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Orcas/Orcas.nativeproj @@ -0,0 +1,22 @@ + + + + + + + + + COPY + + + + + FeatureTests\ElementServices\TXRRepository + + + FeatureTests\ElementServices + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/MarkupExtDotPropertyName.xaml b/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/MarkupExtDotPropertyName.xaml new file mode 100644 index 000000000..c1b904be5 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/MarkupExtDotPropertyName.xaml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/NetFX2007NS.xaml b/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/NetFX2007NS.xaml new file mode 100644 index 000000000..108f6a68f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Orcas/TestData/bvt/parser/NetFX2007NS.xaml @@ -0,0 +1,41 @@ + + + + + + RichTextBox1 + + + + + + + + RichTextBox2 + + + + + + + + RichTextBox3 + + + + + + + + RichTextBox4 + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Code/TransControls.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/Code/TransControls.cs new file mode 100644 index 000000000..2ba3d280b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Code/TransControls.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; + +namespace Com.ControlStore +{ + public class TransButton : Button + { + public TransButton() + : base() + { + Opacity = 0.5; + } + } + + public class TransListBox : ListBox + { + public TransListBox() + : base() + { + Opacity = 0.5; + } + } + + public class TransListBoxItem : ListBoxItem + { + public TransListBoxItem() + : base() + { + Opacity = 0.5; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/FixedSizeTransControls.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/FixedSizeTransControls.cs new file mode 100644 index 000000000..f01871699 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/FixedSizeTransControls.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Com.ControlStore +{ + public class FixedSizeTransButton : TransButton + { + public FixedSizeTransButton() + : base() + { + Height = 200; + Width = 200; + } + } + + public class FixedSizeTransListBox : TransListBox + { + public FixedSizeTransListBox() + : base() + { + Height = 200; + Width = 200; + } + } + + public class FixedSizeTransListBoxItem : TransListBoxItem + { + public FixedSizeTransListBoxItem() + : base() + { + Height = 200; + Width = 200; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/ParserTestControlsFixedSize.csproj b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/ParserTestControlsFixedSize.csproj new file mode 100644 index 000000000..f615ccb72 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/ParserTestControlsFixedSize.csproj @@ -0,0 +1,30 @@ + + + + + + + ParserTestControlsFixedSize + Library + FeatureTests\ElementServices + true + false + + $(BinplaceFlags) + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/XmlnsInfo.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/XmlnsInfo.cs new file mode 100644 index 000000000..f474e9f5c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/FixedSizeControls/XmlnsInfo.cs @@ -0,0 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +[assembly: System.Windows.Markup.XmlnsDefinition("http://ns.controlstore.com/avalon/fixedsize/2005", "Com.ControlStore")] diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta new file mode 100644 index 000000000..4fbcbbebf --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta @@ -0,0 +1,52 @@ +#include "versions.h" +#include "ndp20.versions.h" + +.assembly extern PresentationFramework +{ + .publickeytoken = PRESENTATIONFRAMEWORK_ASSEMBLY_PUBLIC_KEY_TOKEN_IL + .ver PRESENTATIONFRAMEWORK_ASSEMBLY_VERSION_IL +} +.assembly extern mscorlib +{ + .publickeytoken = MSCORLIB_20_ASSEMBLY_PUBLIC_KEY_TOKEN_IL + .ver MSCORLIB_20_ASSEMBLY_VERSION_IL +} +.assembly ParserTestControlsV1 +{ + .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = { bool(false) } + .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = { bool(false) } + .custom instance void [mscorlib]System.Security.AllowPartiallyTrustedCallersAttribute::.ctor() = { } + .publickey = PARSERTESTCONTROLSV1_ASSEMBLY_PUBLIC_KEY_IL + .hash algorithm 0x00008004 + .ver PARSERTESTCONTROLSV1_ASSEMBLY_VERSION_IL +} +.namespace Com.ControlStore +{ + .class public TransButton + extends [PresentationFramework]System.Windows.Controls.Button + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } + .class public TransListBox + extends [PresentationFramework]System.Windows.Controls.ListBox + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } + .class public TransListBoxItem + extends [PresentationFramework]System.Windows.Controls.ListBoxItem + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta.config.xml b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta.config.xml new file mode 100644 index 000000000..9f643be9c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.asmmeta.config.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.csproj b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.csproj new file mode 100644 index 000000000..0c97e011f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/ParserTestControlsV1.csproj @@ -0,0 +1,30 @@ + + + + + + + ParserTestControlsV1 + Library + true + $(TestTrustedKey) + FeatureTests\ElementServices + true + false + {218F118B-3002-4ca7-933A-AAC2D4FB7F57} + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/XmlnsInfo.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/XmlnsInfo.cs new file mode 100644 index 000000000..6b2d47971 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version1/XmlnsInfo.cs @@ -0,0 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +[assembly: System.Windows.Markup.XmlnsDefinition("http://ns.controlstore.com/avalon/2005", "Com.ControlStore")] diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta new file mode 100644 index 000000000..c422ea904 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta @@ -0,0 +1,52 @@ +#include "versions.h" +#include "ndp20.versions.h" + +.assembly extern PresentationFramework +{ + .publickeytoken = PRESENTATIONFRAMEWORK_ASSEMBLY_PUBLIC_KEY_TOKEN_IL + .ver PRESENTATIONFRAMEWORK_ASSEMBLY_VERSION_IL +} +.assembly extern mscorlib +{ + .publickeytoken = MSCORLIB_20_ASSEMBLY_PUBLIC_KEY_TOKEN_IL + .ver MSCORLIB_20_ASSEMBLY_VERSION_IL +} +.assembly ParserTestControlsV2 +{ + .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = { bool(false) } + .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = { bool(false) } + .custom instance void [mscorlib]System.Security.AllowPartiallyTrustedCallersAttribute::.ctor() = { } + .publickey = PARSERTESTCONTROLSV2_ASSEMBLY_PUBLIC_KEY_IL + .hash algorithm 0x00008004 + .ver PARSERTESTCONTROLSV2_ASSEMBLY_VERSION_IL +} +.namespace Com.ControlStore +{ + .class public TransButton + extends [PresentationFramework]System.Windows.Controls.Button + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } + .class public TransListBox + extends [PresentationFramework]System.Windows.Controls.ListBox + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } + .class public TransListBoxItem + extends [PresentationFramework]System.Windows.Controls.ListBoxItem + { + .method public hidebysig specialname + instance void .ctor() + { + ret + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta.config.xml b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta.config.xml new file mode 100644 index 000000000..d4fb8be63 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.asmmeta.config.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.csproj b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.csproj new file mode 100644 index 000000000..74e939de7 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/ParserTestControlsV2.csproj @@ -0,0 +1,32 @@ + + + + + + + ParserTestControlsV2 + Library + true + $(TestTrustedKey) + FeatureTests\ElementServices + true + false + + $(BinplaceFlags) + {6F90C1FA-B230-4c7b-980A-7831BC6385DB} + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/XmlnsInfo.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/XmlnsInfo.cs new file mode 100644 index 000000000..5db5e983d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2/XmlnsInfo.cs @@ -0,0 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +[assembly: System.Windows.Markup.XmlnsDefinition("http://ns.controlstore.com/avalon/2007", "Com.ControlStore")] diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/ParserTestControlsV2SubsumingV1.csproj b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/ParserTestControlsV2SubsumingV1.csproj new file mode 100644 index 000000000..ba4f9da4f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/ParserTestControlsV2SubsumingV1.csproj @@ -0,0 +1,29 @@ + + + + + + + ParserTestControlsV2SubsumingV1 + Library + FeatureTests\ElementServices + true + false + + $(BinplaceFlags) + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/XmlnsInfo.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/XmlnsInfo.cs new file mode 100644 index 000000000..3e3ae8dc3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version2SubsumingV1/XmlnsInfo.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +[assembly: System.Windows.Markup.XmlnsDefinition("http://ns.controlstore.com/avalon/2007", "Com.ControlStore")] +[assembly: System.Windows.Markup.XmlnsCompatibleWith("http://ns.controlstore.com/avalon/2005", "http://ns.controlstore.com/avalon/2007")] diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/ParserTestControlsV3SubsumingV2.csproj b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/ParserTestControlsV3SubsumingV2.csproj new file mode 100644 index 000000000..dc37b5822 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/ParserTestControlsV3SubsumingV2.csproj @@ -0,0 +1,29 @@ + + + + + + + ParserTestControlsV3SubsumingV2 + Library + FeatureTests\ElementServices + true + false + + $(BinplaceFlags) + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/XmlnsInfo.cs b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/XmlnsInfo.cs new file mode 100644 index 000000000..8c3cbfa9b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/Version3SubsumingV2/XmlnsInfo.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +[assembly: System.Windows.Markup.XmlnsDefinition("http://ns.controlstore.com/avalon/2009", "Com.ControlStore")] +[assembly: System.Windows.Markup.XmlnsCompatibleWith("http://ns.controlstore.com/avalon/2007", "http://ns.controlstore.com/avalon/2009")] diff --git a/src/Test/ElementServices/FeatureTests/ParserTestControls/dirs.proj b/src/Test/ElementServices/FeatureTests/ParserTestControls/dirs.proj new file mode 100644 index 000000000..6c5fa11b2 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/ParserTestControls/dirs.proj @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventBuilder.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventBuilder.cs new file mode 100644 index 000000000..29b685af6 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventBuilder.cs @@ -0,0 +1,349 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using Microsoft.Test.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Baseline event builder. Uses the Mouse to perform hit testing. + /// + public class BaselineEventBuilder + { + #region Fields + + private enum CollectionState + { + Skip, MatchToTouchDown, MatchToTouchMove, MatchToTouchUp, MatchToTouchHasGone + }; + + // mouse event to collect + private static readonly RoutedEvent s_simulationEvent = Mouse.PreviewMouseMoveEvent; + + // mouse events to collect + private static readonly RoutedEvent[] s_mouseEvents = new RoutedEvent[] + { + s_simulationEvent, + }; + + // mouse events to collect + private static readonly RoutedEvent[] s_mouseEventsWithEnterLeave = new RoutedEvent[] + { + s_simulationEvent, + Mouse.MouseEnterEvent, + Mouse.MouseLeaveEvent, + }; + + #endregion + + + /// + /// Event collector that collects simulated mouse events + /// + private class SimulationEventCollector : EventCollector + { + // collection state, the caller is responsible to set this property that is used to generate matched touch event + private CollectionState _state; + + // a dictionary: visual element -> bool to filter out duplicated events + private Dictionary _handledEvents = new Dictionary(); + + // insert position to gnerate a new event + private int _insertPosition; + + // root of the visual tree + private readonly UIElement _root; + + public SimulationEventCollector(UIElement root, bool collectEnterLeave) + : base(collectEnterLeave ? s_mouseEventsWithEnterLeave : s_mouseEvents) + { + Debug.Assert(root != null); + this._root = root; + Init(); + } + + protected override void Collect(IList list, object sender, RoutedEventArgs args) + { + RoutedEvent[] matchedEvents = GetExpectedTouchEvents(sender, args); + if (matchedEvents != null) + { + Point position = GetPosition(args); + for (int i = 0; i < matchedEvents.Length; i++) + { + RoutedEvent matchedEvent = matchedEvents[i]; + EventParameters parameters = new EventParameters(sender, args, position, matchedEvent); + list.Insert(this._insertPosition, parameters); + if (i == 0) + { + // increase insertPosition only once, we need to make sure that all tunnel (Preview) events + // go first follow by all bubble events. + this._insertPosition++; + } + } + } + } + + /// + /// Returns a collection of expected events based on the matching specified by the 'this.state' + /// + /// + /// + /// + private RoutedEvent[] GetExpectedTouchEvents(object sender, RoutedEventArgs args) + { + RoutedEvent[] expectedEvents = null; + + if (args.RoutedEvent == s_simulationEvent) + { + if (!this._handledEvents.ContainsKey(sender)) + { + this._handledEvents.Add(sender, true); + + switch (this._state) // + { + // handle the event as TouchDown + case CollectionState.MatchToTouchDown: + expectedEvents = new RoutedEvent[] + { + UIElement.PreviewTouchDownEvent, + UIElement.TouchDownEvent + }; + break; + + // handle the event as TouchMove + case CollectionState.MatchToTouchMove: + expectedEvents = new RoutedEvent[] + { + UIElement.PreviewTouchMoveEvent, + UIElement.TouchMoveEvent + }; + break; + + // handle the event as Touchup + case CollectionState.MatchToTouchUp: + expectedEvents = new RoutedEvent[] + { + UIElement.PreviewTouchUpEvent, + UIElement.TouchUpEvent + }; + break; + + // skip the event + case CollectionState.Skip: + break; + + // unexpected state + default: + Debug.Assert(false); + break; + } + } + } + else if (args.RoutedEvent == Mouse.MouseEnterEvent && + (this._state == CollectionState.MatchToTouchDown || this._state == CollectionState.MatchToTouchMove)) + { + expectedEvents = new RoutedEvent[] { UIElement.TouchEnterEvent }; + } + else if (args.RoutedEvent == Mouse.MouseLeaveEvent && + (this._state == CollectionState.MatchToTouchMove || this._state == CollectionState.MatchToTouchHasGone)) + { + expectedEvents = new RoutedEvent[] { UIElement.TouchLeaveEvent }; + } + + return expectedEvents; + } + + /// + /// Reads position from the mouse event + /// + /// + /// + private Point GetPosition(RoutedEventArgs args) + { + MouseEventArgs mouseEventArgs = args as MouseEventArgs; + if (mouseEventArgs != null) + { + if (this._state == CollectionState.MatchToTouchHasGone) + { + // take position from the previous event + return LastEvent != null ? LastEvent.Position : new Point(double.NaN, double.NaN); + } + else + { + // get the current position + return mouseEventArgs.GetPosition(this._root); + } + } + return new Point(); + } + + public override void Clear() + { + base.Clear(); + Init(); + } + + private void Init() + { + this._state = CollectionState.Skip; + this._handledEvents.Clear(); + this._insertPosition = 0; + } + + public CollectionState State + { + get + { + return this._state; + } + set + { + this._state = value; + this._handledEvents.Clear(); + this._insertPosition = CollectedEventsCount; + } + } + } + + + #region Methods + + private static void MoveMouseOutsideWindow(Window window) + { + // move the mouse outside the window + UserInput.MouseMove((int)1000000, (int)1000000); + } + + /// + /// Generates baseline, returns true if operation succeeds, otherwise - false with the 'error' parameter containing the error string. + /// + /// Window the simulated events will be sent to. + /// Root element to retrieve the event position relative to. + /// The object to attach events handlers. + /// Add event handlers to the children. + /// Collect Enter and Leave events. + /// List of touch snapshots to build the baseline against. + /// Optional delegate that will be called before processing a touch snapshot. + /// The result collection of collected events. + /// The result error string if the method fails. + /// + public static bool Generate(Window window, UIElement root, + DependencyObject objectToAddHandlers, bool addHandlersToChildren, bool collectEnterLeave, + IList touchSnapshots, Action previewTouchProcessing, + out ReadOnlyCollection collectedEvents, out string error) + { + error = null; + collectedEvents = null; + SimulationEventCollector collector = null; + + try + { + // + + // move mouse outside the window + MoveMouseOutsideWindow(window); + + // create event collector and add handlers + collector = new SimulationEventCollector(root, collectEnterLeave); + collector.AddHandlers(objectToAddHandlers, addHandlersToChildren); + + // simulate mouse events + Debug.Assert(touchSnapshots.Count >= 2); + Point previousPosition = new Point(double.NaN, double.NaN); + + for (int i = 0; i < touchSnapshots.Count; i++) + { + // current touch snapshot + TouchDevice snapshot = touchSnapshots[i]; + + // get snapshot position and simulate a mouse event + Point position = snapshot.GetTouchPoint(root).Position; + + // move mouse somewhere else if position is the same as the previous one + if (position == previousPosition) + { + // if there are more than one consequent snapshot with the same position then we cannot do anything. + // We can try to move the mouse somewhere else but then we can get spurious MouseEnter event. + // So fail beseline generation unless this is the last snapshot that + // corresponds to the touchUp. + if (i != touchSnapshots.Count - 1) + { + error = "Interrupted. Could not generate baseline, several snapshots have the same position."; + return false; + } + collector.State = CollectionState.Skip; + + Point anyPosition = new Point(position.X > 0 ? position.X - 1 : position.X + 1, position.Y); + + // simulate mouse move + UserInput.MouseMove(window, (int)anyPosition.X, (int)anyPosition.Y); + } + previousPosition = position; + + // invoke the optional previewTouchProcessing delegate + if (previewTouchProcessing != null) + { + previewTouchProcessing(snapshot); + } + + if (i == 0) // first touch snapshot, generate TouchDown event + { + collector.State = CollectionState.MatchToTouchDown; + } + + else if (i == touchSnapshots.Count - 1) // last touch snapshot, generate TouchUp event + { + collector.State = CollectionState.MatchToTouchUp; + } + else // a touch snapshot somewhere in the middle, generate TouchMove event + { + collector.State = CollectionState.MatchToTouchMove; + } + + int collectedEventCountBefore = collector.CollectedEventsCount; + + UserInput.MouseMove(window, (int)position.X, (int)position.Y); + + // make sure that the event is processed + EventCollector.DoEvents(); + + int collectedEventCountAfter = collector.CollectedEventsCount; + + if (collectedEventCountBefore == collectedEventCountAfter) + { + // mouse event is missing, can't do anything + error = "Interrupted. Could not generate baseline, mouse event is missing."; + return false; + } + } + + // move the mouse outside the window + collector.State = CollectionState.MatchToTouchHasGone; + MoveMouseOutsideWindow(window); + } + finally + { + if (collector != null) + { + // remove event handlers + collector.RemoveHandlers(objectToAddHandlers, addHandlersToChildren); + } + + // + } + + collectedEvents = collector.CollectedEvents; + return true; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventCollector.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventCollector.cs new file mode 100644 index 000000000..29a104ce0 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/BaselineEventCollector.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using Microsoft.Test.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// BaselineEventArgs + /// + public class BaselineEventArgs : RoutedEventArgs + { + private readonly Point _position; + + public BaselineEventArgs(RoutedEvent routedEvent, object source, Point position) + : base(routedEvent, source) + { + this._position = position; + } + + public Point Position + { + get + { + return this._position; + } + } + } + + /// + /// BaselineEventCollector + /// + public class BaselineEventCollector : EventCollector + { + public BaselineEventCollector(): base(true/*collectAllEvents*/) + { + } + + protected override void Collect(IList list, object sender, RoutedEventArgs args) + { + BaselineEventArgs baselineArgs = args as BaselineEventArgs; + Point position = baselineArgs == null ? new Point() : baselineArgs.Position; + list.Add(new EventParameters(sender, args, position, args.RoutedEvent)); + } + + public void Collect(object sender, BaselineEventArgs args) + { + base.Collect(sender, args); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/CollectionFactory.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/CollectionFactory.cs new file mode 100644 index 000000000..36b371148 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/CollectionFactory.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; + +namespace Microsoft.Test.Input.MultiTouch +{ + public static class CollectionFactory + { + /// + /// A set of valid and invalid Points + /// + public static PointCollection Points + { + get + { + PointCollection c = new PointCollection(); + + c.Add(new Point(0, 0)); + c.Add(new Point(16.8, 16.8)); + c.Add(new Point(-16.8, -16.8)); + c.Add(new Point(double.MaxValue, double.MinValue)); + c.Add(new Point(double.MinValue, double.MaxValue)); + c.Add(new Point(double.MinValue, double.MaxValue)); + c.Add(new Point(double.NaN, double.Epsilon)); + + return c; + } + } + + /// + /// A set of valid and invalid Vectors + /// + public static VectorCollection Vectors + { + get + { + VectorCollection c = new VectorCollection(); + + c.Add(new Vector(0, 0)); + c.Add(new Vector(11.11, 0.11)); + c.Add(new Vector(-11.11, -0.11)); + c.Add(new Vector(double.MaxValue, double.MinValue)); + c.Add(new Vector(double.MinValue, double.MaxValue)); + c.Add(new Vector(double.MinValue, double.MaxValue)); + c.Add(new Vector(double.NaN, double.Epsilon)); + + return c; + } + } + + /// + /// A set of valid and invalid doubles + /// + public static DoubleCollection Doubles + { + get + { + DoubleCollection c = new DoubleCollection(); + + c.Add(0); + c.Add(-20.16); + c.Add(20.16); + c.Add(double.MaxValue); + c.Add(double.MinValue); + c.Add(double.PositiveInfinity); + c.Add(double.NegativeInfinity); + c.Add(double.Epsilon); + c.Add(double.NaN); + + return c; + } + } + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/CommonUsedGestures.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/CommonUsedGestures.cs new file mode 100644 index 000000000..5e064e790 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/CommonUsedGestures.cs @@ -0,0 +1,428 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Collections; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + ///**************************************************************************// + /// Commonly Used Input Gesture Commands // + /// All are of type MultiplePointGesture, while SingelPointGesture // + /// is a special case for MultiplePointGesture // + ///**************************************************************************// + /// + + #region "Touch And Release" gesture + + /// + /// Represent a single point touch that presses and releases for a given number of milliseconds + /// + public class TouchAndReleaseGesture : MultipleContactsGesture + { + public TouchAndReleaseGesture(Point point) + { + SingleContactGesture dotgesture = new DotGesture(point); + base.AddCommand(dotgesture); + } + + public TouchAndReleaseGesture(Point point, int milliseconds) + { + SingleContactGesture dotgesture = new DotGesture(point, milliseconds); + base.AddCommand(dotgesture); + } + } + + #endregion + + #region "Drag" gesture + + /// + /// Represents a drage gesture moves through a set of points defined by the given PointF[] + /// + public class DragGesture : MultipleContactsGesture + { + public DragGesture(Point start, Point end) + : this(new Point[] { start, end }) + { + } + + public DragGesture(double x1, double y1, double x2, double y2) + : this(new Point[] { new Point(x1, y1), new Point(x2, y2) }) + { + } + + public DragGesture(Point[] points) + : this(points, false) + { + } + + public DragGesture(Point[] points, bool bsmoothed) + { + SingleContactGesture linegesture = new LineGesture(points, bsmoothed); + base.AddCommand(linegesture); + } + } + + #endregion + + #region "Pan" gesture + + /// + /// Represents a pan gesture that moves through a set of points defined by the given PointF[] + /// + public class PanGesture : MultipleContactsGesture + { + public PanGesture(Point start, Point end) + : this(new Point[] { start, end }) + { + } + + public PanGesture(float x1, float y1, float x2, float y2) + : this(new Point[] { new Point(x1, y1), new Point(x2, y2) }) + { + } + + public PanGesture(Point[] points) + : this(points, false) + { + } + + public PanGesture(Point[] points, bool bsmoothed) + { + SingleContactGesture linegesture = new LineGesture(points, bsmoothed); + base.AddCommand(linegesture); + } + } + + #endregion + + #region "Zoom" gesture + + /// + /// Represents a Zoom gesture + /// 1. one point stays, another finger moves from begin point to end point + /// 2. two points move from begin point to end point respectively + /// 3. all point constitute a circle and its centre stays when moving + /// 4. specific line combination + /// + public class ZoomGesture : MultipleContactsGesture + { + /// + /// Zoom with one point stays and another point moves + /// + /// + /// + /// + public ZoomGesture(Point stayPoint, Point movePointStart, Point movePointEnd) + : this(stayPoint, stayPoint, movePointStart, movePointEnd) + { + } + + /// + /// Zoom with two point move respectively + /// + /// + /// + /// + /// + public ZoomGesture(Point firstStart, Point firstEnd, Point secondStart, Point secondEnd) + { + Point[] first = new Point[2]; + Point[] second = new Point[2]; + + first[0] = firstStart; + first[1] = firstEnd; + GenerateGesture(first); + + second[0] = secondStart; + second[1] = secondEnd; + GenerateGesture(second); + } + + /// + /// All point constitute a circle and its centre stay when moving + /// + /// + /// + /// + /// + public ZoomGesture(Point center, int fingerCount, double startRadius, double endRadius) + { + if (fingerCount < 1 || fingerCount > 10) + { + throw new ArgumentOutOfRangeException("fingerCount", "fingerCount must greater than 0 and less than or equal to 10"); + } + + if (startRadius <= 0) + { + throw new ArgumentOutOfRangeException("startRadius", "startRadius must greater than 0"); + } + + if (endRadius <= 0) + { + throw new ArgumentOutOfRangeException("endRadius", "endRadius must greater than 0"); + } + + Point[] point = null; + for (int i = 0; i < fingerCount; i++) + { + point = new Point[2]; + + point[0].X = (double)(center.X + startRadius * Math.Cos(Math.PI * i * 2 / fingerCount)); + point[0].Y = (double)(center.Y + startRadius * Math.Sin(Math.PI * i * 2 / fingerCount)); + + point[1].X = (double)(center.X + endRadius * Math.Cos(Math.PI * i * 2 / fingerCount)); + point[1].Y = (double)(center.Y + endRadius * Math.Sin(Math.PI * i * 2 / fingerCount)); + + GenerateGesture(point); + } + } + + /// + /// Zoom with specific line combination + /// + /// + public ZoomGesture(LineGesture[] lineGestures) + { + if (lineGestures == null) + { + throw new ArgumentNullException("lineGestures", "lineGestures cannot be null"); + } + + foreach (LineGesture lineGesture in lineGestures) + { + if (lineGesture == null) + { + throw new ArgumentNullException("lineGesture", "lineGesture cannot be null"); + } + AddCommand(lineGesture); + } + } + + private void GenerateGesture(Point[] point) + { + LineGesture lineGesture = new LineGesture(point, false); + AddCommand(lineGesture); + } + } + + #endregion + + #region "Rotate" gesture + + /// + /// Represents a Rotate gesture + /// 1. Two fingers rotate : one finger press at center, another performs rotate + /// 2. Multiple fingers (>=2) rotate, locating at one circle evenly + /// 3. Rotate with customized archs + /// + public class RotateGesture : MultipleContactsGesture + { + public override int ContactsInterval + { + get + { + foreach (SingleContactGesture singlegesture in GestureList) + { + if (singlegesture is ArcGesture) + { + return singlegesture.ContactsInterval; + } + } + throw new NotImplementedException("no interval value provided"); + } + } + + public override int Samples + { + get + { + foreach (SingleContactGesture singlegesture in GestureList) + { + if (singlegesture is ArcGesture) + { + return singlegesture.Samples; + } + } + throw new NotImplementedException("no samples value provided"); + } + + set + { + if (value < 1) + { + throw new ArgumentOutOfRangeException("Samples should be at least 1"); + } + foreach (SingleContactGesture singlegesture in GestureList) + { + if (singlegesture is ArcGesture) + { + singlegesture.Samples = value; + } + } + } + } + + public override int Duration + { + get + { + foreach (SingleContactGesture singlegesture in GestureList) + { + if (singlegesture is ArcGesture) + { + return singlegesture.Duration; + } + } + throw new NotImplementedException("no duration value provided"); + } + set + { + if (value < SingleContactGesture.INTERVALMIN) + { + throw new ArgumentOutOfRangeException("Interval must be bigger than INTERVALMIN = " + SingleContactGesture.INTERVALMIN.ToString()); + } + foreach (SingleContactGesture singlegesture in GestureList) + { + if (singlegesture is ArcGesture) + { + singlegesture.Duration = value; + } + else if (singlegesture is DotGesture) + { + //DotGesture used to use the same duration with arc gestures. However, as the time needed for + //every touch operation is often much bigger than ContactInterval, this caused the total time + //used for arc gesture is bigger than the duration value. + //This will cause the DotGesture to be finished much earlier than arc gestures as it always just has one sample. + //To double the time so the rotate gesture can be finished completely. + //This is a magic number, may have a better solution in future. + singlegesture.Duration = value * 2; + } + } + } + } + + public RotateGesture(Point center, double height, double width, double startAngle, double endAngle) + : this(center, 1, height, width, startAngle, endAngle, true) + { + } + + public RotateGesture(Point center, int fingerCount, double height, double width, double startAngle, double endAngle) + : this(center, fingerCount, height, width, startAngle, endAngle, true) + { + } + + private RotateGesture(Point center, int fingerCount, double height, double width, double startAngle, double endAngle, bool pressCenter) + { + if (fingerCount <= 0 || fingerCount > 10) + { + throw new ArgumentOutOfRangeException("fingerCount", "fingerCount must be greater than 0 and less than or equal to 10"); + } + + int arcDuration = 1000; //Make each arc have a 1 second duration + for (int i = 0; i < fingerCount; i++) + { + ArcGesture arcGesture = new ArcGesture(center, + height, + width, + startAngle + i * 360 / fingerCount, + endAngle + i * 360 / fingerCount); + arcGesture.Duration = arcDuration; + AddCommand(arcGesture); + } + + if (pressCenter) + { + //In this case, leave the dot gesture running a little longer than the arc gesture + DotGesture dotGesture = new DotGesture(center, arcDuration + 3000); + AddCommand(dotGesture); + } + } + + public RotateGesture(ArcGesture[] arcGestures) + { + foreach (ArcGesture arcGesture in arcGestures) + { + AddCommand(arcGesture); + } + } + } + + #endregion + + #region "Circle" gesture + + /// + /// Traces out a circle of set radius from the location given + /// + public class CircleGesture : MultipleContactsGesture + { + public CircleGesture(double originX, double originY, double radiusInches) + { + SingleContactGesture arcgesture = new ArcGesture(new Point(originX, originY), radiusInches, radiusInches, 0.0, 360.0); + base.AddCommand(arcgesture); + } + } + + #endregion + + #region "Arc" gesture + + /// + /// Traces out a circle of set radius from the location given + /// + public class EllipseArcGesture : MultipleContactsGesture + { + public EllipseArcGesture(Point center, double height, double width, double startAngle, double endAngle) + { + SingleContactGesture archgesture = new ArcGesture(center, height, width, startAngle, endAngle); + base.AddCommand(archgesture); + } + } + + #endregion + + #region "Wave" gesture + + /// + /// Represents a single point touch that traces a path of a sine wave, starting at the given location + /// and with set amplitude and frequency + /// + public class WaveGesture : MultipleContactsGesture + { + public WaveGesture(double originX, double originY, double heightInches, double widthInches, int count) + { + SingleContactGesture sinegesture = new SineGesture(originX, originY, heightInches, widthInches, count, false); + base.AddCommand(sinegesture); + } + } + + #endregion + + #region "Translate" gesture + + /// + /// Represents a pan gesture that moves through + /// a set of points defined by the given PointF[] + /// + public class TranslateGesture : MultipleContactsGesture + { + public TranslateGesture(List points) + { + for (int i = 0; i < points.Count; i++) + { + SingleContactGesture lingesture = new LineGesture(points[i][0], points[i][1]); + base.AddCommand(lingesture); + } + } + } + + #endregion + +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ControlVisualHelper.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ControlVisualHelper.cs new file mode 100644 index 000000000..df8f7e780 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ControlVisualHelper.cs @@ -0,0 +1,636 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; +using Microsoft.Test; +using System.Windows.Controls.Primitives; +using System.Reflection; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// This is a temp visual tree helper kind of class, encapsulating many helper methods for various controls + /// that are useful in the MT testing. There is no single class existing currently in the test tree that would + /// supply all that we need here, so we can either go the hassle of referrencing ControlsCommon (another area) + /// or just reuse some of the helpers from there. In MQ - we should come up with a better story as to how we + /// manage these common libraries. + /// + public static class ControlVisualHelper + { + #region General VisualTreeHelper + + /// + /// Get visual tree children of a type + /// + /// Visual tree children type + /// A DependencyObject reference + /// A collection of one visual tree children type + private static void GetVisualChildren(DependencyObject current, Collection children) where T : DependencyObject + { + if (current != null) + { + if (current.GetType() == typeof(T)) + { + children.Add((T)current); + } + + for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(current); i++) + { + GetVisualChildren(System.Windows.Media.VisualTreeHelper.GetChild(current, i), children); + } + } + } + + /// + /// Get visual tree children of a type + /// + /// Visaul tree children type + /// A DependencyObject reference + /// Returns a collection of one visual tree children type + public static Collection GetVisualChildren(DependencyObject current) where T : DependencyObject + { + if (current == null) + { + return null; + } + + Collection children = new Collection(); + + GetVisualChildren(current, children); + + return children; + } + + /// + /// Get the first visual child from a FrameworkElement Template + /// + /// FrameworkElement type + /// FrameworkElement type + /// A FrameworkElement typeof P + /// Returns a FrameworkElement visual child typeof T if found one; returns null otherwise + public static T GetVisualChild(P templatedParent) + where T : FrameworkElement + where P : FrameworkElement + { + Collection children = GetVisualChildren(templatedParent); + + foreach (T child in children) + { + if (child.TemplatedParent == templatedParent) + { + return child; + } + } + + return null; + } + + /// + /// Get descendant by given type + /// Given the perf side effect of ApplyTemplate, use this method judiciously + /// + /// Visual element + /// type to search for + /// + public static Visual GetDescendantByType(Visual element, Type type) + { + if (element == null) return null; + if (element.GetType() == type) return element; + + Visual foundElement = null; + if (element is FrameworkElement) + { + (element as FrameworkElement).ApplyTemplate(); + } + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; + foundElement = GetDescendantByType(visual, type); + if (foundElement != null) + { + break; + } + } + return foundElement; + } + + /// + /// Walk up the visual tree looking for a node with a given type + /// + /// type of desired node + /// starting node for the search + /// if false, do not test the node itself + /// + public static DependencyObject FindAncestorByType(Type type, DependencyObject node, bool includeNode) + { + if (node == null) + throw new ArgumentNullException("node"); + + if (includeNode) + { + if (type == node.GetType()) + return node; + } + + for (node = VisualTreeHelper.GetParent(node); node != null; node = VisualTreeHelper.GetParent(node)) + { + if (type == node.GetType()) + return node; + } + + return null; + } + + #endregion + + #region ScrollViewer + + /// + /// Get ScrollContentPresenter from a ScrollViewer + /// + /// A ScrollViewer referecnce + /// Returns a ScrollContentPresenter if found; returns null otherwise + public static ScrollContentPresenter GetScrollContentPresenter(ScrollViewer scrollViewer) + { + return (ScrollContentPresenter)scrollViewer.Template.FindName("PART_ScrollContentPresenter", scrollViewer); + } + + /// + /// Get ScrollBar from a ScrollViewer + /// + /// A ScrollViewer reference + /// ScrollBar part name + /// Returns a ScrollBar if found; returns null otherwise + public static ScrollBar GetScrollBar(ScrollViewer scrollViewer, ScrollBarPartName scrollBarPartName) + { + return (ScrollBar)scrollViewer.Template.FindName(scrollBarPartName.ToString(), scrollViewer); + } + + /// + /// Get VirtualizingStackPanel from a ScrollContentPresenter + /// + /// A ScrollContentPresenter reference + /// Returns a VirtualizingStackPanel if found; returns null otherwise + public static VirtualizingStackPanel GetVirtualizingStackPanel(ScrollContentPresenter scrollContentPresenter) + { + Collection panels = GetVisualChildren(scrollContentPresenter); + + foreach (VirtualizingStackPanel panel in panels) + { + if (String.Compare(panel.TemplatedParent.GetType().Name, "ItemsPresenter") == 0) + { + return panel; + } + } + + return null; + } + + #endregion + + #region ViewPort + + /// + /// Whether the item is in viewport or not. + /// + /// A Control reference + /// Returns true if the Control is in viewport; returns false otherwise + public static bool IsInViewport(Control item) + { + ItemsControl itemsControl = null; + + if (item is ListBoxItem) + { + itemsControl = GetListBox(item); + } + else if (item is TreeViewItem) + { + itemsControl = GetTreeView((TreeViewItem)item); + } + else if (item is DataGridCell) + { + itemsControl = (ItemsControl)item.GetType().InvokeMember("DataGridOwner", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, item, null); + } + else + { + throw new NotSupportedException(item.GetType().Name); + } + + ScrollViewer scrollViewer = GetVisualChild(itemsControl); + ScrollContentPresenter scrollContentPresenter = GetScrollContentPresenter(scrollViewer); + MethodInfo isInViewportMethod = scrollViewer.GetType().GetMethod("IsInViewport", BindingFlags.NonPublic | BindingFlags.Instance); + + return (bool)isInViewportMethod.Invoke(scrollViewer, new object[] { scrollContentPresenter, item }); + } + + /// + /// Get First Top Item InViewport Index + /// + /// A ListBox reference + /// Returns the first top item InViewport index + public static int GetFirstTopItemInViewportIndex(ListBox listbox) + { + ScrollViewer scrollViewer = GetVisualChild(listbox); + ScrollContentPresenter scrollContentPresenter = GetScrollContentPresenter(scrollViewer); + VirtualizingStackPanel virtualizingStackPanel = GetVirtualizingStackPanel(scrollContentPresenter); + + foreach (ListBoxItem item in virtualizingStackPanel.Children) + { + if (item.PointToScreen(new Point()).Y + item.ActualHeight / 2 > scrollContentPresenter.PointToScreen(new Point()).Y) + { + return listbox.ItemContainerGenerator.IndexFromContainer(item); + } + } + + throw new ArgumentNullException("Fail: the first top item InViewport index is not found."); + } + + /// + /// Get First Bottom Item Not InViewport Index + /// + /// A ListBox reference + /// First item InViewport index + /// Returns the first bottom item not InViewport index + public static int GetFirstBottomItemNotInViewportIndex(ListBox listbox, int firstItemInViewportIndex) + { + int firstBottomItemNotInViewportIndex = 0; + GetNumberOfItemsInViewport(listbox, firstItemInViewportIndex, ref firstBottomItemNotInViewportIndex); + return firstBottomItemNotInViewportIndex; + } + + /// + /// Get Last Bottom Item InViewport Index + /// + /// A ListBox reference + /// First item InViewport index + /// Returns the last bottom item InViewport index + public static int GetLastBottomItemInViewportIndex(ListBox listbox, int firstItemInViewportIndex) + { + int firstBottomItemNotInViewportIndex = 0; + GetNumberOfItemsInViewport(listbox, firstItemInViewportIndex, ref firstBottomItemNotInViewportIndex); + // the first bottom item not in view port index subtract 1 is the last bottom item in view port. + return firstBottomItemNotInViewportIndex - 1; + } + + /// + /// Get Number Of Items InViewport + /// + /// A ListBox reference + /// First item InViewport index + /// Returns the number of items InViewport + public static int GetNumberOfItemsInViewport(ListBox listbox, int firstItemInViewportIndex) + { + int firstBottomItemNotInViewportIndex = 0; + return GetNumberOfItemsInViewport(listbox, firstItemInViewportIndex, ref firstBottomItemNotInViewportIndex); + } + + private static int GetNumberOfItemsInViewport(ListBox listbox, int firstItemInViewportIndex, ref int index) + { + ScrollViewer scrollViewer = GetVisualChild(listbox); + double viewPortHeight = scrollViewer.ViewportHeight; + ScrollContentPresenter scrollContentPresenter = GetScrollContentPresenter(scrollViewer); + double itemsHeight = 0; + index = firstItemInViewportIndex; + int count = 1; + while (itemsHeight < scrollContentPresenter.ActualHeight) + { + ListBoxItem listBoxItem = listbox.ItemContainerGenerator.ContainerFromIndex(index++) as ListBoxItem; + if (listBoxItem == null) + { + break; + } + + itemsHeight += listBoxItem.ActualHeight; + count++; + } + + index = index - 1; + + if (listbox.ItemContainerGenerator.ContainerFromIndex(index) != null) + { + if (!IsInViewport((ListBoxItem)listbox.ItemContainerGenerator.ContainerFromIndex(index))) + { + throw new TestValidationException("Fail: " + index + " is not in Viewport."); + } + + if (listbox.ItemContainerGenerator.ContainerFromIndex(index + 1) != null) + { + if (IsInViewport((ListBoxItem)listbox.ItemContainerGenerator.ContainerFromIndex(index + 1))) + { + throw new TestValidationException("Fail: " + (index + 1) + " is in Viewport."); + } + } + } + + // subtract 1 because it includes one that is not in viewport + return count - 1; + } + + #endregion + + #region ItemsControl + + #region TreeView + + /// + /// Get TreeView from TreeViewItem + /// + /// A TreeViewItem reference + /// Returns a TreeView reference if found it; returns null otherwise + public static TreeView GetTreeView(TreeViewItem item) + { + return (TreeView)item.GetType().InvokeMember("ParentTreeView", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, item, null); + } + + /// + /// Scroll TreeView's ScrollView to top. + /// + /// A TreeViewItem reference + public static void ScrollTreeViewToTop(TreeViewItem treeviewitem) + { + ScrollViewer scrollViewer = GetVisualChild(GetTreeView(treeviewitem)); + scrollViewer.ScrollToHome(); + + // + } + + /// + /// Get a container from a ItemsControl + /// + /// A ItemsControl reference + /// An Index that you'd like to get the container from + /// Returns a TreeViewItem reference if found it; returns null otherwise + public static TreeViewItem GetContainer(ItemsControl itemsControl, int index) + { + return itemsControl.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; + } + + #endregion + + #region ListBox + + /// + /// GEt listbox from item container + /// + /// + /// + public static ListBox GetListBox(Control container) + { + return ItemsControl.ItemsControlFromItemContainer(container) as ListBox; + } + + #endregion + + #region ComboBox + + public static ToggleButton FindDropDownToggleButton(ComboBox combobox) + { + Collection toggleButtons = GetVisualChildren(combobox); + + for (int i = 0; i < toggleButtons.Count; i++) + { + if (toggleButtons[i].TemplatedParent == combobox) + { + return toggleButtons[i]; + } + } + + return null; + } + + public static void WaitForDropDownOpened(ComboBox combobox) + { + DispatcherFrame frame = new DispatcherFrame(); + combobox.DropDownOpened += delegate(Object s, EventArgs e) { frame.Continue = false; }; + Dispatcher.PushFrame(frame); + } + + public static void WaitForDropDownClosed(ComboBox combobox) + { + DispatcherFrame frame = new DispatcherFrame(); + combobox.DropDownClosed += delegate(Object s, EventArgs e) { frame.Continue = false; }; + Dispatcher.PushFrame(frame); + } + + #endregion + + #region DataGrid + + /// + /// Get scroll content presenter for a datagrid + /// + /// An instance of datagrid. + /// Returns datagrid's ScrollContentPresenter + public static ScrollContentPresenter GetScrollContentPresenter(DataGrid dataGrid) + { + ScrollViewer scrollViewer = GetVisualChild(dataGrid); + if (scrollViewer == null) + { + throw new TestValidationException("ScrollViewer is null."); + } + + return (ScrollContentPresenter)GetScrollContentPresenter(scrollViewer); + } + + /// + /// Get DataGridCell from a DataGridCellInfo. + /// + /// An instance of DataGridCellInfo. + /// DataGridCell if it is not null. + public static DataGridCell GetCell(DataGridCellInfo dataGridCellInfo) + { + if (!dataGridCellInfo.IsValid) + { + return null; + } + + var cellContent = dataGridCellInfo.Column.GetCellContent(dataGridCellInfo.Item); + if (cellContent != null) + { + return (DataGridCell)cellContent.Parent; + } + else + { + return null; + } + } + + /// + /// Gets the DataGridCell based on row and column index + /// + /// row index of cell to get + /// column index of cell to get + public static DataGridCell GetCell(DataGrid dataGrid, int row, int column) + { + DataGridRow rowContainer = GetRow(dataGrid, row); + if (rowContainer != null) + { + DataGridCellsPresenter presenter = GetVisualChild(rowContainer); + + // try to get the cell but it may possibly be virtualized + DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column); + if (cell == null) + { + // now try to bring into view and retreive the cell + dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]); + + //// + + cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column); + } + + return cell; + } + + return null; + } + + /// + /// this is a version that takes the virtualization into consideration, so the cell + /// can be null and don't have to be in view + /// + /// the row index + /// the column index + /// + public static DataGridCell GetCellVirtual(DataGrid dataGrid, int row, int column) + { + DataGridRow rowContainer = GetRow(dataGrid, row); + if (rowContainer != null) + { + return GetCell(rowContainer, column); + } + + return null; + } + + /// + /// Get a cell by the row container and column index + /// + /// row + /// column index + /// + public static DataGridCell GetCell(DataGridRow rowContainer, int column) + { + DataGridCellsPresenter presenter = GetCellsPresenter(rowContainer); + if (presenter != null) + { + return presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell; + } + + return null; + } + + /// + /// Check if a given cell is in the viewport + /// + /// the datagrid in test + /// cell to evaluate + /// true if in view else false + public static bool IsCellInView(DataGrid dataGrid, DataGridCell cell) + { + if (cell == null) + { + throw new ArgumentNullException("cell"); + } + + ScrollContentPresenter scrollContentPresenter = GetScrollContentPresenter(dataGrid); + int viewWidth = Convert.ToInt32(scrollContentPresenter.ActualWidth); + + GeneralTransform cellTransform = cell.TransformToAncestor(scrollContentPresenter); + Point ptIn = new Point(0, 0); + Point cellLeftX; + cellTransform.TryTransform(ptIn, out cellLeftX); + int cellRightX = Convert.ToInt32(cellLeftX.X + cell.RenderSize.Width); + + // cell left renders outside of scrollcontentpresenter on X coordinate. + if (cellLeftX.X < 0) + { + return false; + } + + // cell right renders outside of scrollcontentpresenter on X coordinate. + if (cellRightX > viewWidth) + { + return false; + } + + return true; + } + + public static DataGridCellsPresenter GetCellsPresenter(FrameworkElement parent) + { + return GetVisualChild(parent); // FindVisualChild(parent); + } + + /// + /// Gets the DataGridRow based on the given index + /// + /// the index of the container to get + public static DataGridRow GetRow(DataGrid dataGrid, int index) + { + DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index); + if (row == null) + { + // may be virtualized, bring into view and try again + dataGrid.ScrollIntoView(dataGrid.Items[index]); + + // + + row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index); + } + + return row; + } + + #endregion + + #region ListView + + + + #endregion + + #endregion + + #region Others + + // TextBoxBase - TextBox, PasswordBox + // DatePicker + // MenuItem + + // NavigationWindow + // BrowserWindow + + #endregion + + } + + public enum ScrollBarPartName + { + PART_VerticalScrollBar, + PART_HorizontalScrollBar, + Unknown + }; + + public enum ScrollingMode + { + LineUp, + LineDown, + LineLeft, + LineRight, + PageUp, + PageDown, + PageLeft, + PageRight, + Unknown + }; +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchDevice.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchDevice.cs new file mode 100644 index 000000000..f4996435a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchDevice.cs @@ -0,0 +1,155 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using System; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Custom TouchDevice for TouchDevice related captures + /// + public class CustomTouchDevice : TouchDevice + { + #region Constructor + + public CustomTouchDevice(int id) + : base(id) + { + } + + #endregion + + #region Public Methods, Properties, and Event Handlers + + /// + /// Provides the current position. + /// + /// Defines the coordinate space. + /// The current position in the coordinate space of relativeTo. + public override TouchPoint GetTouchPoint(IInputElement relativeTo) + { + if (relativeTo == null) + { + throw new ArgumentNullException("relativeTo"); + } + + if (CurrentTouchPoint != null) + { + if (relativeTo != null) + { + Visual rootVisual = ActiveSource.RootVisual; + UIElement element = relativeTo as UIElement; + if (element != null) + { + GeneralTransform transform = rootVisual.TransformToDescendant(element); + + Point position = transform.Transform(CurrentTouchPoint.Position); + Rect bounds = transform.TransformBounds(CurrentTouchPoint.Bounds); + + return new TouchPoint(this, position, bounds, _lastAction); + } + } + else + { + return CurrentTouchPoint; + } + } + + return null; + } + + /// + /// Provides all of the known points the device hit since the last reported position update. + /// + /// Defines the coordinate space. + /// A list of points in the coordinate space of relativeTo. + public override TouchPointCollection GetIntermediateTouchPoints(IInputElement relativeTo) + { + TouchPointCollection points = new TouchPointCollection(); + + TouchPoint point = GetTouchPoint(relativeTo); + if (point != null) + { + points.Add(point); + } + + return points; + } + + public void UpdateActiveSource(PresentationSource activeSource) + { + SetActiveSource(activeSource); + } + + public TouchPoint CurrentTouchPoint + { + get; + set; + } + + public void OnActivate() + { + Activate(); + } + + public void OnDeactivate() + { + Deactivate(); + } + + public void OnDown() + { + _lastAction = TouchAction.Down; + ReportDown(); + } + + public void OnMove() + { + _lastAction = TouchAction.Move; + ReportMove(); + } + + public void OnUp() + { + _lastAction = TouchAction.Up; + ReportUp(); + } + + public Point GetPosition(IInputElement relativeTo) + { + if (this._positionRelativeTo == null || relativeTo == null) + { + return new Point(0, 0); + } + + return this._positionRelativeTo.TranslatePoint(this._position, (UIElement)relativeTo); + } + + public new event EventHandler Updated; + + public void SetPosition(UIElement positionRelativeTo, Point position) + { + this._position = position; + this._positionRelativeTo = positionRelativeTo; + + if (Updated != null) + { + Updated(this, EventArgs.Empty); + } + } + + #endregion + + #region Private Fields + + private TouchAction _lastAction = TouchAction.Move; + private UIElement _positionRelativeTo; + private Point _position; + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchEventArgs.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchEventArgs.cs new file mode 100644 index 000000000..96bb84d87 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/CustomTouchEventArgs.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// This will be added in Beta 2 for Raw Touch + /// + public class CustomTouchEventArgs : RoutedEventArgs + { + #region Private members + + private int _x; // touch x client coordinate in pixels + private int _y; // touch y client coordinate in pixels + private int _id; // touch ID + private int _mask; // mask which fields in the structure are valid + private int _flags; // flags + private int _time; // touch event time + private int _touchX; // x size of the touch area in pixels + private int _touchY; // y size of the touch area in pixels + + #endregion + + #region Public Properties + + public int LocationX + { + get { return _x; } + set { _x = value; } + } + + public int LocationY + { + get { return _y; } + set { _y = value; } + } + + public int Id + { + get { return _id; } + set { _id = value; } + } + + public int Flags + { + get { return _flags; } + set { _flags = value; } + } + + public int Mask + { + get { return _mask; } + set { _mask = value; } + } + + public int Time + { + get { return _time; } + set { _time = value; } + } + + public int TouchX + { + get { return _touchX; } + set { _touchX = value; } + } + + public int TouchY + { + get { return _touchY; } + set { _touchY = value; } + } + + public bool IsPrimaryTouch + { + get { return (_flags & MultiTouchNativeMethods.TOUCHEVENTF_PRIMARY) != 0; } + } + + #endregion + + public CustomTouchEventArgs() + { + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/Directory.build.props b/src/Test/ElementServices/FeatureTests/Part1/Common/Directory.build.props new file mode 100644 index 000000000..1ba7b00fc --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/Directory.build.props @@ -0,0 +1,4 @@ + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/DoublePropertyTest.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/DoublePropertyTest.cs new file mode 100644 index 000000000..fb11ebaff --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/DoublePropertyTest.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Specializes Property for double values. + /// + /// + public class DoubleProperty : ValueTypeProperty where TOwningType : new() + { + #region Constructor + + /// + /// Constructor. + /// + /// The name of the property. + /// The default value of the property. + /// A function for enumerating valid and invalid values. + /// A function to get the property value. + /// An action that sets the property value. + public DoubleProperty( + string name, + double defaultValue, + System.Func> values, + System.Func getter, + System.Action setter) + : base(name, defaultValue, values, () => new TOwningType(), getter, setter) + { + } + + #endregion + + #region Methods + + /// + /// double.NaN doesn't evaluate as equal to itself + /// + /// + /// + /// + protected override bool CompareValues(double value1, double value2) + { + return (value1.Equals(value2)); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/DoubleUtil.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/DoubleUtil.cs new file mode 100644 index 000000000..fca02f430 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/DoubleUtil.cs @@ -0,0 +1,197 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// General double utilities + /// + public static class DoubleUtil + { + public const double epsilon = (double)0.49f; // half pixel, in various verifiers + + public const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ + + /// + /// AreClose - Returns whether or not two doubles are "close". That is, whether or + /// not they are within epsilon of each other. + /// + /// + /// bool - the result of the AreClose comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool AreClose(double value1, double value2) + { + if (value1 == value2) + { + return true; + } + + // computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON + double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; + double delta = value1 - value2; + return (-eps < delta) && (eps > delta); + } + + /// + /// LessThan - Returns whether or not the first double is less than the second double. + /// That is, whether or not the first is strictly less than *and* not within epsilon of + /// the other number. + /// + /// + /// bool - the result of the LessThan comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool LessThan(double value1, double value2) + { + return (value1 < value2) && !AreClose(value1, value2); + } + + /// + /// GreaterThan - Returns whether or not the first double is greater than the second double. + /// That is, whether or not the first is strictly greater than *and* not within epsilon of + /// the other number. + /// + /// + /// bool - the result of the GreaterThan comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool GreaterThan(double value1, double value2) + { + return (value1 > value2) && !AreClose(value1, value2); + } + + /// + /// LessThanOrClose - Returns whether or not the first double is less than or close to + /// the second double. That is, whether or not the first is strictly less than or within + /// epsilon of the other number. + /// + /// + /// bool - the result of the LessThanOrClose comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool LessThanOrClose(double value1, double value2) + { + return (value1 < value2) || AreClose(value1, value2); + } + + /// + /// GreaterThanOrClose - Returns whether or not the first double is greater than or close to + /// the second double. That is, whether or not the first is strictly greater than or within + /// epsilon of the other number. + /// + /// + /// bool - the result of the GreaterThanOrClose comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool GreaterThanOrClose(double value1, double value2) + { + return (value1 > value2) || AreClose(value1, value2); + } + + /// + /// Verifies if the given double is a finite number. + /// + /// + /// + public static bool IsDoubleFinite(double d) + { + return !(double.IsInfinity(d) || double.IsNaN(d)); + } + + /// + /// Verifies if the given double is a finite number or 0. + /// + /// + /// + public static bool IsDoubleFiniteNonZero(double d) + { + return IsDoubleFinite(d) && !IsZero(d); + } + + /// + /// Verifies if the given value is close to 0. + /// + /// + /// + public static bool IsZero(double d) + { + // IsZero(d) check can be used to make sure that dividing by 'd' will never produce Infinity. + // use DBL_EPSILON instead of double.Epsilon because double.Epsilon is too small and doesn't guarantee that. + return Math.Abs(d) <= DBL_EPSILON; + } + + /// + /// Limits a double value to the given interval. + /// + /// + /// + /// + /// + public static double Limit(double d, double min, double max) + { + if (!double.IsNaN(max) && d > max) + { + return max; + } + + if (!double.IsNaN(min) && d < min) + { + return min; + } + + return d; + } + + /// + /// Converts a double to a float + /// + /// the double value to convert + /// + public static float ConvertToFloat(double d) + { + float f = (float)d; + if (!double.IsInfinity(d) && float.IsInfinity(f)) + { + // The conversion exceeded the size of a float and the value became infinity. + // Instead, set the value to the min/max for float. + if (d > float.MaxValue) + { + f = float.MaxValue; + } + else if (d < float.MinValue) + { + f = float.MinValue; + } + } + + return f; + } + + /// + /// If a nullable double has a value, returns that value. Otherwise, returns 0.0. + /// + public static double ValueOrDefault(double? nullable) + { + return ValueOrDefault(nullable, 0.0); + } + + /// + /// If a nullable double has a value, returns that value. Otherwise, returns defaultValue. + /// + public static double ValueOrDefault(double? nullable, double defaultValue) + { + return nullable.HasValue ? nullable.Value : defaultValue; + } + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/EventCollector.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/EventCollector.cs new file mode 100644 index 000000000..b9791b2a3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/EventCollector.cs @@ -0,0 +1,402 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using Microsoft.Test.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Event parameters + /// + public class EventParameters + { + #region Fields + + private readonly object _originalSender; + private readonly RoutedEventArgs _originalRoutedEventArgs; + private readonly Point _position; + private readonly RoutedEvent _matchedRoutedEvent; + private readonly int _receivedTimestamp; + + #endregion + + #region Contructor + + public EventParameters(object sender, RoutedEventArgs args, Point snapshotPosition, RoutedEvent matchedRoutedEvent) + { + this._originalSender = sender; + this._originalRoutedEventArgs = args; + this._position = snapshotPosition; + this._matchedRoutedEvent = matchedRoutedEvent; + this._receivedTimestamp = Environment.TickCount; + } + + #endregion + + #region Properties + + public object OriginalSender + { + get + { + return this._originalSender; + } + } + + public RoutedEventArgs OriginalRoutedEventArgs + { + get + { + return this._originalRoutedEventArgs; + } + } + + public int ReceviedTimestamp + { + get + { + return this._receivedTimestamp; + } + } + + public Point Position + { + get + { + return this._position; + } + } + + public RoutedEvent MatchedRoutedEvent + { + get + { + return this._matchedRoutedEvent; + } + } + + #endregion + } + + /// + /// A general purpose collector of events + /// + /// Usage: + /// 1. Create an instance of this class and specify what events to collect. + /// 2. Call the AttachHandlers() method to subscribe event listerens + /// 3. Execute a test that is suppose to trigger events + /// 4. Call the CollectedEvents property to get a readonly collection of the collected events + /// 5. Call the RemoveHandlers() method to unsubscribe listeners before releasing the collector instance + /// + public class EventCollector + { + #region Fields + + private List _collectedEventParameters = new List(); + private RoutedEvent[] _eventsToCollect; + private readonly bool _collectAllEvents; + + #endregion + + #region Constructors + + /// + /// Construct an instance that can listern to the given events + /// + /// UIElement to retrive + /// + public EventCollector(params RoutedEvent[] eventsToCollect) + { + this._eventsToCollect = eventsToCollect; + this._collectAllEvents = false; + } + + public EventCollector(bool collectAllEvents) + { + this._eventsToCollect = new RoutedEvent[0]; + this._collectAllEvents = collectAllEvents; + } + + #endregion + + #region Properties + + /// + /// Returns a readonly collection of the collected events + /// + public ReadOnlyCollection CollectedEvents + { + get + { + return new ReadOnlyCollection(this._collectedEventParameters); + } + } + + /// + /// Returns the number of collected events + /// + public int CollectedEventsCount + { + get + { + return this._collectedEventParameters.Count; + } + } + + /// + /// The last collected event or null if no events have been collected + /// + public EventParameters LastEvent + { + get + { + return this._collectedEventParameters.Count > 0 ? + this._collectedEventParameters[this._collectedEventParameters.Count - 1] : + null; + } + } + + #endregion + + #region Various Methods + + /// + /// Attaches event handlers + /// + /// + /// + public void AddHandlers(DependencyObject obj, bool addToChildren) + { + Debug.Assert(obj != null); + foreach (RoutedEvent e in this._eventsToCollect) + { + MultiTouchVerifier.AddHandler(obj, e, new RoutedEventHandler(GenericEventHandler), false/*addToParents*/, addToChildren); + } + } + + /// + /// Detaches event handlers + /// + /// + /// + public void RemoveHandlers(DependencyObject obj, bool addToChildren) + { + Debug.Assert(obj != null); + foreach (RoutedEvent e in this._eventsToCollect) + { + MultiTouchVerifier.RemoveHandler(obj, e, new RoutedEventHandler(GenericEventHandler), false/*addToParents*/, addToChildren); + } + } + + /// + /// Clears the list of collected events + /// + public virtual void Clear() + { + this._collectedEventParameters.Clear(); + } + + /// + /// Base implementation of the Collect() method, derived class can override it. + /// + /// + /// + /// + protected virtual void Collect(IList list, object sender, RoutedEventArgs args) + { + list.Add(new EventParameters(sender, args, new Point(), args.RoutedEvent)); + } + + /// + /// Collects the event + /// + /// + /// + public void Collect(object sender, RoutedEventArgs args) + { + if (this._collectAllEvents || Array.Exists(this._eventsToCollect, delegate(RoutedEvent r) { return r == args.RoutedEvent; })) + { + Collect(_collectedEventParameters, sender, args); + } + } + + /// + /// Dumps the list of the collected events + /// + public void Dump() + { + Dump(this._collectedEventParameters); + } + + /// + /// Dumps the list of the collected events + /// + public static void Dump(IList collectedEvents) + { + for (int i = 0; i < collectedEvents.Count; i++) + { + EventParameters p = collectedEvents[i]; + Debug.WriteLine(" " + i + ": " + p.MatchedRoutedEvent + " sender=" + p.OriginalSender + "[" + GetHashCode(p.OriginalSender) + "]" + + " (" + p.OriginalRoutedEventArgs.RoutedEvent + ")" + + " position={" + p.Position.X + " " + p.Position.Y + "}" + + " source=" + p.OriginalRoutedEventArgs.Source + "[" + GetHashCode(p.OriginalRoutedEventArgs.Source) + "]"); + } + } + + /// + /// Compares events. - + + + + public static bool CompareEvents(IList expectedEvents, IList touchEvents) + { + Debug.WriteLine(""); + Debug.WriteLine("ACTUAL:"); + EventCollector.Dump(touchEvents); + + Debug.WriteLine(""); + Debug.WriteLine("EXPECTED:"); + EventCollector.Dump(expectedEvents); + + bool isMatch = true; + int mi = 0; + int ci = 0; + + Debug.WriteLine(""); + Debug.WriteLine("VERIFICATION:"); + for (; mi < expectedEvents.Count && ci < touchEvents.Count; mi++, ci++) + { + EventParameters baselineEvent = expectedEvents[mi]; + EventParameters touchEvent = touchEvents[ci]; + Debug.WriteLine(mi.ToString() + " EVENT, exp=" + baselineEvent.MatchedRoutedEvent + " act=" + touchEvent.MatchedRoutedEvent); + if (baselineEvent.MatchedRoutedEvent != touchEvent.MatchedRoutedEvent) + { + Debug.WriteLine("FAILURE: Unexpected event."); + isMatch = false; + } + + // check position + Point baselinePosition = baselineEvent.Position; + Point touchPosition = touchEvent.Position; + Debug.WriteLine("Position, exp={" + baselinePosition.X + " " + baselinePosition.Y + "} act={" + + touchPosition.X + " " + touchPosition.Y + "}"); + if (!IsTheSame(baselinePosition, touchPosition, 0.0001)) + { + Debug.WriteLine("FAILURE: Invalid Position."); + isMatch = false; + } + + // check source + RoutedEventArgs baselineEventArgs = baselineEvent.OriginalRoutedEventArgs; + if (touchEvent.OriginalRoutedEventArgs is StylusSystemGestureEventArgs) + { + StylusSystemGestureEventArgs gestureEventArgs = (StylusSystemGestureEventArgs)touchEvent.OriginalRoutedEventArgs; + + Debug.WriteLine("Source, exp=" + baselineEventArgs.Source + "[" + GetHashCode(baselineEventArgs.Source) + "]" + + " act=" + gestureEventArgs.Source + "[" + GetHashCode(gestureEventArgs.Source) + "]"); + if (baselineEventArgs.Source != gestureEventArgs.Source) + { + Debug.WriteLine("FAILURE: Invalid Source."); + isMatch = false; + } + } + else + { + TouchEventArgs touchEventArgs = (TouchEventArgs)touchEvent.OriginalRoutedEventArgs; + + Debug.WriteLine("Source, exp=" + baselineEventArgs.Source + "[" + GetHashCode(baselineEventArgs.Source) + "]" + + " act=" + touchEventArgs.Source + "[" + GetHashCode(touchEventArgs.Source) + "]"); + if (baselineEventArgs.Source != touchEventArgs.Source) + { + Debug.WriteLine("FAILURE: Invalid Source."); + isMatch = false; + } + } + + // check sender + Debug.WriteLine("Sender, exp=" + baselineEvent.OriginalSender + "[" + GetHashCode(baselineEvent.OriginalSender) + "]" + + " act=" + touchEvent.OriginalSender + "[" + GetHashCode(touchEvent.OriginalSender) + "]"); + if (baselineEvent.OriginalSender != touchEvent.OriginalSender) + { + Debug.WriteLine("FAILURE: Invalid Sender."); + isMatch = false; + } + } + + // missing events + for (; mi < expectedEvents.Count; mi++) + { + EventParameters baselineEvent = expectedEvents[mi]; + Debug.WriteLine("FAILURE, missing event: " + baselineEvent.MatchedRoutedEvent); + Debug.WriteLine("Position, {" + baselineEvent.Position.X + " " + baselineEvent.Position.Y + "}"); + Debug.WriteLine("Source, " + baselineEvent.OriginalRoutedEventArgs.Source + "[" + GetHashCode(baselineEvent.OriginalRoutedEventArgs.Source) + "]"); + Debug.WriteLine("Sender, " + baselineEvent.OriginalSender + "[" + GetHashCode(baselineEvent.OriginalSender) + "]"); + isMatch = false; + } + + // unexpected events + for (; ci < touchEvents.Count; ci++) + { + EventParameters touchEvent = touchEvents[ci]; + Debug.WriteLine("FAILURE, Unexpected event: " + touchEvent.MatchedRoutedEvent); + Debug.WriteLine("Position, {" + touchEvent.Position.X + " " + touchEvent.Position.Y + "}"); + Debug.WriteLine("Source, " + touchEvent.OriginalRoutedEventArgs.Source + "[" + GetHashCode(touchEvent.OriginalRoutedEventArgs.Source) + "]"); + Debug.WriteLine("Sender, " + touchEvent.OriginalSender + "[" + GetHashCode(touchEvent.OriginalSender) + "]"); + isMatch = false; + } + + return isMatch; + } + + /// + /// the good old helper + /// + public static void DoEvents() + { + // To keep this thread busy, we'll have to push a frame. + System.Windows.Threading.DispatcherFrame frame = new System.Windows.Threading.DispatcherFrame(); + + System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, + new System.Windows.Threading.DispatcherOperationCallback( + delegate(object arg) + { + frame.Continue = false; + return null; + }), null); + + // Keep the thread busy processing events until the timeout has expired. + System.Windows.Threading.Dispatcher.PushFrame(frame); + } + + /// + /// General event handler for all events + /// + /// + /// + private void GenericEventHandler(object sender, RoutedEventArgs args) + { + Collect(sender, args); + } + + private static string GetHashCode(object obj) + { + return obj == null ? "null" : obj.GetHashCode().ToString(); + } + + private static bool IsTheSame(Point pt1, Point pt2, double tolerance) + { + return Math.Abs(pt1.X - pt2.X) < tolerance && Math.Abs(pt1.Y - pt2.Y) < tolerance; + } + + #endregion + } + +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/EventMonitor.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/EventMonitor.cs new file mode 100644 index 000000000..fcf508313 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/EventMonitor.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Utility class to track the firing of events + /// + public class EventMonitor + { + #region Fields + + private readonly Stack _events = new Stack(); + + #endregion + + #region Methods + + /// + /// Register that an event has fired + /// + /// + public void Fire(EventArgs args) + { + this._events.Push(args); + } + + /// + /// Execute an action, expecting that no event will fire + /// + /// + public void ExpectNone(Action action) + { + EventArgs dummy = new EventArgs(); + this._events.Push(dummy); + action(); + EventArgs last = this._events.Pop(); + Utils.AssertEqual(dummy, last, "Event fired when wasn't expecting one"); + } + + /// + /// Call a function, expecting that no event will fire + /// + /// + /// + /// + public T ExpectNone(Func function) + { + T result = default(T); + ExpectNone(() => { result = function(); }); + return result; + } + + /// + /// Execute an action, expecting that one event of an expected type will fire + /// + /// + /// + public TEventArgs ExpectOne(Action action) where TEventArgs : EventArgs + { + EventArgs dummy = new EventArgs(); + this._events.Push(dummy); + action(); + EventArgs last = this._events.Pop(); + Utils.AssertEqual(dummy, last, "Event failed to fire when expected"); + + TEventArgs args = last as TEventArgs; + last = this._events.Pop(); + Utils.AssertEqual(dummy, last, "Too many events fired"); + Utils.Assert(args != null, "Unexpected event type fired"); + + return args; + } + + /// + /// Execute an action, expecting that at most one event will fire + /// + /// + public EventArgs ExpectAtMostOne(Action action) + { + EventArgs dummy = new EventArgs(); + this._events.Push(dummy); + action(); + EventArgs last = this._events.Pop(); + if (object.ReferenceEquals(last, dummy)) + { + // no event fired + return null; + } + EventArgs result = last; + last = this._events.Pop(); + Utils.AssertEqual(dummy, last, "Too many events fired"); + return result; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/FloatUtil.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/FloatUtil.cs new file mode 100644 index 000000000..1691584a3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/FloatUtil.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Utilities for float + /// + public static class FloatUtil + { + #region constants + + public static float FLT_EPSILON = 1.192092896e-07F; + public static float FLT_MAX_PRECISION = 0xffffff; + public static float INVERSE_FLT_MAX_PRECISION = 1.0F / FLT_MAX_PRECISION; + + #endregion + + /// + /// AreClose + /// + public static bool AreClose(float a, float b) + { + if (a == b) + { + return true; + } + + // computes (|a-b| / (|a| + |b| + 10.0f)) < FLT_EPSILON + float eps = ((float)Math.Abs(a) + (float)Math.Abs(b) + 10.0f) * FLT_EPSILON; + float delta = a - b; + return (-eps < delta) && (eps > delta); + } + + /// + /// IsOne + /// + public static bool IsOne(float a) + { + return AreClose(a, 1.0f); + } + + /// + /// IsZero + /// + public static bool IsZero(float a) + { + return AreClose(a, 0.0f); + } + + /// + /// IsCloseToDivideByZero + /// + public static bool IsCloseToDivideByZero(float numerator, float denominator) + { + return Math.Abs(denominator) <= Math.Abs(numerator) * INVERSE_FLT_MAX_PRECISION; + } + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/GestureAtoms.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureAtoms.cs new file mode 100644 index 000000000..e58e76a87 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureAtoms.cs @@ -0,0 +1,226 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Collections; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// All atom gestures for basic tracks like dot, line, etc., used to construct commonly used + /// gestures like drag, rotate, etc.. Gestures in SinglePointGestures.cs and + /// MultiplePointGestures.cs are prefered to use directly. + /// + + #region "DotGesture" gesture + + /// + /// Represent a single point touch that presses and releases + /// for a given number of milliseconds, getting a dot track. + /// + public class DotGesture : SingleContactGesture + { + public DotGesture(Point point) + { + origin = point; + samples = 1; + + CalculatePoints(); + } + + public DotGesture(Point point, int milliseconds) + { + origin = point; + samples = 1; + duration = milliseconds; + + CalculatePoints(); + } + + public override void CalculatePoints() + { + interpolated = new Point[1]; + interpolated[0] = origin; + } + } + + #endregion + + #region "LineGesture" gesture + + /// + /// Represents a single-point touch that moves through a set of pre-defined points + /// by the given PointF[], getting a line track + /// + public class LineGesture : SingleContactGesture + { + private Point[] _points; + + public LineGesture(Point[] inPoints, bool smoothed) + { + if (smoothed) + { + throw new NotImplementedException("Smoothed curve fit not yet implemented!"); + } + _points = inPoints; + + CalculatePoints(); + } + + /// + /// the original points + /// + internal override Point[] Points + { + get + { + return _points; + } + } + + public LineGesture(Point startpoint, Point endpoint) + { + _points = new Point[] { startpoint, endpoint }; + CalculatePoints(); + } + + public override void CalculatePoints() + { + int res = Samples - 1; + + interpolated = new Point[(_points.Length - 1) * Samples]; + + for (int i = 0; i < _points.Length - 1; i++) + { + Point point = _points[i]; + Point delta = new Point(_points[i + 1].X - _points[i].X, _points[i + 1].Y - _points[i].Y); + + for (int j = 0; j < Samples; j++) + { + interpolated[i * Samples + j].X = point.X + j * (delta.X / res); + interpolated[i * Samples + j].Y = point.Y + j * (delta.Y / res); + } + } + } + } + + #endregion + + #region "Arc" gesture + + /// + /// Represents a arch track that will be a part of a ellipse (circle is a special case for ellipse.) + /// + public class ArcGesture : SingleContactGesture + { + private Point _center; + private double _height; + private double _width; + private double _startAngle; + private double _endAngle; + + /// + /// Arc gesture + /// + /// the center of the ellipse + /// length of semi axis on Y direction + /// length of semi axis on X direction + /// the angle from which the arch starts + /// the angle at which the arch ends. + /// if startAngle > endAngle, this is clockwise, otherwise, it is anti-clockwise + public ArcGesture(Point center, double height, double width, double startAngle, double endAngle) + { + if (height <= 0 || width <= 0) + { + throw new ArgumentOutOfRangeException("width and height must be greater than 0"); + } + if (startAngle == endAngle) + { + throw new ArgumentOutOfRangeException("startAngle should not equal to endAngle"); + } + this._center = center; + this._height = height; + this._width = width; + this._startAngle = startAngle; + this._endAngle = endAngle; + + CalculatePoints(); + } + + public override void CalculatePoints() + { + double newx; + double newy; + double r; + double pathLen = _endAngle - _startAngle; + double perChange = pathLen / (double)(samples - 1); + double changedAngle = 0; + double currentAngle = 0; + + interpolated = new Point[samples]; + + for (int i = 0; i < samples; i++) + { + currentAngle = (_startAngle + changedAngle) * Math.PI / 180; + r = Math.Sqrt(Math.Pow(_height * _width, 2.0) + / (Math.Pow(_height * Math.Cos(currentAngle), 2.0) + + Math.Pow(_width * Math.Sin(currentAngle), 2.0))); + newx = _center.X + r * Math.Cos(currentAngle); + newy = _center.Y - r * Math.Sin(currentAngle); + changedAngle += perChange; + interpolated[i].X = (float)newx; + interpolated[i].Y = (float)newy; + } + } + } + + #endregion + + #region "SineGesture" gesture + + /// + /// Represents a single point touch that traces a path of a sine wave, starting at + /// the given location and with set amplitude and frequency + /// + public class SineGesture : SingleContactGesture + { + private double _height; + private double _width; + private int _count; + private bool _oscillate; + + public SineGesture(double originX, double originY, double heightInches, double widthInches, int count, bool oscillate) + { + this.origin = new Point(originX, originY); + this._height = heightInches; + this._width = widthInches; + this._count = count; + this._oscillate = oscillate; + base.RecalcOnSamplesChange = false; + + CalculatePoints(); + } + + public override void CalculatePoints() + { + double newx = origin.X; + double newy = origin.Y; + + List interpolatedList = new List(); + + for (newx = origin.X; (newx < origin.X + _width); newx += 1.0) + { + newy = origin.Y + _height * Math.Sin(((newx - origin.X) * 2 * Math.PI) * _count / _width); + interpolatedList.Add(new Point((_oscillate) ? origin.X : (double)newx, (double)newy)); + } + interpolated = interpolatedList.ToArray(); + } + + } + + #endregion +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/GestureEventArgs.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureEventArgs.cs new file mode 100644 index 000000000..857619fb2 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureEventArgs.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// General gesture testing event args + /// + public class GestureEventArgs : System.EventArgs + { + #region Private Fields + + private int _size; + private int _arguments; + private int _y; + private int _x; + private Point _deltaLocation; + private bool _validDeltas; + private int _deltaArgs; + + #endregion + + public GestureEventArgs() + { + } + + #region Public Properties + + public int Size + { + get { return _size; } + set { _size = value; } + } + + public int Arguments + { + get { return _arguments; } + set { _arguments = value; } + } + + public int LocationY + { + get { return _y; } + set { _y = value; } + } + + public int LocationX + { + get { return _x; } + set { _x = value; } + } + + public Point Location + { + get { return new Point(_x, _y); } + } + + public int DeltaArgs + { + get { return _deltaArgs; } + set { _deltaArgs = value; } + } + + public Point DeltaLocation + { + get { return _deltaLocation; } + set { _deltaLocation = value; } + } + + public bool ValidDeltas + { + get { return _validDeltas; } + set { _validDeltas = value; } + } + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/GestureVerifier.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureVerifier.cs new file mode 100644 index 000000000..4e4d71eb2 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/GestureVerifier.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Static Gestures verifier + /// + public class GestureVerifier : MultiTouchVerifier + { + #region Private Fields + + private StaticGestures _staticGesture; + private UIElement _uiElement; + + #endregion + + #region Constructor + + public GestureVerifier(UIElement element) + : base() + { + _uiElement = element; + } + + #endregion + + #region Public Properties + + public UIElement TargetElement + { + get + { + return _uiElement; + } + } + + public StaticGestures Gesture + { + get + { + return _staticGesture; + } + set + { + _staticGesture = value; + } + } + + #endregion + + #region Public Methods + + public void VerifyGesture() + { + switch (Gesture) + { + case StaticGestures.TwoFingerTap: + PerformTwoFingerTap(); + break; + + case StaticGestures.RollOver: + PerformRollOver(); + break; + + case StaticGestures.Drag: + case StaticGestures.Flick: + case StaticGestures.HoldEnter: + case StaticGestures.HoldLeave: + case StaticGestures.HoverEnter: + case StaticGestures.HoverLeave: + case StaticGestures.RightDrag: + case StaticGestures.RightTap: + case StaticGestures.Tap: + // existing ones, should be covered by regression tests w/ existing one + break; + + case StaticGestures.None: + // do nothing + break; + + default: + throw new NotImplementedException(); // not in WPF4 + + } + } + + #endregion + + #region Helpers + + void PerformTwoFingerTap() + { + // + } + + void PerformRollOver() + { + // + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationBoundaryData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationBoundaryData.cs new file mode 100644 index 000000000..b4da6f351 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationBoundaryData.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for a manipulation boundary feedback + /// + public struct ManipulationBoundaryData + { + public ManipulationDelta BoundaryFeedback; + public IInputElement Container; + + public object OriginalSource; + public object Source; + public int TimeStamp; + + public ManipulationBoundaryData(ManipulationBoundaryFeedbackEventArgs e) + { + BoundaryFeedback = e.BoundaryFeedback; + Container = e.ManipulationContainer; + + OriginalSource = e.OriginalSource; + Source = e.Source; + TimeStamp = e.Timestamp; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationComparisons.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationComparisons.cs new file mode 100644 index 000000000..8c5cd31eb --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationComparisons.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows.Input; +using System.Windows.Input.Manipulations; +using Microsoft.Test; +using Microsoft.Test.Discovery; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Threading; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Various comparisons for results of manipulations + /// + public static class ManipulationComparisons + { + /// + /// Check that all the deltas are zero. + /// + /// The delta to check. + /// If true, comparisons are done with hard ==; + /// otherwise, epsilon-tolerant comparison is done. + public static void CheckZero(ManipulationDelta delta, bool isHardZero) + { + CheckEqual(delta.Translation.X, 0.0, isHardZero, "Translation.X"); + CheckEqual(delta.Translation.Y, 0.0, isHardZero, "Translation.Y"); + CheckEqual(delta.Rotation, 0.0, isHardZero, "Rotation"); + CheckEqual(delta.Expansion.X, 0.0, isHardZero, "Expansion.X"); + CheckEqual(delta.Expansion.Y, 0.0, isHardZero, "Expansion.Y"); + CheckEqual(delta.Scale.X, 1.0, isHardZero, "Scale.X"); + CheckEqual(delta.Scale.Y, 1.0, isHardZero, "Scale.Y"); + } + + /// + /// Check that all the velocities are zero + /// + /// The velocities to check. + /// If true, comparisons are done with hard ==; + /// otherwise, epsilon-tolerant comparison is done. + public static void CheckZero(ManipulationVelocities velocities, bool isHardZero) + { + CheckEqual(velocities.LinearVelocity.X, 0.0, isHardZero, "LinearVelocity.X"); + CheckEqual(velocities.LinearVelocity.Y, 0.0, isHardZero, "LinearVelocity.Y"); + CheckEqual(velocities.AngularVelocity, 0.0, isHardZero, "AngularVelocity"); + CheckEqual(velocities.ExpansionVelocity.X, 0.0, isHardZero, "ExpansionVelocity.X"); + CheckEqual(velocities.ExpansionVelocity.Y, 0.0, isHardZero, "ExpansionVelocity.Y"); + } + + /// + /// Checks two manipulation deltas to see if they're equal + /// + /// The first delta + /// The second delta + /// A number representing the typical distance a point might move. + /// Used for generating error tolerances. + public static void CheckEqual(ManipulationDelta delta1, ManipulationDelta delta2, double scale) + { + const double baseEpsilon = 0.000006; + const double scaleEpsilon = 5 * baseEpsilon; + double linearEpsilon = baseEpsilon * scale; + + CheckNearlyEqual(delta2.Translation.X, delta1.Translation.X, linearEpsilon, "Translation.X"); + CheckNearlyEqual(delta2.Translation.Y, delta1.Translation.Y, linearEpsilon, "Translation.Y"); + CheckNearlyEqual(delta2.Rotation, delta1.Rotation, baseEpsilon, "Rotation"); + CheckNearlyEqual(delta2.Expansion.X, delta1.Expansion.X, linearEpsilon, "Expansion.X"); + CheckNearlyEqual(delta2.Expansion.Y, delta1.Expansion.Y, linearEpsilon, "Expansion.Y"); + CheckNearlyEqual(delta2.Scale.X, delta1.Scale.X, scaleEpsilon, "Scale.X"); + CheckNearlyEqual(delta2.Scale.X, delta1.Scale.Y, scaleEpsilon, "Scale.Y"); + } + + /// + /// Compares two sets of velocities + /// If one is a simple multiple of the other, returns the ratio. Otherwise, will assert. + /// If both are all zeroes, returns NaN. + /// + /// + /// + /// The ratio of velocities2 to velocities1. + public static double CheckVelocityRatio(ManipulationVelocities velocities1, ManipulationVelocities velocities2) + { + double overallRatio = double.NaN; + + CheckRatio(ref overallRatio, velocities1.LinearVelocity.X, velocities2.LinearVelocity.X, "LinearVelocity.X"); + CheckRatio(ref overallRatio, velocities1.LinearVelocity.Y, velocities2.LinearVelocity.Y, "LinearVelocity.Y"); + CheckRatio(ref overallRatio, velocities1.AngularVelocity, velocities2.AngularVelocity, "AngularVelocity"); + CheckRatio(ref overallRatio, velocities1.ExpansionVelocity.X, velocities2.ExpansionVelocity.X, "ExpansionVelocity.X"); + CheckRatio(ref overallRatio, velocities1.ExpansionVelocity.Y, velocities2.ExpansionVelocity.Y, "ExpansionVelocity.Y"); + + return overallRatio; + } + + /// + /// Check that a manipulation delta is rotation only + /// + /// + /// + public static void CheckRotationOnly(ManipulationDelta delta, double expectedDegrees) + { + double degrees = delta.Rotation * (double)(180.0 / Math.PI); + + + //CheckNearlyEqual(degrees - expectedDegrees, 0.0, 0.0001, "rotation error"); + //CheckNearlyEqual(delta.Translation.X, 0.0, 0.001, "Translation.X"); + //CheckNearlyEqual(delta.Translation.Y, 0.0, 0.001, "Translation.Y"); + //CheckNearlyEqual(delta.Expansion.X, 0.0, 0.0001, "Expansion.X"); + //CheckNearlyEqual(delta.Expansion.Y, 0.0, 0.0001, "Expansion.Y"); + //CheckNearlyEqual(delta.Scale.X, 1.0, 0.00001, "Scale.X"); + //CheckNearlyEqual(delta.Scale.Y, 1.0, 0.00001, "Scale.Y"); + } + + /// + /// Check whether two numbers are equal + /// + /// + /// + /// + /// + private static void CheckEqual(double value, double expected, bool isHardComparison, string paramName) + { + if (isHardComparison) + { + Utils.AssertEqualGeneric(expected, value, + string.Format("{0} should exactly equal {1}", paramName, expected)); + } + else + { + Utils.Assert(DoubleUtil.AreClose(value, expected), + string.Format("{0} should equal {1}", paramName, expected)); + } + } + + /// + /// Check whether two numbers are fairly close together. + /// + /// + /// + /// + /// + private static void CheckNearlyEqual(double value, double expected, double epsilon, string paramName) + { + double error = Math.Abs(value - expected); + Utils.Assert(error <= epsilon, + string.Format("{0} value of {1} doesn't match expected value of {2} with epsilon {3}", paramName, value, expected, epsilon)); + } + + + /// + /// Get a ratio between two numbers + /// If both are zero, returns NaN + /// + /// + /// + /// + private static double GetRatio(double value1, double value2) + { + if (DoubleUtil.IsZero(value1)) + { + if (DoubleUtil.IsZero(value2)) + { + return double.NaN; + } + else + { + return (value2 > 0.0) ? double.PositiveInfinity : double.NegativeInfinity; + } + } + else + { + return value2 / value1; + } + } + + /// + /// Checks the ratio between two numbers and sees whether it matches the expected + /// value. If the expected ratio is NaN, will allow any ratio, and set the expected + /// one to the actual one. + /// + /// + /// + /// + /// + private static void CheckRatio(ref double expectedRatio, double value1, double value2, string paramName) + { + double ratio = GetRatio(value1, value2); + if (double.IsNaN(expectedRatio)) + { + expectedRatio = ratio; + } + else if (!double.IsNaN(ratio)) + { + double error = Math.Abs(1 - ratio / expectedRatio); + const double epsilon = 0.0002; + Utils.Assert(error < epsilon, "{0} ratio is {1}, doesn't match expected value of {2}", + paramName, ratio, expectedRatio); + } + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationCompletedData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationCompletedData.cs new file mode 100644 index 000000000..7a73c840a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationCompletedData.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for Manipulation Completed Event Args + /// + public struct ManipulationCompletedData + { + public IInputElement Container; + public Point Origin; + public ManipulationDelta Total; + public ManipulationVelocities Velocites; + public bool IsInertia; + public IEnumerable Manipulators; + + public object OriginalSource; + public object Source; + public int TimeStamp; // + + public ManipulationCompletedData(ManipulationCompletedEventArgs e) + { + Container = e.ManipulationContainer; + Origin = e.ManipulationOrigin; + Total = e.TotalManipulation; + Velocites = e.FinalVelocities; + IsInertia = e.IsInertial; + Manipulators = e.Manipulators; + + OriginalSource = e.OriginalSource; + Source = e.Source; + TimeStamp = e.Timestamp; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationData.cs new file mode 100644 index 000000000..b23d8626e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationData.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for a manipulator for Surface scenarios + /// + public struct ManipulationData + { + // + + public Vector Translation; + public double Rotation; + public double Scale; + public double Expansion; + + public ManipulationData(Vector translation, double rotation, double scale, double expansion) + { + Translation = translation; + Rotation = rotation; + Scale = scale; + Expansion = expansion; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationDeltaData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationDeltaData.cs new file mode 100644 index 000000000..2f81a5db5 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationDeltaData.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for Manipulation Delta Event Args + /// + public struct ManipulationDeltaData + { + public bool IsInertial; + public IInputElement Container; + public Point Origin; + public ManipulationDelta Delta; + public ManipulationDelta Cumulative; + public ManipulationVelocities Velocites; + public IEnumerable Manipulators; + + public object OriginalSource; + public object Source; + public int TimeStamp; + + // + + public ManipulationDeltaData(ManipulationDeltaEventArgs e) + { + Origin = e.ManipulationOrigin; + Delta = e.DeltaManipulation; + Cumulative = e.CumulativeManipulation; + Velocites = e.Velocities; + IsInertial = e.IsInertial; + Container = e.ManipulationContainer; + Manipulators = e.Manipulators; + + OriginalSource = e.OriginalSource; + Source = e.Source; + TimeStamp = e.Timestamp; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationInertiaStartingData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationInertiaStartingData.cs new file mode 100644 index 000000000..4737c5b51 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationInertiaStartingData.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for properties in ManipulationInertiaStartingEventArgs + /// + public struct ManipulationInertiaStartingData + { + public Point Origin; + public ManipulationVelocities InitialVelocites; + // + public InertiaExpansionBehavior ExpansionBehavior; + public IInputElement Container; + public InertiaRotationBehavior RotationBehavior; + public InertiaTranslationBehavior TranslationBehavior; + public IEnumerable Manipulators; + + public ManipulationInertiaStartingData(ManipulationInertiaStartingEventArgs e) + { + Origin = e.ManipulationOrigin; + InitialVelocites = e.InitialVelocities; + ExpansionBehavior = e.ExpansionBehavior; + RotationBehavior = e.RotationBehavior; + TranslationBehavior = e.TranslationBehavior; + Container = e.ManipulationContainer; + Manipulators = e.Manipulators; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartedData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartedData.cs new file mode 100644 index 000000000..bce29ab08 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartedData.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for Manipulation Started Event Args + /// + public struct ManipulationStartedData + { + public IInputElement Container; + public Point Origin; + public IEnumerable Manipulators; + + public ManipulationStartedData(ManipulationStartedEventArgs e) + { + Container = e.ManipulationContainer; + Origin = e.ManipulationOrigin; + Manipulators = e.Manipulators; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartingData.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartingData.cs new file mode 100644 index 000000000..a1218520c --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationStartingData.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Input; +using System.Windows.Input.Manipulations; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// struct for Manipulation Starting Event Args + /// + public struct ManipulationStartingData + { + public ManipulationModes Mode; + public IInputElement Container; + public ManipulationPivot Pivot; + public bool IsSingleTouchEnabled; + public IEnumerable Manipulators; + // + + public ManipulationStartingData(ManipulationStartingEventArgs e) + { + Mode = e.Mode; + Container = e.ManipulationContainer; + Pivot = e.Pivot; + IsSingleTouchEnabled = e.IsSingleTouchEnabled; + Manipulators = e.Manipulators; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationState.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationState.cs new file mode 100644 index 000000000..10f1bda7b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationState.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + public enum ManipulationState + { + None, + ManipulationStarting, + ManipulationStarted, + ManipulationDelta, + ManipulationCompleted + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationVerifier.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationVerifier.cs new file mode 100644 index 000000000..830c13953 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ManipulationVerifier.cs @@ -0,0 +1,926 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using Microsoft.Test.Logging; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// General verifications for manipulations + /// + /// Segments - + /// a. inertia portions - need some review + /// b. combo MP modes - valid and invalid + /// c. event sequence - full and/or partial + /// d. event routing + /// e. hit testing + /// f. panning during deltas + /// F. MP factory – Beta 2 + /// + public class ManipulationVerifier : MultiTouchVerifier + { + #region Constructor + + public ManipulationVerifier(UIElement element) + : base() + { + Element = element; + //currentState = ManipulationState.None; + } + + #endregion + + #region Properties + + /// + /// keep track of the element that's being manipulated + /// + public UIElement Element { get; set; } // + + #region manipulation events data + + public ManipulationData ManipulationInfo { get; set; } + public ManipulationStartingData StartingEventData { get; set; } + public ManipulationStartedData StartedEventData { get; set; } + public ManipulationDeltaData DeltaEventData { get; set; } + public ManipulationInertiaStartingData InertiaStartingEventData { get; set; } + public ManipulationCompletedData CompletedEventData { get; set; } + public ManipulationBoundaryData BoundaryFeedbackData { get; set; } + public List manipulationDataList; // + + /// + /// set the ManipulationData + /// + public List ManipulationDataList + { + get + { + return manipulationDataList; + } + set + { + if (value == null) + { + throw new ArgumentNullException("manipulationDataList should not be null!"); + } + + manipulationDataList = value; + } + } + + #endregion + + /// + /// check if the manipulation is enabled + /// + /// + /// + public bool IsManipulationOn + { + get + { + return Element.IsManipulationEnabled; + } + } + + /// + /// check if there is any active manipulation for the Element + /// + /// + /// + public bool IsManipulationActive + { + get + { + return Manipulation.IsManipulationActive(Element); + } + } + + /// + /// Check for single or non-single touch manipulations + /// + public bool AllowsSingleMode + { + // + get + { + return _isSingleTouchEnabled; + } + set + { + _isSingleTouchEnabled = value; + } + } + + /// + /// keep track of the current mode + /// + public ManipulationModes CurrentSupportedMode + { + get + { + return _supportedMode; + } + set + { + _supportedMode = value; + } + } + + /// + /// Gets the set of manipulations that are allowed + /// + public ManipulationModes AllowedManipulations + { + get + { + ManipulationModes allowed = ManipulationModes.None; + + if (Allows(ManipulationModes.TranslateX)) + { + allowed |= ManipulationModes.TranslateX; + } + if (Allows(ManipulationModes.TranslateY)) + { + allowed |= ManipulationModes.TranslateY; + } + if (Allows(ManipulationModes.Scale) && (this._manipulatorsSinceStart > 1)) + { + allowed |= ManipulationModes.Scale; + } + if (Allows(ManipulationModes.Rotate) && ((this._manipulatorsSinceStart > 1) || this.HadPivotSinceStart)) + { + allowed |= ManipulationModes.Rotate; + } + + return allowed; + } + } + + /// + /// track the container + /// + public UIElement Container + { + get + { + return _container; + } + set + { + _container = value; + } + } + + /// + /// check if we have a pivot set + /// + public bool HadPivotSinceStart + { + get + { + return (_originPivot != null); + } + } + + /// + /// This value is true by default + /// If complete() is called before all velocities reach zero, the value should be set to false. + /// + public bool HaveAllVelocitiesReachZero + { + get { return _haveAllVelocitiesReachZero; } + set { _haveAllVelocitiesReachZero = value; } + } + + /// + /// starting event counter + /// + public int StartingEventCount + { + get { return _startingEventCount; } + } + + /// + /// started event counter + /// + public int StartedEventCount + { + get { return _startEventCount; } + } + + /// + /// delta event counter + /// + public int DeltaEventCount + { + get { return _deltaEventCount; } + } + + /// + /// inertia starting event counter + /// + public int InertiaStartingEventCount + { + get { return _inertiaStartingEventCount; } + } + + /// + /// completed event counter + /// + public int CompletedEventCount + { + get { return _completedEventCount; } + } + + /// + /// boundary feedback event counter + /// + public int BoundaryFeedbackEventCount + { + get { return _boundaryFeedback; } + } + + #endregion + + #region Public Methods and Events + + /// + /// check if a given manipulation mode is supported by the element + /// + /// + /// + public bool IsManipulationSupported(ManipulationModes mode) + { + return ((ManipulationModes)(this._supportedMode & mode)) == mode; + } + + /// + /// starting event + /// + /// + /// + public void VerifyStartingEvent(object sender, ManipulationStartingEventArgs e) + { + _startingEventCount++; + + // set the data + StartingEventData = new ManipulationStartingData(e); + + // set variables + _isSingleTouchEnabled = StartingEventData.IsSingleTouchEnabled; + _supportedMode = StartingEventData.Mode; + _container = (UIElement)StartingEventData.Container; + _originPivot = StartingEventData.Pivot; + } + + /// + /// started event + /// + /// + /// + public void VerifyStartedEvent(object sender, ManipulationStartedEventArgs e) + { + _startEventCount++; + + // get the data + StartedEventData = new ManipulationStartedData(e); + + // get the manipulation origin + _originStart = StartedEventData.Origin; + + // get the container + var localContainer = StartedEventData.Container; + Utils.Assert(localContainer == this._container, "In started - the container is incorrect"); + } + + /// + /// delta event + /// + /// + /// + public void VerifyDeltaEvent(object sender, ManipulationDeltaEventArgs e) + { + if (e.IsInertial) + { + _deltaInertiaEventCount++; + } + else + { + _deltaEventCount++; + } + + // set the current dalta data + DeltaEventData = new ManipulationDeltaData(e); + + // get the origin + _originDelta = DeltaEventData.Origin; // + + // get the container + _container = (UIElement)DeltaEventData.Container; + + //******************* + // verifications + //******************* + + // manipulation data + var manipulationDelta = DeltaEventData.Delta; + var manipulationCumulated = DeltaEventData.Cumulative; + var manipulationVelocities = DeltaEventData.Velocites; + + // cumulating delta + _translationDeltaCumulated += manipulationDelta.Translation; + _expansionDeltaCumulated += manipulationDelta.Expansion; + _scaleDeltaCumulated += manipulationDelta.Scale; // -1; + _rotationDeltaCumulated += manipulationDelta.Rotation; + ManipulationDelta cumulated = new ManipulationDelta(_translationDeltaCumulated, + _rotationDeltaCumulated, _scaleDeltaCumulated, _expansionDeltaCumulated); + + // current velocities - used later + _linearVelocityCurrent = manipulationVelocities.LinearVelocity; + _angularVelocityCurrent = manipulationVelocities.AngularVelocity; + _expansionVelocityCurrent = manipulationVelocities.ExpansionVelocity; + } + + /// + /// inertia starting + /// + /// + /// + public void VerifyInertiaStartingEvent(object sender, ManipulationInertiaStartingEventArgs e) + { + _inertiaStartingEventCount++; + + // set the data + InertiaStartingEventData = new ManipulationInertiaStartingData(e); + + // set variables + _inertiaElement = (UIElement)sender; + _originInertia = InertiaStartingEventData.Origin; + _container = (UIElement)InertiaStartingEventData.Container; + _inertiaInitialVelocities = InertiaStartingEventData.InitialVelocites; + } + + /// + /// verify completed + /// + /// + /// + public void VerifyCompletedEvent(object sender, ManipulationCompletedEventArgs e) + { + if (e.IsInertial) + { + _completedInertiaEventCount++; + } + else + { + _completedEventCount++; + } + + // set the completed data + CompletedEventData = new ManipulationCompletedData(e); + + // set the origin at the completion + _originCompleted = CompletedEventData.Origin; + + ManipulationDelta manipulationTotal; + manipulationTotal = e.TotalManipulation; + + // Verifications - the total should be close to the accumulated on the element + Utils.Assert(VerifyVector(manipulationTotal.Translation, DeltaEventData.Cumulative.Translation), string.Format("In Completed - Translation - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", manipulationTotal.Translation, _translationDeltaCumulated)); + Utils.Assert(VerifyVector(manipulationTotal.Expansion, DeltaEventData.Cumulative.Expansion), + string.Format("In Completed - Expansion - the sum of delta cumulated should be close to the total cumulated - Expected = {0}, Actual = {1}", manipulationTotal.Expansion, _expansionDeltaCumulated)); + + // + Utils.Assert(VerifyVector(manipulationTotal.Scale, DeltaEventData.Cumulative.Scale), + string.Format("Scale - the sum of delta cumulated should be close to the total cumulated - Expected = {0}, Actual = {1}", manipulationTotal.Scale, _scaleDeltaCumulated)); + + Utils.AssertAreClose(manipulationTotal.Rotation, DeltaEventData.Cumulative.Rotation, DoubleUtil.epsilon, + string.Format("In Completed - Rotation - the sum of delta cumulated should be close to the total cumulated - Expected = {0}, Actual = {1}", manipulationTotal.Rotation, _rotationDeltaCumulated)); + + // other verifications + if (e.IsInertial) + { + //note: this won't work if the inertia was completed before the velocities reach zero + if (HaveAllVelocitiesReachZero) + { + Utils.AssertAreClose(Math.Round(CompletedEventData.Velocites.AngularVelocity,1), 0, DoubleUtil.epsilon, "VerifyCompletedEvent: AngularVelocity is not expected!!"); + Utils.Assert(CompletedEventData.Velocites.ExpansionVelocity == new Vector(0, 0), "VerifyCompletedEvent: ExpansionVelocity is not expected!!"); + Utils.AssertAreClose(Math.Round(CompletedEventData.Velocites.LinearVelocity.X,1), 0, DoubleUtil.epsilon, "VerifyCompletedEvent: LinearVelocity.X is not expected!!"); + Utils.AssertAreClose(Math.Round(CompletedEventData.Velocites.LinearVelocity.Y,1), 0, DoubleUtil.epsilon, "VerifyCompletedEvent: LinearVelocity.Y is not expected!"); + + VerifyExpansion(); + VerifyRotation(); + } + } + else + { + // no inertia + VerifyOrigin(); + VerifyManipulations(e, (UIElement)sender); + VerifyVelocities(); + } + } + + /// + /// manipulation boundaryfeedback + /// + /// + /// + public void VerifyManipulationBoundaryFeedbackEvent(object sender, ManipulationBoundaryFeedbackEventArgs e) + { + _boundaryFeedback++; + + if (e.BoundaryFeedback != null) + { + BoundaryFeedbackData = new ManipulationBoundaryData(e); + } + } + + #endregion + + #region Private Manipulation Methods + + /// + /// verify the sender + /// + /// + private void VerifySender(object sender) + { + Utils.AssertEqual(Element, (UIElement)sender, "The sender should be the Element", null); // + } + + /// + /// Verify manipulations at Completed w/o inertia + /// + /// + + + + private void VerifyManipulations(ManipulationCompletedEventArgs e, UIElement element) + { + var totalManipulation = e.TotalManipulation; + + // verify the mode + if (totalManipulation.Translation.X != 0) + { + Utils.Assert(IsManipulationSupported(ManipulationModes.TranslateX), string.Format(CultureInfo.InvariantCulture, "VerifyManipulations: ManipulationModes.TranslateX should be enabled")); + } + + if (totalManipulation.Translation.Y != 0) + { + Utils.Assert(IsManipulationSupported(ManipulationModes.TranslateY), string.Format(CultureInfo.InvariantCulture, "VerifyManipulations: ManipulationModes.TranslateY should be enabled")); + } + + if (totalManipulation.Rotation != 0) + { + Utils.Assert(IsManipulationSupported(ManipulationModes.Rotate), string.Format(CultureInfo.InvariantCulture, "VerifyManipulations: ManipulationModes.Rotation should be enabled")); + } + + if (totalManipulation.Scale.X != 0 || totalManipulation.Scale.Y != 0) // should be uniformed + { + Utils.Assert(IsManipulationSupported(ManipulationModes.Scale), string.Format(CultureInfo.InvariantCulture, "VerifyManipulations: ManipulationModes.Scale should be enabled")); + } + + if (totalManipulation.Expansion.X != 0 || totalManipulation.Expansion.Y != 0) // should be uniformed + { + Utils.Assert(IsManipulationSupported(ManipulationModes.Scale), string.Format(CultureInfo.InvariantCulture, "VerifyManipulations: ManipulationModes.Scale should be enabled")); + } + + // verify related manipulations + if (WantsManipulation(_supportedMode)) + { + if (_supportedMode == ManipulationModes.All) + { + VerifyAllEnabled(); + } + else if (_supportedMode == ManipulationModes.Rotate) + { + VerifyOnlyRotateEnabled(); + } + else if (_supportedMode == ManipulationModes.TranslateX) + { + VerifyOnlyTranslateXEnabled(); + } + else if (_supportedMode == ManipulationModes.TranslateY) + { + VerifyOnlyTranslateYEnabled(); + } + else if ((_supportedMode == (ManipulationModes.TranslateX | ManipulationModes.TranslateY)) || + this._isSingleTouchEnabled) + { + VerifyOnlyTranslationEnabled(); + } + else if (_supportedMode == ManipulationModes.Scale) + { + VerifyOnlyScaleEnabled(); + } + } + else // none + { + VerifyNoneEnabled(); + } + } + + /// + /// General verificaions for ManipulationMode == ManipulationModes.All + /// + private void VerifyAllEnabled() + { + Utils.Assert(VerifyVector(_translationDeltaCumulated, CompletedEventData.Total.Translation), + string.Format("VerifyAllEnabled: Translation - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _translationDeltaCumulated, CompletedEventData.Total.Translation)); + Utils.Assert(VerifyVector(_expansionDeltaCumulated, CompletedEventData.Total.Expansion), + string.Format("VerifyAllEnabled: Expansion - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _expansionDeltaCumulated, CompletedEventData.Total.Expansion)); + + // + + + + Utils.AssertAreClose(_rotationDeltaCumulated, CompletedEventData.Total.Rotation, DoubleUtil.epsilon, + string.Format("VerifyAllEnabled: Rotation - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _rotationDeltaCumulated, CompletedEventData.Total.Rotation)); + Utils.Assert(VerifyVector(_linearVelocityCurrent, CompletedEventData.Velocites.LinearVelocity), + string.Format("VerifyAllEnabled: LinearVelocity - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _linearVelocityCurrent, CompletedEventData.Velocites.LinearVelocity)); + Utils.AssertAreClose(_angularVelocityCurrent, CompletedEventData.Velocites.AngularVelocity, DoubleUtil.epsilon, + string.Format("VerifyAllEnabled: AngularVelocity - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _angularVelocityCurrent, CompletedEventData.Velocites.AngularVelocity)); + Utils.Assert(VerifyVector(_expansionVelocityCurrent, CompletedEventData.Velocites.ExpansionVelocity), + string.Format("VerifyAllEnabled: ExpansionVelocity - the total should be close to the sum of the cumulated - Expected = {0}, Actual = {1}", _expansionVelocityCurrent, CompletedEventData.Velocites.ExpansionVelocity)); + } + + /// + /// General verificaions for ManipulationModes.None + /// + private void VerifyNoneEnabled() + { + Utils.Assert(CompletedEventData.Total == new ManipulationDelta(new Vector(0, 0), 0, new Vector(0, 0), new Vector(0, 0)), "VerifyNoneEnabled - Total Manipulation is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyNoneEnabled - Total Velocites is not expected!"); + } + + /// + /// General verificaions for ManipulationModes.Scale + /// + private void VerifyOnlyScaleEnabled() + { + Utils.Assert(CompletedEventData.Total.Translation == new Vector(0, 0), "VerifyOnlyScaleEnabled - Total Translation is not expected!"); + Utils.AssertAreClose(0.0, CompletedEventData.Total.Rotation, DoubleUtil.epsilon, "VerifyOnlyScaleEnabled - Total Rotation is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Expansion, "VerifyOnlyScaleEnabled - Total Expansion is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyOnlyScaleEnabled - Total Velocites is not expected!"); + } + + /// + /// general verificaitons for only Translate enable (TranslateX && TranslateY). + /// + private void VerifyOnlyTranslationEnabled() + { + Utils.AssertAreClose(0.0, CompletedEventData.Total.Rotation, DoubleUtil.epsilon, "VerifyOnlyTranslationEnabled - Total Rotation is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Scale, "VerifyOnlyTranslationEnabled - Total Scale is not expected!"); + + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Expansion, "VerifyOnlyTranslationEnabled - Total Expansion is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyOnlyTranslationEnabled - Total Velocites is not expected!"); + } + + /// + ///General verificaitions for ManipulationModes.TranslateX + /// + private void VerifyOnlyTranslateXEnabled() + { + Utils.AssertAreClose(0.0, CompletedEventData.Total.Translation.Y, DoubleUtil.epsilon, "VerifyOnlyTranslateXEnabled - Total Translation Y is not expected!"); + Utils.AssertAreClose(0.0, CompletedEventData.Total.Rotation, DoubleUtil.epsilon, "VerifyOnlyTranslateXEnabled - Total Rotation is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Scale, "VerifyOnlyTranslateXEnabled - Total Scale is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Expansion, "VerifyOnlyTranslateXEnabled - Total Expansion is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyOnlyTranslateXEnabled - Total Velocites is not expected!"); + } + + /// + /// General verificaitions for ManipulationModes.TranslateY + /// + private void VerifyOnlyTranslateYEnabled() + { + Utils.AssertAreClose(0.0, CompletedEventData.Total.Translation.X, DoubleUtil.epsilon, "VerifyOnlyTranslateYEnabled - Total Translation X is not expected!"); + Utils.AssertAreClose(0.0, CompletedEventData.Total.Rotation, DoubleUtil.epsilon, "VerifyOnlyTranslateYEnabled - Total Rotation is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Scale, "VerifyOnlyTranslateYEnabled - Total Scale is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Expansion, "VerifyOnlyTranslateYEnabled - Total Expansion is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyOnlyTranslateYEnabled - Total Velocites is not expected!"); + } + + /// + /// general verificaiton for ManipulationModes.Rotate + /// + private void VerifyOnlyRotateEnabled() + { + Utils.Assert(CompletedEventData.Total.Translation == new Vector(0, 0), "VerifyOnlyRotateEnabled - Total Translation is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Scale, "VerifyOnlyRotateEnabled - Total Scale is not expected!"); + Utils.Assert(new Vector(0, 0) == CompletedEventData.Total.Expansion, "VerifyOnlyRotateEnabled - Total Expansion is not expected!"); + Utils.Assert(CompletedEventData.Velocites == new ManipulationVelocities(new Vector(0, 0), 0, new Vector(0, 0)), "VerifyOnlyRotateEnabled - Total Velocites is not expected!"); + } + + /// + /// Check the velocities between last delta event and the completed event - all velocities should reach 0 by the last completed + /// + private void VerifyVelocities() + { + // + Utils.Assert(CompletedEventData.Velocites.LinearVelocity == _linearVelocityCurrent, "VerifyVelocities - Total LinearVelocity is not correct!"); + Utils.AssertAreClose(CompletedEventData.Velocites.AngularVelocity, _angularVelocityCurrent, DoubleUtil.epsilon, "VerifyVelocities - Total AngularVelocity is not correct!"); + Utils.Assert(CompletedEventData.Velocites.ExpansionVelocity == _expansionVelocityCurrent, "VerifyVelocities - Total ExpansionVelocity is not correct!"); + } + + /// + /// verify the manipulation origin from started to completed + /// + private void VerifyOrigin() + { + double actual = (double)(_originCompleted.X - _originStart.X); + // + } + + /// + /// verify + /// + private void VerifyBoundaryFeedback() + { + ManipulationDelta bf = BoundaryFeedbackData.BoundaryFeedback; + Utils.Assert(new Vector(0, 0) == bf.Scale, "VerifyBoundaryFeedback - Scale is not expected!"); + Utils.Assert(new Vector(0,0) == bf.Expansion, "VerifyBoundaryFeedback - Expansion is not expected!"); + Utils.AssertAreClose(0.0, bf.Rotation, DoubleUtil.epsilon, "VerifyBoundaryFeedback - Rotation is not expected!"); + } + + #endregion + + #region Private Inertia Methods + + /// + /// Verify that the Manipulation origin is correct + /// + /// + private void VerifyManipulationOrigin(Point expectedOrigin) + { + double actual = (double)(CompletedEventData.Origin.X - expectedOrigin.X); + Utils.Assert(DoubleUtil.LessThan(actual, DoubleUtil.epsilon), "VerifyManipulationOrigin: Manipulation Origin.X is not at the correct range!"); + + actual = (double)(CompletedEventData.Origin.Y - expectedOrigin.Y); + Utils.Assert(DoubleUtil.LessThan(actual, DoubleUtil.epsilon), "VerifyManipulationOrigin: Manipulation Origin.Y is not at the correct range!"); + } + + /// + /// Verify the expansion against the expected value within given default epsilon + /// + /// + private void VerifyExpansion(Vector expectedExpansion) + { + //ONLY USE X here!!! + double expansionError = Math.Abs(expectedExpansion.X - CompletedEventData.Total.Expansion.X); + Utils.Assert(DoubleUtil.LessThan(expansionError, DoubleUtil.epsilon), + string.Format("The expansion error is not within error margin, CurrentError = {0}, Epsilon = {1}", expansionError, DoubleUtil.epsilon)); + } + + /// + /// Verify Manipulation Origin when all velocity reach to zero + /// NOTE - given product change with Surface scnearios this is temp outdated + /// + private void VerifyInertiaOrigin() + { + double x = _originInertia.X + CompletedEventData.Total.Translation.X; + double y = _originInertia.Y + CompletedEventData.Total.Translation.Y; + VerifyManipulationOrigin(new Point(x, y)); + } + + /// + /// Verify rotation when all velocity reach to zero + /// + private void VerifyRotation() + { + double currentDiff = 0; + double rotationEpsilon = 0.1; + + if ((InertiaStartingEventData.InitialVelocites != null) && + !double.IsNaN(InertiaStartingEventData.InitialVelocites.AngularVelocity)) + { + var behavior = InertiaStartingEventData.RotationBehavior; + + if (!double.IsNaN(behavior.DesiredRotation) && + DoubleUtil.IsDoubleFinite(behavior.DesiredRotation)) + { + currentDiff = Math.Abs(behavior.DesiredRotation - CompletedEventData.Total.Rotation); + Utils.Assert(DoubleUtil.LessThan(currentDiff, rotationEpsilon), + string.Format("VerifyRotation: Total Rotation is not at expected range. CurrentError = {0}, Error margin = {1}", currentDiff, rotationEpsilon)); + } + else if (!double.IsNaN(behavior.DesiredDeceleration) && + DoubleUtil.IsDoubleFinite(behavior.DesiredDeceleration)) + { + double totalRotation = (double)(Math.Pow(InertiaStartingEventData.InitialVelocites.AngularVelocity, 2) / (2 * behavior.DesiredDeceleration)); + currentDiff = Math.Abs(CompletedEventData.Total.Rotation - totalRotation); + Utils.Assert(DoubleUtil.LessThan(currentDiff, rotationEpsilon), + string.Format("VerifyRotation: AngularDeceleration is not at expected range. CurrentError = {0}, Error margin = {1}", currentDiff, rotationEpsilon)); + } + } + } + + /// + /// Verify expansion after the velocities reach 0. + /// + private void VerifyExpansion() + { + if (InertiaStartingEventData.InitialVelocites != null) + { + var behavior = InertiaStartingEventData.ExpansionBehavior; + + if (DoubleUtil.IsDoubleFinite(behavior.DesiredExpansion.X) && + DoubleUtil.IsDoubleFinite(behavior.DesiredExpansion.Y)) + { + VerifyExpansion(behavior.DesiredExpansion); + } + else if (DoubleUtil.IsDoubleFinite(behavior.DesiredDeceleration)) + { + double locX = (Math.Pow(InertiaStartingEventData.InitialVelocites.ExpansionVelocity.X, 2) / (2 * behavior.DesiredDeceleration)); + VerifyExpansion(new Vector(locX, locX)); + } + } + } + + private bool VerifyVector(Vector expected, Vector actual) + { + double currentDiffX = 0; + double currentDiffY = 0; + bool isClose = true; + + currentDiffX = Math.Abs(expected.X - actual.X); + currentDiffY = Math.Abs(expected.Y - actual.Y); + + if (expected.X != 0 && expected.Y != 0) + { + if ((currentDiffX / expected.X) < 0.15 && (currentDiffY / expected.Y) < 0.15) + { + isClose = true; + } + else + { + isClose = false; + } + } + + return isClose; + } + + #endregion + + #region Local Helpers + + /// + /// Get the visual parent of the element passed in + /// + /// the element + /// the visual parent + private static UIElement GetParent(object element) + { + return (UIElement)VisualTreeHelper.GetParent((UIElement)element); + } + + /// + /// reset all counters + /// + private void ResetAll() + { + _startingEventCount = 0; + _startEventCount = 0; + _deltaEventCount = 0; + _inertiaStartingEventCount = 0; + _completedEventCount = 0; + _boundaryFeedback = 0; + } + + /// + /// Make sure UIElement tested wants manipulations + /// + /// + /// + private static bool WantsManipulation(ManipulationModes mode) + { + return (mode & (ManipulationModes.Translate | ManipulationModes.Scale | ManipulationModes.Rotate)) != ManipulationModes.None; + } + + /// + /// check whether all the specified manipulations are allowed + /// + /// + /// + private bool Allows(ManipulationModes manipulations) + { + return (manipulations & this._supportedMode) == manipulations; + } + + /// + /// Detects whether a point falls within a registered element + /// + private static UIElement HitTestRegistered(Visual visual) + { + while (visual != null) + { + UIElement element = visual as UIElement; + + // NOTE - THIS WOULD NOT WORK W/O AN ACTIVE MANIPULATION + if ((element != null) && WantsManipulation(Manipulation.GetManipulationMode(element))) + { + return element; + } + else + { + visual = VisualTreeHelper.GetParent(visual) as Visual; + } + } + + return null; + } + + /// + /// expresses rotation in the specified degrees per second + /// + /// + /// + private static Func Rotate(double degreesPerSecond) + { + return (timestamp) => + { + double seconds = (double)timestamp / (double)oneSecond; + return degreesPerSecond * seconds; + }; + } + + /// + /// Gets whether a pivot is usable + /// + /// + /// + private static bool IsUsablePivot(ManipulationPivot pivot) + { + return (pivot != null) + && !double.IsNaN(pivot.Center.X) && !double.IsInfinity(pivot.Center.X) + && !double.IsNaN(pivot.Center.Y) && !double.IsInfinity(pivot.Center.Y) + && (!double.IsNaN(pivot.Radius) && (double.IsInfinity(pivot.Radius) || (pivot.Radius < 0.0D))); + } + + #endregion + + #region Fields + + // counters + private int _startingEventCount = 0; + private int _startEventCount = 0; + private int _deltaEventCount = 0; + private int _inertiaStartingEventCount = 0; + private int _completedEventCount = 0; + private int _boundaryFeedback = 0; + + private int _deltaInertiaEventCount = 0; + private int _completedInertiaEventCount = 0; + + private int _manipulatorsSinceStart = 0; + + // cumulated manipulation + private Vector _translationDeltaCumulated = new Vector(0, 0); + private double _rotationDeltaCumulated = 0; + private Vector _expansionDeltaCumulated = new Vector(0, 0); + private Vector _scaleDeltaCumulated = new Vector(0, 0); + + // current velocities + private Vector _linearVelocityCurrent = new Vector(0, 0); + private double _angularVelocityCurrent = 0; + private Vector _expansionVelocityCurrent = new Vector(0, 0); + + // manipulation origins + private Point _originStart = new Point(0, 0); + private Point _originDelta = new Point(0, 0); + private Point _originCompleted = new Point(0, 0); + private Point _originInertia = new Point(0, 0); + + private ManipulationVelocities _inertiaInitialVelocities; + private ManipulationPivot _originPivot; // pivot from the starting + + // indicators + private bool _isSingleTouchEnabled = false; + private bool _haveAllVelocitiesReachZero = true; + + // elements + // + private UIElement _inertiaElement; // + private UIElement _container; + + // mode + private ManipulationModes _supportedMode = ManipulationModes.All; + + // consts - manipulation processor needs + private const long oneSecond = 10000000; // # of timestamp ticks in 1 sec + private const double minProcessorRadius = 20.0; // the manipulator's value + private const double maxProcessorSmoothingRadius = 10.0 * minProcessorRadius; + private const double spatialScale = 4.0 * maxProcessorSmoothingRadius; + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchEventLog.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchEventLog.cs new file mode 100644 index 000000000..d9d923486 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchEventLog.cs @@ -0,0 +1,364 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; +using Microsoft.Test.Logging; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// A event log class for touch, both frame based and non-frame based, and manipulations, + /// which use TouchEventLog, FrameEventLog and ManipulationEventLog defined below + /// + public class MultiTouchEventLog + { + #region Public Lists for various logs + + public List AddedEvents = new List(); + public List ChangedEvents = new List(); + public List RemovedEvents = new List(); + public List TappedEvents = new List(); + public List HoldEvents = new List(); + public List TouchEnter = new List(); + public List TouchLeave = new List(); + public List GotTouchCapture = new List(); + public List LostTouchCapture = new List(); + + public List FrameEvents = new List(); + + public List ManipulationStartingEvents = new List(); + public List ManipulationStartedEvents = new List(); + public List ManipulationDeltaEvents = new List(); + public List ManipulationCompleteEvents = new List(); + public List ManipulationInertiaStartingEvents = new List(); + public List ManipulationBoundaryFeedbackEvents = new List(); + + #endregion + + #region Touch + + public void LogTouchAdded(object sender, TouchEventArgs e) + { + lock (AddedEvents) + { + TouchEventLog log = new TouchEventLog(e); + AddedEvents.Add(log); + } + } + + public void LogTouchUpdated(object sender, TouchEventArgs e) + { + lock (ChangedEvents) + { + TouchEventLog log = new TouchEventLog(e); + ChangedEvents.Add(log); + } + + } + + public void LogTouchRemoved(object sender, TouchEventArgs e) + { + lock (RemovedEvents) + { + TouchEventLog log = new TouchEventLog(e); + RemovedEvents.Add(log); + } + } + + public void LogTouchTapped(object sender, TouchEventArgs e) + { + lock (TappedEvents) + { + TouchEventLog log = new TouchEventLog(e); + TappedEvents.Add(log); + } + } + + public void LogTouchHold(object sender, TouchEventArgs e) + { + lock (HoldEvents) + { + TouchEventLog log = new TouchEventLog(e); + HoldEvents.Add(log); + } + } + public void LogTouchEnter(object sender, TouchEventArgs e) + { + lock (TouchEnter) + { + TouchEventLog log = new TouchEventLog(e); + TouchEnter.Add(log); + } + } + + public void LogTouchLeave(object sender, TouchEventArgs e) + { + lock (TouchLeave) + { + TouchEventLog log = new TouchEventLog(e); + TouchLeave.Add(log); + } + } + + public void LogGotTouchCapture(object sender, TouchEventArgs e) + { + lock (GotTouchCapture) + { + TouchEventLog log = new TouchEventLog(e); + GotTouchCapture.Add(log); + } + } + + public void LogLostTouchCapture(object sender, TouchEventArgs e) + { + lock (LostTouchCapture) + { + TouchEventLog log = new TouchEventLog(e); + LostTouchCapture.Add(log); + } + } + + #endregion + + #region Framebased + + public void LogFrameReceived(object sender, TouchFrameEventArgs e) + { + lock (FrameEvents) + { + FrameEventLog log = new FrameEventLog(); + // + FrameEvents.Add(log); + } + } + + #endregion + + #region Manipulations + + public void LogManipulationStarting(object sender, ManipulationStartingEventArgs e) + { + lock (ManipulationStartingEvents) + { + GlobalLog.LogEvidence(string.Format("--- {0}, MP Starting", DateTime.Now.ToLongTimeString())); + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationStartingEvents.Add(log); + } + } + + public void LogManipulationStarted(object sender, ManipulationStartedEventArgs e) + { + lock (ManipulationStartedEvents) + { + GlobalLog.LogEvidence(string.Format("--- {0}, MP Started", DateTime.Now.ToLongTimeString())); + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationStartedEvents.Add(log); + } + } + + public void LogManipulationDelta(object sender, ManipulationDeltaEventArgs e) + { + lock (ManipulationDeltaEvents) + { + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationDeltaEvents.Add(log); + } + } + + public void LogManipulationCompleted(object sender, ManipulationCompletedEventArgs e) + { + lock (ManipulationCompleteEvents) + { + GlobalLog.LogEvidence("--- {0}, MP Completed", DateTime.Now.ToLongTimeString()); + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationCompleteEvents.Add(log); + } + } + + public void LogManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) + { + lock (ManipulationInertiaStartingEvents) + { + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationInertiaStartingEvents.Add(log); + } + } + + public void LogManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e) + { + lock (ManipulationBoundaryFeedbackEvents) + { + ManipulationEventLog log = new ManipulationEventLog(e); + ManipulationBoundaryFeedbackEvents.Add(log); + } + } + + #endregion + } + + /// + /// a struct encapsulating the touch events + /// + public struct TouchEventLog + { + public TouchEventLog(TouchEventArgs e) + { + Time = DateTime.Now; + + this.touchDevice = e.TouchDevice; + Id = e.TouchDevice.Id; + + // + + + + } + + public DateTime Time; + public int Id; + public TouchDevice touchDevice; + + // + + + + } + + /// + /// a struct encapsulating frame event + /// + public struct FrameEventLog + { + public DateTime Time; + public long TimeStamp; + public TouchPoint PrimaryTouchPoint; + public TouchPointCollection TouchPoints; + public IInputElement RelativeTo; + } + + /// + /// a class encapsulating the manipulation events + /// + public class ManipulationEventLog + { + #region Fields + + // + public bool IsSingleManipulationEnabled; + public UIElement Container; + public ManipulationModes ManipulationMode; + + public double ManipulationOriginX; + public double ManipulationOriginY; + + public double DeltaX; + public double DeltaY; + public Vector ScaleDelta; + public double RotationDelta; + public Vector ExpansionDelta; + + public double CumulativeTranslationX; + public double CumulativeTranslationY; + public Vector CumulativeScale; + public double CumulativeRotation; + public Vector CumulativeExpansion; + + public double VelocityX; + public double VelocityY; + public double AngularVelocity; + public Vector ExpansionVelocity; + + public InertiaExpansionBehavior ExpansionBehavior; + public InertiaRotationBehavior RotationBehavior; + public InertiaTranslationBehavior TranslationBehavior; + + public ManipulationDelta Feedback; + + #endregion + + #region Constructors + + public ManipulationEventLog(ManipulationStartingEventArgs e) + { + Container = (UIElement)e.ManipulationContainer; + IsSingleManipulationEnabled = e.IsSingleTouchEnabled; + ManipulationMode = e.Mode; + } + + public ManipulationEventLog(ManipulationStartedEventArgs e) + { + ManipulationOriginX = e.ManipulationOrigin.X; + ManipulationOriginY = e.ManipulationOrigin.Y; + } + + public ManipulationEventLog(ManipulationDeltaEventArgs e) + { + ManipulationOriginX = e.ManipulationOrigin.X; + ManipulationOriginY = e.ManipulationOrigin.Y; + + DeltaX = e.DeltaManipulation.Translation.X; + DeltaY = e.DeltaManipulation.Translation.Y; + ScaleDelta = e.DeltaManipulation.Scale; + RotationDelta = e.DeltaManipulation.Rotation; + ExpansionDelta = e.DeltaManipulation.Expansion; + + CumulativeTranslationX = e.CumulativeManipulation.Translation.X; + CumulativeTranslationY = e.CumulativeManipulation.Translation.Y; + CumulativeScale = e.CumulativeManipulation.Scale; + CumulativeExpansion = e.CumulativeManipulation.Expansion; + CumulativeRotation = e.CumulativeManipulation.Rotation; + + VelocityX = e.Velocities.LinearVelocity.X; + VelocityY = e.Velocities.LinearVelocity.Y; + ExpansionVelocity = e.Velocities.ExpansionVelocity; + AngularVelocity = e.Velocities.AngularVelocity; + } + + public ManipulationEventLog(ManipulationInertiaStartingEventArgs e) + { + Container = (UIElement)e.ManipulationContainer; + + ManipulationOriginX = e.ManipulationOrigin.X; + ManipulationOriginY = e.ManipulationOrigin.Y; + + VelocityX = e.InitialVelocities.LinearVelocity.X; + VelocityY = e.InitialVelocities.LinearVelocity.Y; + ExpansionVelocity = e.InitialVelocities.ExpansionVelocity; + AngularVelocity = e.InitialVelocities.AngularVelocity; + + ExpansionBehavior = e.ExpansionBehavior; + TranslationBehavior = e.TranslationBehavior; + RotationBehavior = e.RotationBehavior; + } + + public ManipulationEventLog(ManipulationCompletedEventArgs e) + { + ManipulationOriginX = e.ManipulationOrigin.X; + ManipulationOriginY = e.ManipulationOrigin.Y; + + CumulativeTranslationX = e.TotalManipulation.Translation.X; + CumulativeTranslationY = e.TotalManipulation.Translation.Y; + CumulativeScale = e.TotalManipulation.Scale; + CumulativeExpansion = e.TotalManipulation.Expansion; + CumulativeRotation = e.TotalManipulation.Rotation; + + VelocityX = e.FinalVelocities.LinearVelocity.X; + VelocityY = e.FinalVelocities.LinearVelocity.Y; + ExpansionVelocity = e.FinalVelocities.ExpansionVelocity; + AngularVelocity = e.FinalVelocities.AngularVelocity; + } + + public ManipulationEventLog(ManipulationBoundaryFeedbackEventArgs e) + { + // + Container = (UIElement)e.ManipulationContainer; + Feedback = e.BoundaryFeedback; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchNativeMethods.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchNativeMethods.cs new file mode 100644 index 000000000..f1f3d4c10 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchNativeMethods.cs @@ -0,0 +1,312 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// MultiTouch related constants, DLLImports, structs, etc. + /// + public static class MultiTouchNativeMethods + { + #region Constants + + public const int GCF_ABORTIFHUNG = 2; + public const int GCF_ABORTIFHUNGANY = 4; + public const int GCF_SYNC = 1; + public const int GCI_COMMAND_INERTIA = 4; + public const int GCI_COMMAND_PAN = 2; + public const int GCI_COMMAND_ROLLOVER = 6; + public const int GCI_COMMAND_ROTATE = 3; + public const int GCI_COMMAND_TWOFINGERTAP = 5; + public const int GCI_COMMAND_ZOOM = 1; + public const int LOGPIXELSX = 0x58; + public const int LOGPIXELSY = 90; + public const int TWF_FINETOUCH = 1; + + //Nonzero if the current operating system is Windows 7 or Windows Server 2008 R2 and the Tablet PC Input service is started; otherwise, 0. + //The return value is a bit mask that specifies the type of digitizer input supported by the device. + //NOTE - Windows Server 2008, Windows Vista, and Windows XP/2000: This value is not supported!!! + public const int SM_DIGITIZER = 94; + + // Touch event window message constants + public const int WM_GESTURECOMMAND = 0x0119; + public const int WM_TOUCHMOVE = 0x0240; + public const int WM_TOUCHDOWN = 0x0241; + public const int WM_TOUCHUP = 0x0242; + public const int WM_FLICK = 715; + public const int WM_TABLET_QUERYSYSTEMGESTURESTATUS = 716; + + // Gesture commands + public const int GID_ZOOM = 1; + public const int GID_PAN = 2; + public const int GID_ROTATE = 3; + public const int GID_INERTIA = 4; + public const int GID_TWOFINGERTAP = 5; + public const int GID_ROLLOVER = 6; + public const int GID_GESTURE_BEGIN = 252; + public const int GID_GESTURE_END = 253; + public const int GID_BEGIN = 254; + public const int GID_END = 255; + + // Touch event flags + public const int GESTURE_STATUSF_ROTATE_ENABLE = 0x02000000; + public const int TOUCHEVENTF_MOVE = 0x0001; + public const int TOUCHEVENTF_DOWN = 0x0002; + public const int TOUCHEVENTF_UP = 0x0004; + public const int TOUCHEVENTF_INRANGE = 0x0008; + public const int TOUCHEVENTF_PRIMARY = 0x0010; + public const int TOUCHEVENTF_NOCOALESCE = 0x0020; + public const int TOUCHEVENTF_PEN = 0x0040; + + // Touch input mask values + public const int TOUCHINPUTMASKF_TIMEFROMSYSTEM = 0x0001; // the dwTime field contains a system generated value + public const int TOUCHINPUTMASKF_EXTRAINFO = 0x0002; // the dwExtraInfo field is valid + public const int TOUCHINPUTMASKF_CONTACTAREA = 0x0004; // the cxContact and cyContact fields are valid + + // General window message constants + public const int WM_CLOSE = 0x0010; + public const int WM_ACTIVATE = 0x0006; + + #endregion + + #region ExternDll + + public static class ExternDll + { + public const string Gdi32 = "gdi32.dll"; + public const string User32 = "user32.dll"; + public const string Uxtheme = "uxtheme.dll"; + } + + #endregion + + #region DllImport + + [DllImport(ExternDll.User32)] + public static extern bool SetProp( + IntPtr hWnd, + string lpString, + IntPtr hData); + + [DllImport(ExternDll.User32, BestFitMapping = false, CharSet = CharSet.Auto)] + public static extern bool SetPropMT( + HandleRef hWnd, + string propName, + HandleRef data); + + [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern int GetSystemMetrics(int nIndex); + + [DllImport(ExternDll.User32)] + public static extern bool GetGestureCommandInfo( + int uMsg, + IntPtr wParam, + IntPtr lParam, + IntPtr lExtraInfo, + out GESTURECOMMANDINFO pGestureCommandInfo); + + [DllImport(ExternDll.User32)] + public static extern bool GetTouchInputInfo( + IntPtr hTouchInput, + int cInput, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] TOUCHINPUT[] pInputs, + int cbSize); + + // WMGesture + [DllImport(ExternDll.User32)] + public static extern bool RegisterGestureHandlerWindow( + IntPtr hwnd, + long flags); + + // WMTouch + [DllImport(ExternDll.User32)] + public static extern bool RegisterTouchWindow( + IntPtr hwnd, + long flags); + + [DllImport(ExternDll.User32)] + public static extern bool UnregisterGestureHandlerWindow(IntPtr hwnd); + + [DllImport(ExternDll.User32)] + public static extern bool UnregisterTouchWindow(IntPtr hwnd); + + [DllImport(ExternDll.User32)] + public static extern bool CloseTouchInputHandle(IntPtr hTouchInput); + + [DllImport(ExternDll.Uxtheme, CharSet = CharSet.Unicode)] + public static extern bool BeginPanningFeedback(HandleRef hwnd); + + [DllImport(ExternDll.Uxtheme, CharSet = CharSet.Unicode)] + public static extern bool UpdatePanningFeedback( + HandleRef hwnd, + int lTotalOverpanOffsetX, + int lTotalOverpanOffsetY, + bool fInInertia); + + [DllImport(ExternDll.Uxtheme, CharSet = CharSet.Unicode)] + public static extern bool EndPanningFeedback(HandleRef hwnd, bool fAnimateBack); + + [DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Auto)] + public static extern uint GetRawInputDeviceList( + [In, Out] RAWINPUTDEVICELIST[] ridl, + [In, Out] ref uint numDevices, + uint sizeInBytes); + + [DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Auto)] + public static extern uint GetRawInputDeviceInfo( + IntPtr hDevice, + uint command, + [In] ref RID_DEVICE_INFO ridInfo, + ref uint sizeInBytes); + + [DllImport(ExternDll.User32)] + public static extern IntPtr GetDC(IntPtr HWND); + + [DllImport(ExternDll.Gdi32, SetLastError = true)] + public static extern int GetDeviceCaps( + IntPtr HDC, + int flagIndex); + + [DllImport(ExternDll.User32)] + public static extern int ReleaseDC( + IntPtr HWND, + IntPtr HDC); + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential)] + public struct GESTURECOMMANDINFO + { + public uint cbSize; + public uint dwFlags; + public uint dwCommand; + public uint dwArguments; + public ushort usX; + public ushort usY; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TOUCHINPUT + { + public int x; + public int y; + public IntPtr hSource; + public uint dwID; + public uint dwFlags; + public uint dwMask; + public uint dwTime; + public UIntPtr dwExtraInfo; + public uint cxContact; + public uint cyContact; + } + + [StructLayout(LayoutKind.Sequential)] + public struct POINTS + { + public short x; + public short y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GESTUREINFO + { + public int cbSize; + public int dwFlags; + public int dwCommand; + public int dwArguments; + [MarshalAs(UnmanagedType.Struct)] + public POINTS ptsLocation; + } + + #region WPF Tablet + + [StructLayout(LayoutKind.Sequential)] + public struct RAWINPUTDEVICELIST + { + public IntPtr hDevice; + public uint dwType; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RID_DEVICE_INFO_MOUSE + { + public uint dwId; + public uint dwNumberOfButtons; + public uint dwSampleRate; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RID_DEVICE_INFO_KEYBOARD + { + public uint dwType; + public uint dwSubType; + public uint dwKeyboardMode; + public uint dwNumberOfFunctionKeys; + public uint dwNumberOfIndicators; + public uint dwNumberOfKeysTotal; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RID_DEVICE_INFO_HID + { + public uint dwVendorId; + public uint dwProductId; + public uint dwVersionNumber; + public ushort usUsagePage; + public ushort usUsage; + } + + [StructLayout(LayoutKind.Explicit)] + public struct RID_DEVICE_INFO + { + [FieldOffset(0)] + public uint cbSize; + [FieldOffset(4)] + public uint dwType; + [FieldOffset(8)] + public RID_DEVICE_INFO_MOUSE mouse; + [FieldOffset(8)] + public RID_DEVICE_INFO_KEYBOARD keyboard; + [FieldOffset(8)] + public RID_DEVICE_INFO_HID hid; + } + + public const uint RIDI_DEVICEINFO = 0x2000000b; + public const uint RIM_TYPEHID = 2; + public const ushort HID_USAGE_PAGE_DIGITIZER = 0x0D; + public const ushort HID_USAGE_DIGITIZER_DIGITIZER = 1; + public const ushort HID_USAGE_DIGITIZER_PEN = 2; + public const ushort HID_USAGE_DIGITIZER_LIGHTPEN = 3; + public const ushort HID_USAGE_DIGITIZER_TOUCHSCREEN = 4; + + #endregion + + #endregion + + #region Input Interaction + + [DllImport(ExternDll.User32, CharSet = CharSet.Auto, EntryPoint = "BlockInput")] + private static extern int Win32BlockInput(int fBlockIt); + + /// + /// Prevent user from sending any input to the system. (Press CTRL-ALT-DEL to unblock if you need to). + /// + private static void Win32BlockInput(bool blockIt) + { + int hr = Win32BlockInput(blockIt ? 1 : 0); + if (hr < 0) + { + throw new Win32Exception(); + } + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestCommon.csproj b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestCommon.csproj new file mode 100644 index 000000000..10de02893 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestCommon.csproj @@ -0,0 +1,68 @@ + + + + MultiTouchTestCommon + Library + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestModes.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestModes.cs new file mode 100644 index 000000000..e73055ee7 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchTestModes.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Test.Input.MultiTouch +{ + public enum MultiTouchTestModes + { + Gestures, + Touch, + Manipulations, + Events, + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchVerifier.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchVerifier.cs new file mode 100644 index 000000000..6a60bb6d1 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultiTouchVerifier.cs @@ -0,0 +1,894 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Windows.Input; +using System.Runtime.InteropServices; +using System.Windows; +using System.Collections; +using System.Collections.Generic; +using System.Windows.Media; +using System.Diagnostics; +using System.Windows.Controls; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Base class for MultiTouch testing verifiers + /// + public abstract class MultiTouchVerifier + { + #region Fields + + private MultiTouchTestModes _mtTestMode; + private TabletDevice _inputDevice; + private static MultiTouchVerifier s_verifier; + + const int VistaMajorVersion = 6; + + #endregion + + #region Constructor + + public MultiTouchVerifier() + { + _mtTestMode = MultiTouchTestModes.Manipulations; + s_verifier = this; + } + + #endregion + + #region Public and Protected Properties + + public MultiTouchTestModes MultiTouchMode + { + get + { + return _mtTestMode; + } + set + { + _mtTestMode = value; + } + } + + public TabletDevice InputDevice + { + get + { + return _inputDevice; + } + set + { + _inputDevice = value; + } + } + + public static bool IsMultiTouchDigitizer() + { + int value = MultiTouchNativeMethods.GetSystemMetrics(MultiTouchNativeMethods.SM_DIGITIZER); + return ((value & 0x40) == 0); + } + + /// + /// for the time being only Win7 and Win2k8 RC have MT support, so check only these OSs for now + /// + /// + public static bool IsSupportedOS() + { + return (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1); + } + + public static bool IsTabletDeviceAvailable() + { + uint deviceCount = 0; + // Determine the # of devices (result will be -1 if fails and cDevices will have count) + int result = (int)MultiTouchNativeMethods.GetRawInputDeviceList(null, ref deviceCount, (uint)Marshal.SizeOf(typeof(MultiTouchNativeMethods.RAWINPUTDEVICELIST))); + + if (result >= 0 && deviceCount != 0) + { + MultiTouchNativeMethods.RAWINPUTDEVICELIST[] ridl = new MultiTouchNativeMethods.RAWINPUTDEVICELIST[deviceCount]; + int count = (int)MultiTouchNativeMethods.GetRawInputDeviceList(ridl, ref deviceCount, (uint)Marshal.SizeOf(typeof(MultiTouchNativeMethods.RAWINPUTDEVICELIST))); + + if (count > 0) + { + for (int i = 0; i < count; i++) + { + if (ridl[i].dwType == MultiTouchNativeMethods.RIM_TYPEHID) + { + MultiTouchNativeMethods.RID_DEVICE_INFO deviceInfo = new MultiTouchNativeMethods.RID_DEVICE_INFO(); + deviceInfo.cbSize = (uint)Marshal.SizeOf(typeof(MultiTouchNativeMethods.RID_DEVICE_INFO)); + uint cbSize = (uint)deviceInfo.cbSize; + int cBytes = (int)MultiTouchNativeMethods.GetRawInputDeviceInfo(ridl[i].hDevice, MultiTouchNativeMethods.RIDI_DEVICEINFO, ref deviceInfo, ref cbSize); + + if (cBytes > 0) + { + if (deviceInfo.hid.usUsagePage == MultiTouchNativeMethods.HID_USAGE_PAGE_DIGITIZER) + { + switch (deviceInfo.hid.usUsage) + { + case MultiTouchNativeMethods.HID_USAGE_DIGITIZER_DIGITIZER: + case MultiTouchNativeMethods.HID_USAGE_DIGITIZER_PEN: + case MultiTouchNativeMethods.HID_USAGE_DIGITIZER_TOUCHSCREEN: + case MultiTouchNativeMethods.HID_USAGE_DIGITIZER_LIGHTPEN: + { + return true; + } + } + } + } + else + { + System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceInfo failed!"); + } + } + } + } + else if (count < 0) + { + System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceList failed!"); + } + } + + return false; + } + + public bool IsSimulationAvailable + { + get + { + if (MultiTouchVerifier.IsSupportedOS() && + //MultiTouchVerifier.IsTabletDeviceAvailable() && + Tablet.TabletDevices.Count > 0) + { + foreach (TabletDevice tablet in Tablet.TabletDevices) + { + if ((string.Compare(tablet.Name, "VHidPen", false, System.Globalization.CultureInfo.InvariantCulture) == 0) && + tablet.Type == TabletDeviceType.Touch) + { + _inputDevice = tablet; + return true; + } + } + } + + return false; + } + } + + public bool IsTouchEnabled + { + get { return true; } // + } + + protected static MultiTouchVerifier Verifier + { + get { return s_verifier; } + set { s_verifier = value; } + } + + #endregion + + #region General MP Methods + + /// + /// check if a given manipulation modes is valid + /// + /// + /// + public bool IsValidManipulationMode(ManipulationModes mode) + { + return (mode & (ManipulationModes.Translate | ManipulationModes.Scale | ManipulationModes.Rotate)) != ManipulationModes.None; + } + + #endregion + + #region Validation helpers for MP/IP params + + /// + /// Checks if the given value is valid. + /// + /// + /// + /// + public void CheckOriginalValue(double value, string property, string paramName) + { + Utils.CheckFinite(value, property, paramName); + } + + /// + /// Checks if the given value is a valid velocity. + /// + /// + /// + /// + public void CheckVelocity(double value, string property, string paramName) + { + Utils.CheckFiniteOrNaN(value, property, paramName); + } + + /// + /// Checks if the given value is a valid offset. + /// + /// + /// + /// + public void CheckOffset(double value, string property, string paramName) + { + Utils.CheckFiniteNonNegative(value, property, paramName); + } + + /// + /// Checks if the given value is a valid deceleration. + /// + /// + /// + /// + public void CheckDeceleration(double value, string property, string paramName) + { + Utils.CheckFiniteNonNegative(value, property, paramName); + } + + /// + /// Checks if the given value is valid radius. + /// + /// + /// + public void CheckRadius(double value, string paramName) + { + if (value < 1 || double.IsInfinity(value) || double.IsNaN(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckRadius for param [{0}]", paramName)); + } + } + + #endregion + + #region Asserts + + /// + /// add it here so all tests can use it directly. + /// + /// + public void AssertNotNull(object element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + } + + #endregion + + #region Hit Testing and Tree Helpers - TODO: refactoring to outside the verifier + + /// + /// Checks whether the given element is hit-testable or not. + /// + /// + /// + public static bool IsHitTestable(object obj) + { + UIElement uiElement = obj as UIElement; + if (uiElement != null) + { + return uiElement.IsEnabled && uiElement.IsVisible && uiElement.IsHitTestVisible; + } + + ContentElement contentElement = obj as ContentElement; + if (contentElement != null) + { + return contentElement.IsEnabled; + } + + UIElement3D uiElement3D = obj as UIElement3D; + if (uiElement3D != null) + { + return uiElement3D.IsEnabled && uiElement3D.IsHitTestVisible && uiElement3D.IsVisible; + } + + return false; + } + + /// + /// Returns random element satisfying the given predicate. + /// + /// + /// + /// + public static DependencyObject GetRandomElement(IEnumerable enumerable, Predicate predicate) + { + // get count + int count = 0; + foreach (object obj in enumerable) + { + if (predicate == null || predicate(obj)) + { + count++; + } + } + + if (count == 0) + { + // no elements satisfying the given criteria + return null; + } + + // get random int + int random = RandomGenerator.GetInt(count); + + // pick the element + int i = 0; + foreach (DependencyObject obj in enumerable) + { + if (predicate == null || predicate(obj)) + { + if (i == random) + { + return obj; + } + i++; + } + } + + Utils.Assert(false); + return null; + } + + /// + /// Modifies visual tree randomly + /// + /// + /// + public static void ModifyVisualTree(Panel panel, VisualTreeOptions options) + { + if (panel == null) + { + throw new ArgumentNullException("panel"); + } + + if (options == null) + { + throw new ArgumentNullException("options"); + } + + if (options.RemoveCount > 0) + { + // delete some existing elements + for (int i = 0; i < options.RemoveCount; i++) + { + UIElement element = (UIElement)GetRandomElement(panel.Children, + delegate(object obj) + { + return obj is UIElement && IsHitTestable(obj); + }); + + if (element == null) + { + // not enough elements + break; + } + + panel.Children.Remove(element); + } + } + + // modify position of existing elements + if (options.ModifyPositionCount > 0) + { + for (int i = 0; i < options.ModifyPositionCount; i++) + { + UIElement element = (UIElement)GetRandomElement(panel.Children, + delegate(object obj) + { + return obj is UIElement && IsHitTestable(obj); + }); + + if (element == null) + { + // not enough elements + break; + } + + panel.Children.Add(element); + + // + } + } + + // modify properties of exiting elements + if (options.ModifyPropertiesCount > 0) + { + for (int i = 0; i < options.ModifyPropertiesCount; i++) + { + UIElement element = (UIElement)GetRandomElement(panel.Children, + delegate(object obj) + { + return obj is UIElement && IsHitTestable(obj); + }); + + if (element == null) + { + // not enough elements + break; + } + + SetHitTestRelatedFlags(element, options); + } + } + + // + + // transform + if (options.RandomPanelTransform) + { + panel.RenderTransform = RandomGenerator.GetTransform(RandomGenerator.TransformOptions.LightTransform); + } + } + + /// + /// enumerates through the visual and/or logical trees. + /// + /// An object to start enumeration. + /// Indicates whether parent chain needs to be enumerated. + /// Indicates whether children should be included in the enumeration. + /// Indicates enumeration through the visual tree. + /// Indicates enumeration through the logical tree. + /// + public static IEnumerable EnumerateTree(DependencyObject obj, + bool includeParents, bool includeChildren, + bool visualTree, bool logicalTree) + { + // check parameters + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + yield return obj; + + if (includeParents || includeChildren) + { + Dictionary processed = new Dictionary(); + processed[obj] = true; + + if (includeParents) + { + // go recursively through all the parents + foreach (DependencyObject parent in EnumerateRecursivelyUp(obj, visualTree, logicalTree, processed, true/*skipRootCheck*/)) + { + yield return parent; + } + } + + if (includeChildren) + { + // go recursively through all the children + foreach (DependencyObject child in EnumerateRecursivelyDown(obj, visualTree, logicalTree, processed, true/*skipRootCheck*/)) + { + yield return child; + } + } + } + } + + /// + /// get a random element under the give element + /// + /// + /// + public static IInputElement GetRandomHitTestableElement(DependencyObject element) + { + return (IInputElement)GetRandomElement(EnumerateTree(element, false/*include parent*/, true/*include children*/, + true/*visual tree*/, true/*logical tree*/), IsHitTestable); + } + + /// + /// get a list of values exptected + /// + /// + /// + /// + public static Dictionary ReadAllValues(GetPropertyValue getValue, UIElement element) + { + // enumerate all child elements + Dictionary values = new Dictionary(); + + foreach (DependencyObject obj in + EnumerateTree(element, false/*include parent*/, true/*include children*/, true/*visual tree*/, true/*logicalTree*/)) + { + values.Add(obj, getValue(obj)); + } + + return values; + } + + /// + /// enumerates through parents + /// + /// + /// + /// + /// + /// + private static IEnumerable EnumerateRecursivelyUp( + DependencyObject obj, bool visualTree, bool logicalTree, + Dictionary processed, bool skipRootCheck) + { + Utils.Assert(obj != null, "EnumerateRecursivelyUp - the param obj should not be null"); + Utils.Assert(processed != null, "EnumerateRecursivelyUp - the param processed should not be null"); + + if (!skipRootCheck) + { + if (processed.ContainsKey(obj)) + { + // the object has been already processed + yield break; + } + + else + { + // the object requires processing + processed[obj] = true; + yield return obj; + } + } + + // visual tree + DependencyObject visualParent = null; + if (visualTree) + { + visualParent = obj is Visual ? VisualTreeHelper.GetParent(obj) : null; + if (visualParent != null) + { + foreach (DependencyObject parent in + EnumerateRecursivelyUp(visualParent, visualTree, logicalTree, processed, false/*skipRootCheck*/)) + { + yield return parent; + } + } + } + + if (logicalTree) + { + DependencyObject logicalParent = LogicalTreeHelper.GetParent(obj); + if (logicalParent != null && logicalParent != visualParent) // do nothing if logicalParent is the same as coreParent + { + foreach (DependencyObject parent in + EnumerateRecursivelyUp(logicalParent, visualTree, logicalTree, processed, false/*skipRootCheck*/)) + { + yield return parent; + } + } + } + } + + /// + /// enumerates through children + /// + /// + /// + /// + /// + /// + /// + private static IEnumerable EnumerateRecursivelyDown( + DependencyObject obj, bool visualTree, bool logicalTree, + Dictionary processed, bool skipRootCheck) + { + Utils.Assert(obj != null, "EnumerateRecursivelyDown - the param obj should not be null"); + Utils.Assert(processed != null, "EnumerateRecursivelyDown - the param processed should not be null"); + + if (!skipRootCheck) + { + if (processed.ContainsKey(obj)) + { + // the object has been already processed + yield break; + } + + else + { + // the object requires processing + processed[obj] = true; + yield return obj; + } + } + + // visual children + if (visualTree) + { + int coreChildrenCount = obj is Visual ? VisualTreeHelper.GetChildrenCount(obj) : 0; + for (int i = 0; i < coreChildrenCount; i++) + { + DependencyObject visualChild = VisualTreeHelper.GetChild(obj, i); + if (visualChild != null) + { + foreach (DependencyObject child in + EnumerateRecursivelyDown(visualChild, visualTree, logicalTree, processed, false/*skipRootCheck*/)) + { + yield return child; + } + } + } + } + + // logical children + if (logicalTree) + { + foreach (object logicalChildObject in LogicalTreeHelper.GetChildren(obj)) + { + DependencyObject logicalChild = logicalChildObject as DependencyObject; + if (logicalChild != null) + { + foreach (DependencyObject child in + EnumerateRecursivelyDown(logicalChild, visualTree, logicalTree, processed, false/*skipRootCheck*/)) + { + yield return child; + } + } + } + } + } + + /// + /// set related visual tree change options + /// + /// + /// + public static void SetHitTestRelatedFlags(UIElement element, VisualTreeOptions options) + { + if (options.GetIsVisible != null) + { + element.Visibility = options.GetIsVisible(); + } + if (options.GetIsEnabled != null) + { + element.IsEnabled = options.GetIsEnabled(); + } + if (options.GetIsHitTestVisible != null) + { + element.IsHitTestVisible = options.GetIsHitTestVisible(); + } + } + + #endregion + + #region General Event handlers helpers + + /// + /// Adds an event handler + /// + /// + /// + /// + /// add event handler to all parents + /// add event handler to all children + public static void AddHandler(DependencyObject obj, RoutedEvent routedEvent, Delegate handler, + bool addToParents, bool addToChildren) + { + // check parameters + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + if (routedEvent == null) + { + throw new ArgumentNullException("routedEvent"); + } + if (handler == null) + { + throw new ArgumentNullException("handler"); + } + + AddRemoveHandler(obj, addToParents, addToChildren, + delegate(DependencyObject curObj) + { + AddHandler(curObj, routedEvent, handler); + }); + } + + /// + /// Removes an event handler + /// + /// + /// + /// + /// add event handler to all parents + /// add event handler to all children + public static void RemoveHandler(DependencyObject obj, RoutedEvent routedEvent, Delegate handler, + bool removeFromParents, bool removeFromChildren) + { + // check parameters + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + if (routedEvent == null) + { + throw new ArgumentNullException("routedEvent"); + } + if (handler == null) + { + throw new ArgumentNullException("handler"); + } + + AddRemoveHandler(obj, removeFromParents, removeFromChildren, + delegate(DependencyObject curObj) + { + RemoveHandler(curObj, routedEvent, handler); + }); + } + + + public delegate void AddRemoveHandlerDelegate(DependencyObject obj); + + public static void AddRemoveHandler(DependencyObject obj, + bool addToParents, bool addToChildren, AddRemoveHandlerDelegate addRemoveHandler) + { + Debug.Assert(obj != null); + Debug.Assert(addRemoveHandler != null); + + // + + foreach (DependencyObject cur in EnumerateTree(obj, addToParents, addToChildren, + false/*visual tree*/, true/*logical tree*/)) + { + if (cur is IInputElement) + { + addRemoveHandler(cur); + } + } + } + + /// + /// Adds a specified event handler for a specified attached event. + /// + /// + /// + /// + public static void AddHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler) + { + // make sure that parameter name 'element' matches the parameter name of the public caller + // + + Debug.Assert(routedEvent != null, "In AddHandler - RoutedEvent must not be null"); + + UIElement uiElement = element as UIElement; + if (uiElement != null) + { + // this is an UIElement + uiElement.AddHandler(routedEvent, handler); + } + else + { + ContentElement contentElement = element as ContentElement; + if (contentElement != null) + { + // this is a ContentElement + contentElement.AddHandler(routedEvent, handler); + } + else + { + UIElement3D uiElement3D = element as UIElement3D; + if (uiElement3D != null) + { + // this is a UIElement3D + uiElement3D.AddHandler(routedEvent, handler); + } + else + { + // + } + } + } + } + + /// + /// Removes a handler for the given attached event + /// + public static void RemoveHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler) + { + // make sure that parameter name 'element' matches the parameter name of the public caller + // + + Debug.Assert(routedEvent != null, "In RemoveHandler - RoutedEvent must not be null"); + + UIElement uiElement = element as UIElement; + if (uiElement != null) + { + // This is an UIElement + uiElement.RemoveHandler(routedEvent, handler); + } + else + { + ContentElement contentElement = element as ContentElement; + if (contentElement != null) + { + // This is an ContentElement + contentElement.RemoveHandler(routedEvent, handler); + } + else + { + UIElement3D uiElement3D = element as UIElement3D; + if (uiElement3D != null) + { + // this is a ContentElement + uiElement3D.AddHandler(routedEvent, handler); + } + else + { + // + } + } + } + } + + #endregion + + #region Validation Helpers - TODO: refactoring to outside the verifier + + /// + /// compare property values + /// + /// + /// + /// + /// + /// + public static bool ComparePropertyValues(int frameNumber, + Dictionary expectedValues, + Dictionary actualValues, + Predicate logFilter) + { + Debug.WriteLine(""); + Debug.WriteLine("COMPARE FRAME: " + frameNumber); + + bool ok = true; + + Debug.WriteLine(" number of elements, actual=" + actualValues.Count + " expected=" + expectedValues.Count); + if (expectedValues.Count != actualValues.Count) + { + Debug.WriteLine("FAILURE: Invalid number of elements"); + ok = false; + } + + int i = 0; + foreach (KeyValuePair pair in expectedValues) + { + object expectedValue = pair.Value; + object actualValue; + bool equal; + + if (!actualValues.TryGetValue(pair.Key, out actualValue)) + { + equal = false; + actualValue = ""; + } + else + { + equal = object.Equals(expectedValue, actualValue); + } + + if (!equal || logFilter(actualValue)) + { + Debug.WriteLine((equal ? " " : "**") + (i++).ToString() + ": " + pair.Key + "[" + pair.Key.GetHashCode() + "]" + + " actual=" + actualValue + " expected=" + expectedValue + + (equal ? "" : " - FAILURE")); + } + + if (!equal) + { + ok = false; + } + } + + return ok; + } + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/MultipleContactsGesture.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/MultipleContactsGesture.cs new file mode 100644 index 000000000..ab3d70a21 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/MultipleContactsGesture.cs @@ -0,0 +1,148 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// The base class for all multiple points gestures + /// + public class MultipleContactsGesture + { + #region Private Fields + + private List _singleGestureList; + private bool _runSequentially = false; + + #endregion + + #region Constructor + + public MultipleContactsGesture() + { + _singleGestureList = new List(); + } + + #endregion + + #region Public Properties + + public bool RunSequentially + { + get { return _runSequentially; } + set { _runSequentially = value; } + } + + public int GestureCount + { + get { return _singleGestureList.Count; } + } + + public List GestureList + { + get { return _singleGestureList; } + } + + /// + /// Duration and Samples properties are for scenarios where all SinglePointGestures in the list are using same Duration and Samples + /// + public virtual int Duration + { + get + { + int duration = _singleGestureList[0].Duration; + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + if (duration != singlegesture.Duration) + { + throw new NotImplementedException("SingleGestures in the list are not using the same Duration. Please use the GestureList get the Duration for specified SinglePointGesture"); + } + } + return duration; + } + set + { + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + if (value / singlegesture.Samples < SingleContactGesture.INTERVALMIN) + { + throw new ArgumentOutOfRangeException("Interval(Duration/Samples) must be bigger than INTERVALMIN = " + SingleContactGesture.INTERVALMIN.ToString()); + } + } + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + singlegesture.Duration = value; + } + } + } + + /// + /// Duration and Samples properties are for scenarios where all SinglePointGestures in the list are using same Duration and Samples + /// + public virtual int Samples + { + get + { + int samples = _singleGestureList[0].Samples; + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + if (samples != singlegesture.Samples) + { + throw new NotImplementedException("SingleGestures in the list are not using the same Samples. Please use GestureList to get the Samples for specified SinglePointGesture"); + } + } + return samples; + } + set + { + if (value < 1) + { + throw new ArgumentOutOfRangeException("Samples must be a least 1"); + } + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + singlegesture.Samples = value; + } + } + } + + public virtual int ContactsInterval + { + get + { + int interval = _singleGestureList[0].ContactsInterval; + foreach (SingleContactGesture singlegesture in _singleGestureList) + { + if (interval != singlegesture.ContactsInterval) + { + throw new NotImplementedException("SingleGestures in the list are not using the same interval. Please use GestureList to get the ContactsInterval for specified SinglePointGesture"); + } + } + return interval; + } + } + + #endregion + + #region Public Methods + + public void AddCommand(SingleContactGesture singleGesture) + { + _singleGestureList.Add(singleGesture); + } + + public void AddCommand(MultipleContactsGesture multiGesture) + { + if (multiGesture.GestureCount > 0) + { + _singleGestureList.AddRange(multiGesture.GestureList.ToArray()); + } + } + + #endregion + + } + } diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/Part1CommonData.csproj b/src/Test/ElementServices/FeatureTests/Part1/Common/Part1CommonData.csproj new file mode 100644 index 000000000..e5f345a5f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/Part1CommonData.csproj @@ -0,0 +1,16 @@ + + + + true + + + + + StiConfig\%(FileName)%(Extension) + Always + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/PointR.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/PointR.cs new file mode 100644 index 000000000..e2396957d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/PointR.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Drawing; + +namespace Microsoft.Test.Input.MultiTouch +{ + public struct PointR + { + public static readonly PointR Empty; + + public double X, Y; + public int T; + public int ID; + + public PointR(double x, double y) + : this(x, y, 0, -1) + { + } + + public PointR(double x, double y, int t, int id) + { + X = x; + Y = y; + T = t; + ID = id; + } + + /// + /// copy constructor + /// + /// + public PointR(PointR p) + { + X = p.X; + Y = p.Y; + T = p.T; + ID = p.ID; + } + + public static explicit operator PointF(PointR p) + { + return new PointF((float)p.X, (float)p.Y); + } + + public static bool operator ==(PointR p1, PointR p2) + { + return (p1.X == p2.X && p1.Y == p2.Y); + } + + public static bool operator !=(PointR p1, PointR p2) + { + return (p1.X != p2.X || p1.Y != p2.Y); + } + + public override bool Equals(object obj) + { + if (obj is PointR) + { + PointR p = (PointR)obj; + return (X == p.X && Y == p.Y); + } + + return false; + } + + public override int GetHashCode() + { + return ((PointF)this).GetHashCode(); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/PointUtil.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/PointUtil.cs new file mode 100644 index 000000000..4a90ea484 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/PointUtil.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using System.Windows.Media; +using System.Security; +using System.Runtime.InteropServices; +using System.Reflection; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// This is to reduce the dependency on the old CoreUI code + /// + + + + + public static class PointUtil + { + private static Type GetPointUtilType() + { + Type tsw = typeof(UIElement); + Assembly assembly = tsw.Assembly; + + Type type = assembly.GetType("MS.Internal.PointUtil"); + + return type; + } + + private static Point InvokeStaticMethod(Type type, string name, object[] args) + { + return (Point)type.InvokeMember(name, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Static, + null, + null, + args, + System.Globalization.CultureInfo.InvariantCulture); + } + + + /// + /// Convert a point from "client" coordinate space of a window into + /// the coordinate space of the root element of the same window. + /// + public static Point ClientToRoot(Point pt, PresentationSource presentationSource) + { + object[] args = {pt, presentationSource}; + + return InvokeStaticMethod(GetPointUtilType(),"ClientToRoot", args); + } + + /// + /// Convert a point from the coordinate space of a root element of + /// a window into the "client" coordinate space of the same window. + /// + public static Point RootToClient(Point pt, PresentationSource presentationSource) + { + object[] args = {pt, presentationSource}; + + return InvokeStaticMethod(GetPointUtilType(),"RootToClient", args); + + } + + /// + /// Convert a point from "above" the coordinate space of a + /// visual into the the coordinate space "below" the visual. + /// + public static Point ApplyVisualTransform(Point pt, Visual v, bool inverse) + { + + object[] args = {pt, v, inverse}; + + return InvokeStaticMethod(GetPointUtilType(),"ApplyVisualTransform", args); + } + + /// + /// Convert a point from "client" coordinate space of a window into + /// the coordinate space of the screen. + /// + public static Point ClientToScreen(Point ptClient, PresentationSource presentationSource) + { + + object[] args = {ptClient, presentationSource}; + + return InvokeStaticMethod(GetPointUtilType(),"ClientToScreen", args); + } + + /// + /// Convert a point from the coordinate space of the screen into + /// the "client" coordinate space of a window. + /// + public static Point ScreenToClient(Point ptScreen, PresentationSource presentationSource) + { + object[] args = {ptScreen, presentationSource}; + + return InvokeStaticMethod(GetPointUtilType(),"ScreenToClient", args); + } + + /// + /// Gets the matrix that will convert a point from "above" the coordinate space of a visual + /// into the the coordinate space "below" the visual + /// + internal static Matrix GetVisualTransform(Visual v) + { + Matrix m = Matrix.Identity; + + if (v != null) + { + Transform transform = VisualTreeHelper.GetTransform(v); + if (transform != null) + { + Matrix cm = transform.Value; + m = Matrix.Multiply(m, cm); + } + + Vector offset = VisualTreeHelper.GetOffset(v); + m.Translate(offset.X, offset.Y); + } + + return m; + } + + /// + /// Converts a rectangle from element co-ordinate space to that of the root visual + /// + /// The rectangle to be converted + /// The element whose co-ordinate space you wish to convert from + /// The PresentationSource which hosts the specified Visual. This is passed in for performance reasons. + /// The rectangle in the co-ordinate space of the root visual + public static Rect ElementToRoot(Rect rectElement, Visual element, PresentationSource presentationSource) + { + GeneralTransform transformElementToRoot = element.TransformToAncestor(presentationSource.RootVisual); + Rect rectRoot = transformElementToRoot.TransformBounds(rectElement); + + return rectRoot; + } + + /// + /// Converts a rectangle from root visual co-ordinate space to Win32 client + /// + /// + /// RootToClient takes into account device DPI settings to convert to/from WPF's assumed 96dpi + /// and any "root level" transforms applied to the root such as "right-to-left" inversions. + /// + /// + /// The rectangle to be converted + /// + /// + /// The PresentationSource which hosts the root visual. This is passed in for performance reasons. + /// + /// + /// The rectangle in Win32 client co-ordinate space + /// + public static Rect RootToClient(Rect rectRoot, PresentationSource presentationSource) + { + CompositionTarget target = presentationSource.CompositionTarget; + Matrix matrixRootTransform = PointUtil.GetVisualTransform(target.RootVisual); + Rect rectRootUntransformed = Rect.Transform(rectRoot, matrixRootTransform); + Matrix matrixDPI = target.TransformToDevice; + Rect rectClient = Rect.Transform(rectRootUntransformed, matrixDPI); + + return rectClient; + } + + } +} + diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/Property.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/Property.cs new file mode 100644 index 000000000..8aecbc016 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/Property.cs @@ -0,0 +1,242 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + #region public abstract class Property + + /// + /// Base class for testing getters/setters + /// + public abstract class Property + { + #region private fields + + private readonly string _name; + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// + public Property(string name) + { + Utils.Assert(name != null, "The parameter name should not be null"); + this._name = name; + } + + #endregion + + #region Properties + + /// + /// the name of the property + /// + public string Name + { + get { return this._name; } + } + + #endregion + + #region Methods + + /// + /// Checks that the properties enforce valid and invalid values + /// + /// + public static void CheckValues(IEnumerable properties) + { + Utils.Assert(properties != null, "The parameter 'properties' should not be null in CheckValues"); + + foreach (Property property in properties) + { + property.CheckValues(); + } + } + + /// + /// Checks that the properties have the expected default value + /// + /// + public static void CheckDefault(IEnumerable properties) + { + Utils.Assert(properties != null, "The parameter properties should not be null in CheckDefault"); + + foreach (Property property in properties) + { + property.CheckDefault(); + } + } + + /// + /// Checks that you get what you set + /// + /// + public static void CheckSetGet(IEnumerable properties) + { + Utils.Assert(properties != null, "The parameter properties should not be null in CheckSetGet"); + + foreach (Property property in properties) + { + property.CheckSetGet(); + } + } + + /// + /// Checks that the property enforces valie and invalid values + /// + public abstract void CheckValues(); + + /// + /// Checks that the property has the expected default value + /// + public abstract void CheckDefault(); + + /// + /// Checks that you get what you set + /// + public abstract void CheckSetGet(); + + #endregion + } + + #endregion + + #region public abstract class Property<> + + /// + /// class for testing the behavior of a get/set property + /// + /// the type of the object that has the property on it. + /// the return type of the property. + public abstract class Property : Property + { + #region Private Fields + + private readonly System.Func> _values; + private readonly System.Func _constructor; + private readonly System.Func _getter; + private readonly System.Action _setter; + + #endregion + + #region Constructor + + /// + /// Constructor. + /// + /// The name of the property. + /// A function for enumerating valid and invalid values. + /// A function for constructing the owning type. + /// A function to get the property value. + /// An action that sets the property value. + public Property( + string name, + System.Func> values, + System.Func constructor, + System.Func getter, + System.Action setter) + : base(name) + { + Utils.Assert(values != null, "The parameter values should not be null"); + Utils.Assert(constructor != null, "The parameter constructor should not be null"); + Utils.Assert(getter != null, "The parameter getter should not be null"); + Utils.Assert(setter != null, "The parameter setter should not be null"); + + this._values = values; + this._constructor = constructor; + this._getter = getter; + this._setter = setter; + } + + #endregion + + #region Properties + + /// + /// Gets the constructor function for the owning type. + /// + public System.Func Constructor + { + get { return this._constructor; } + } + + /// + /// Gets the function for getting a property value from the owning type. + /// + public System.Func Getter + { + get { return this._getter; } + } + + #endregion + + #region Methods + + /// + /// Checks that the property enforces valid and invalid values + /// + public override void CheckValues() + { + TOwningType owner = _constructor(); + + ValueTests.Try( + (value) => this._setter(owner, value), + this._values, + Name); + } + + /// + /// Checks that if you set the value and then get it, you get + /// the value that you put in. + /// + public override void CheckSetGet() + { + TOwningType owner = Constructor(); + + foreach (TPropertyType value in this._values(true)) + { + this._setter(owner, value); + TPropertyType result = this._getter(owner); + Utils.Assert(CompareValues(result, value), + string.Format("Property {0} returned different {1} after being set to {2}",Name,result,value)); + } + } + + /// + /// Picks a valid value and sets it + /// + public void SetValidValue(TOwningType owner) + { + IEnumerator enumerator = this._values(true).GetEnumerator(); + enumerator.MoveNext(); + this._setter(owner, enumerator.Current); + } + + /// + /// Compares two property values. + /// + /// + /// + /// + protected virtual bool CompareValues(TPropertyType value1, TPropertyType value2) + { + return value1.Equals(value2); + } + + #endregion + } + + #endregion + +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/RandomGenerator.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/RandomGenerator.cs new file mode 100644 index 000000000..455c42527 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/RandomGenerator.cs @@ -0,0 +1,422 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; +using System.Diagnostics; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Random values generator + /// + public static class RandomGenerator + { + #region Fields + + private static Random s_random; + private static int? s_seed; + + #endregion + + #region Seed and Random Properties + + /// + /// Gets/Sets the seed for the random generator + /// + public static int Seed + { + get + { + if (RandomGenerator.s_seed == null) + { + RandomGenerator.s_seed = Environment.TickCount; + } + return (int)RandomGenerator.s_seed; + } + set + { + RandomGenerator.s_seed = value; + RandomGenerator.s_random = new Random(value); + } + } + + private static Random Random + { + get + { + if (RandomGenerator.s_random == null) + { + RandomGenerator.s_random = new Random(Seed); + } + return RandomGenerator.s_random; + } + } + + #endregion + + #region Doubles + + /// + /// Returns a random double between 0 and max + /// + /// + /// + public static double GetDouble(double max) + { + return GetDouble(0, max); + } + + /// + /// Returns a random double between min and max + /// + /// + /// + /// + public static double GetDouble(double min, double max) + { + return Random.NextDouble() * (max - min) + min; + } + + #endregion + + #region Int + + /// + /// Returns a random int between 0 and max + /// + /// + /// + public static int GetInt(int max) + { + return Random.Next(max); + } + + /// + /// Returns a random int between min and max + /// + /// + /// + /// + public static int GetInt(int min, int max) + { + return Random.Next(min, max); + } + + #endregion + + #region Bool + + /// + /// Returns a random bool. + /// + /// + public static bool GetBoolean() + { + return Random.Next(2) == 0 ? false : true; + } + + #endregion + + #region Enum + + /// + /// Returns a random enum from the valid enum values + /// + /// + /// + public static T GetEnum() + { + Array values = Enum.GetValues(typeof(T)); + return (T)values.GetValue(RandomGenerator.GetInt(values.Length)); + } + + #endregion + + #region String + + /// + /// Generates a random string based on the given template and expected result length + /// + /// + /// + /// + public static string GetString(string template, int length) + { + if (string.IsNullOrEmpty(template)) + { + if (length == 0) + { + return template; + } + else + { + return new string('?', length); + } + } + + if (length <= template.Length) + { + return template.Substring(length); + } + + StringBuilder builder = new StringBuilder(length); + while (true) + { + int required = length - builder.Length; + if (required <= template.Length) + { + builder.Append(template.Substring(required)); + break; + } + + builder.Append(template); + } + return builder.ToString(); + } + + #endregion + + #region Transformation + + /// + /// Type of the transformation + /// + [Flags] + public enum TransformKind + { + /// + /// No transformation + /// + None = 0, + + /// + /// Apply Rotate transform + /// + Rotate = 1, + + /// + /// Apply Scale transform + /// + Scale = 2, + + /// + /// Apply Skew transform + /// + Skew = 4, + + /// + /// Apply Translate transform + /// + Translate = 8, + + /// + /// Apply all transformations + /// + All = Rotate | Scale | Skew | Translate, + } + + /// + /// Transformation options + /// + public class TransformOptions + { + /// + /// Transformation type + /// + public TransformKind TransformKind = TransformKind.None; + + /// + /// Minimum rotation + /// + public double MinRotation = 0; + + /// + /// Maximum rotation + /// + public double MaxRotation = 0; + + /// + /// Minimum scale along X + /// + public double MinScaleX = 1; + + /// + /// Maximum scale along X + /// + public double MaxScaleX = 1; + + /// + /// Minimum scale along Y + /// + public double MinScaleY = 1; + + /// + /// Maximum scale along X + /// + public double MaxScaleY = 1; + + /// + /// Minimum skew along X + /// + public double MinSkewX = 0; + + /// + /// Maximum skew along X + /// + public double MaxSkewX = 0; + + /// + /// Minimum skew along Y + /// + public double MinSkewY = 0; + + /// + /// Maximum skew along X + /// + public double MaxSkewY = 0; + + /// + /// Minimum offset along X + /// + public double MinOffsetX = 0; + + /// + /// Maximum offset along X + /// + public double MaxOffsetX = 0; + + /// + /// Minimum offset along Y + /// + public double MinOffsetY = 0; + + /// + /// Maximum offset along Y + /// + public double MaxOffsetY = 0; + + /// + /// Heavy tranformation + /// + public static readonly TransformOptions HeavyTransform; + + /// + /// Light tranformation + /// + public static readonly TransformOptions LightTransform; + + static TransformOptions() + { + HeavyTransform = new TransformOptions(); + HeavyTransform.TransformKind = TransformKind.All; + HeavyTransform.MinRotation = 0; + HeavyTransform.MaxRotation = 360; + HeavyTransform.MinScaleX = 0.3; + HeavyTransform.MaxScaleX = 3; + HeavyTransform.MinScaleY = 0.3; + HeavyTransform.MaxScaleY = 3; + HeavyTransform.MinSkewX = 0; + HeavyTransform.MaxSkewX = 45; + HeavyTransform.MinSkewY = 0; + HeavyTransform.MaxSkewY = 45; + HeavyTransform.MinOffsetX = -50; + HeavyTransform.MaxOffsetX = 50; + HeavyTransform.MinOffsetY = -50; + HeavyTransform.MaxOffsetY = 50; + + LightTransform = new TransformOptions(); + LightTransform.TransformKind = TransformKind.All; + LightTransform.MinRotation = -25; + LightTransform.MaxRotation = 25; + LightTransform.MinScaleX = 0.9; + LightTransform.MaxScaleX = 1.1; + LightTransform.MinScaleY = 0.9; + LightTransform.MaxScaleY = 1.1; + LightTransform.MinSkewX = -5; + LightTransform.MaxSkewX = 5; + LightTransform.MinSkewY = -5; + LightTransform.MaxSkewY = 5; + LightTransform.MinOffsetX = -5; + LightTransform.MaxOffsetX = 5; + LightTransform.MinOffsetY = -5; + LightTransform.MaxOffsetY = 5; + } + + } + + /// + /// Returns a random transformation based on the given options. + /// + /// + /// + public static Transform GetTransform(TransformOptions options) + { + Matrix total = new Matrix(); + + if ((options.TransformKind & TransformKind.Rotate) != 0) + { + RotateTransform rotate = new RotateTransform(RandomGenerator.GetDouble(options.MinRotation, options.MaxRotation)); + total.Append(rotate.Value); + } + + if ((options.TransformKind & TransformKind.Scale) != 0) + { + ScaleTransform scale = new ScaleTransform(RandomGenerator.GetDouble(options.MinScaleX, options.MaxScaleX), + RandomGenerator.GetDouble(options.MinScaleY, options.MaxScaleY)); + total.Append(scale.Value); + } + + if ((options.TransformKind & TransformKind.Skew) != 0) + { + SkewTransform skew = new SkewTransform(RandomGenerator.GetDouble(options.MinSkewX, options.MaxSkewX), + RandomGenerator.GetDouble(options.MinSkewY, options.MaxSkewY)); + total.Append(skew.Value); + } + + if ((options.TransformKind & TransformKind.Translate) != 0) + { + TranslateTransform translate = new TranslateTransform(RandomGenerator.GetDouble(options.MinOffsetX, options.MaxOffsetX), + RandomGenerator.GetDouble(options.MinOffsetY, options.MaxOffsetY)); + total.Append(translate.Value); + } + + return new MatrixTransform(total); + } + + #endregion + + #region Point + + /// + /// Returns a random point with int coordinates between the given two. + /// + /// + /// + /// + public static Point GetIntPoint(Point topLeft, Point bottomRight) + { + return new Point(GetInt((int)topLeft.X, (int)bottomRight.X), + GetInt((int)topLeft.Y, (int)bottomRight.Y)); + } + + + /// + /// Returns a random point between the given two. + /// + /// + /// + /// + public static Point GetPoint(Point topLeft, Point bottomRight) + { + return new Point(GetDouble(topLeft.X, bottomRight.X), + GetDouble(topLeft.Y, bottomRight.Y)); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/RawInputDeviceType.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/RawInputDeviceType.cs new file mode 100644 index 000000000..9335b1eb3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/RawInputDeviceType.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Test.Input.MultiTouch +{ + [Flags] + public enum RawInputDeviceType + { + MOUSE = 0, + KEYBOARD = 1, + HID = 2 + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/RectangleR.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/RectangleR.cs new file mode 100644 index 000000000..b3b998c00 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/RectangleR.cs @@ -0,0 +1,174 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Drawing; + +namespace Microsoft.Test.Input.MultiTouch +{ + public struct RectangleR + { + #region Fields + + private const int Digits = 4; + + private double _x; + private double _y; + private double _width; + private double _height; + + public static readonly RectangleR Empty = new RectangleR(); + + #endregion + + #region Constructor + + public RectangleR(double xVal, double yVal, double widthVal, double heightVal) + { + _x = xVal; + _y = yVal; + _width = widthVal; + _height = heightVal; + } + + /// + /// copy constructor + /// + /// + public RectangleR(RectangleR r) + { + _x = r.X; + _y = r.Y; + _width = r.Width; + _height = r.Height; + } + + #endregion + + #region Properties + + public double X + { + get + { + return Math.Round(_x, Digits); + } + set + { + _x = value; + } + } + + public double Y + { + get + { + return Math.Round(_y, Digits); + } + set + { + _y = value; + } + } + + public double Width + { + get + { + return Math.Round(_width, Digits); + } + set + { + _width = value; + } + } + + public double Height + { + get + { + return Math.Round(_height, Digits); + } + set + { + _height = value; + } + } + + public PointR TopLeft + { + get + { + return new PointR(X, Y); + } + } + + public PointR BottomRight + { + get + { + return new PointR(X + Width, Y + Height); + } + } + + public PointR Center + { + get + { + return new PointR(X + Width / 2d, Y + Height / 2d); + } + } + + public double MaxSide + { + get + { + return Math.Max(_width, _height); + } + } + + public double MinSide + { + get + { + return Math.Min(_width, _height); + } + } + + public double Diagonal + { + get + { + return Utils.Distance(TopLeft, BottomRight); + } + } + + #endregion + + #region Operators + + public static explicit operator RectangleF(RectangleR r) + { + return new RectangleF((float)r.X, (float)r.Y, (float)r.Width, (float)r.Height); + } + + public override bool Equals(object obj) + { + if (obj is RectangleR) + { + RectangleR r = (RectangleR)obj; + return (X == r.X && Y == r.Y && Width == r.Width && Height == r.Height); + } + + return false; + } + + public override int GetHashCode() + { + return ((RectangleF)this).GetHashCode(); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ReferenceTypePropertyTest.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ReferenceTypePropertyTest.cs new file mode 100644 index 000000000..fc515ed68 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ReferenceTypePropertyTest.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Utility class for testing the behavior of a get/set property + /// that's a reference type. + /// + /// The type of the object that has the property on it. + /// The return type of the property. Must be a reference type. + public class ReferenceTypeProperty : Property + where TPropertyType : class, new() + { + #region Private fields + + private readonly bool _isDefaultValueNull; + + #endregion + + #region Constructor + + /// + /// Constructor. + /// + /// The name of the property. + /// Whether the default value of the property is null. + /// A function for enumerating valid and invalid values. + /// A function for constructing the owning type. + /// A function to get the property value. + /// An action that sets the property value. + public ReferenceTypeProperty( + string name, + bool isDefaultValueNull, + System.Func> values, + System.Func constructor, + System.Func getter, + System.Action setter) + : base(name, values, constructor, getter, setter) + { + this._isDefaultValueNull = isDefaultValueNull; + } + + #endregion + + #region Methods + + /// + /// Checks that the property has the expected default value. + /// + public override void CheckDefault() + { + TPropertyType ownerValue = Getter(Constructor()); + if (this._isDefaultValueNull) + { + Utils.AssertEqual( + ownerValue == null, + "Property {0} has a non-null default value. Expected null.", + Name); + } + else + { + Utils.AssertEqual( + ownerValue != null, + "Property {0} has a null default value. Expected non-null.", + Name); + } + } + + /// + /// Checks two values to see whether they're the same. + /// + /// + /// + /// + protected override bool CompareValues(TPropertyType value1, TPropertyType value2) + { + return object.ReferenceEquals(value1, value2); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/SendTouchInputFlags.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/SendTouchInputFlags.cs new file mode 100644 index 000000000..adc2762fc --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/SendTouchInputFlags.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Test.Input.MultiTouch +{ + public enum SendTouchInputFlags + { + // + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/SingleContactGesture.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/SingleContactGesture.cs new file mode 100644 index 000000000..25229c2f1 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/SingleContactGesture.cs @@ -0,0 +1,147 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// The base class for all single point gestures + /// + public abstract class SingleContactGesture + { + #region Fields + + internal Point origin; + //internal System.Drawing.Point origin; + internal Point[] interpolated; + //private Timer gestureTimer = null; // + internal int starttime = 0; + internal double orientation = 0.0; + internal int samples = 50; // + internal int duration = 1000; // default duration = 3 secs, suitable for the Win7 input stack + internal int? contactid = null; + internal bool recalcOnSamplesChange = true; + internal const int INTERVALMIN = 1; + + #endregion + + #region Public Properties + + public Point[] Interpolated + { + get { return interpolated; } + set { interpolated = value; } + } + + public Point Location + { + get { return origin; } + set { origin = value; } + } + + public int? ContactId + { + get { return contactid; } + set { contactid = value; } + } + + public bool RecalcOnSamplesChange + { + get { return recalcOnSamplesChange; } + set { recalcOnSamplesChange = value; } + } + + /// + /// gets the points in the animation, defaults is interpolated + /// user can override this properties to get a better points to animation + /// + internal virtual Point[] Points + { + get + { + return interpolated; + } + } + + public int Duration + { + get + { + return duration; + } + set + { + if ((value/samples) < INTERVALMIN) + { + throw new ArgumentOutOfRangeException("interval(duration/samples) must be bigger than INTERVALMIN = " + INTERVALMIN.ToString()); + } + duration = value; + } + } + + public int ContactsInterval + { + get + { + return duration/samples; + } + } + + public int StartTime + { + get { return starttime; } + set { starttime = value; } + } + + public int Samples + { + get + { + return samples; + } + set + { + if (value < 1) + { + throw new ArgumentOutOfRangeException("samples must be a least 1"); + } + samples = value; + + if (true == recalcOnSamplesChange) + { + CalculatePoints(); + } + } + } + + public double Orientation + { + get { return orientation; } + set { orientation = value; } + } + + #endregion + + #region Public and Internal Methods + + /// + /// implment this to provide meaningful points track for the gesture + /// + public abstract void CalculatePoints(); + + internal void Reset() + { + //resume to resend the same gesture + contactid = null; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/SizeR.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/SizeR.cs new file mode 100644 index 000000000..ffc7c7a6f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/SizeR.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Drawing; + +namespace Microsoft.Test.Input.MultiTouch +{ + public struct SizeR + { + #region Fields + + public static readonly SizeR Empty; + + private double _cx; + private double _cy; + + #endregion + + #region Constructor + + public SizeR(double cX, double cY) + { + _cx = cX; + _cy = cY; + } + + /// + /// copy constructor + /// + /// + public SizeR(SizeR sz) + { + _cx = sz.Width; + _cy = sz.Height; + } + + #endregion + + #region Properties + + public double Width + { + get + { + return _cx; + } + set + { + _cx = value; + } + } + + public double Height + { + get + { + return _cy; + } + set + { + _cy = value; + } + } + + #endregion + + #region Operators + + public static explicit operator SizeF(SizeR sz) + { + return new SizeF((float)sz.Width, (float)sz.Height); + } + + public static bool operator ==(SizeR sz1, SizeR sz2) + { + return (sz1.Width == sz2.Width && sz1.Height == sz2.Height); + } + + public static bool operator !=(SizeR sz1, SizeR sz2) + { + return (sz1.Width != sz2.Width || sz1.Height != sz2.Height); + } + + public override bool Equals(object obj) + { + if (obj is SizeR) + { + SizeR sz = (SizeR)obj; + return (Width == sz.Width && Height == sz.Height); + } + + return false; + } + + public override int GetHashCode() + { + return ((SizeR)this).GetHashCode(); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/StaticGestures.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/StaticGestures.cs new file mode 100644 index 000000000..4ef28f1a8 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/StaticGestures.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// For static gestures + /// + public enum StaticGestures + { + None, + Tap, + RightTap, + Drag, + RightDrag, + HoldEnter, + HoldLeave, + HoverEnter, + HoverLeave, + Flick, + TwoFingerTap, + RollOver, + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR20/sti.exe.config b/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR20/sti.exe.config new file mode 100644 index 000000000..fb0db5a14 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR20/sti.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR40/sti.exe.config b/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR40/sti.exe.config new file mode 100644 index 000000000..adba684aa --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/StiConfig/CLR40/sti.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/TouchDeviceAction.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchDeviceAction.cs new file mode 100644 index 000000000..b5f50f3ed --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchDeviceAction.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// action indicates a state of a touch device + /// + public enum TouchDeviceAction + { + /// + /// Add a touch + /// + TouchAdd, + + /// + /// Remove a touch + /// + TouchRemove, + + /// + /// Change a touch + /// + TouchChange, + + /// + /// a Tap gesture + /// + TouchTapGesture, + + /// + /// a Hold gesture + /// + TouchHoldGesture, + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/TouchEventCollector.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchEventCollector.cs new file mode 100644 index 000000000..d57744e6e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchEventCollector.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; +using Microsoft.Test.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Collector of touch events + /// + public class TouchEventCollector : EventCollector + { + #region Fields + + private readonly UIElement _root; + private Dictionary> _collectedEventsPerTouch = new Dictionary>(); + + [Flags] + public enum TouchEventTypes + { + None = 0, + UpDownMove = 1, + EnterLeave = 2, + GotLostCapture = 4, + Gestures = 8, + All = UpDownMove | EnterLeave | GotLostCapture | Gestures, + } + + private static RoutedEvent[] CreateTouchEvents(TouchEventTypes touchEventTypes) + { + List eventList = new List(); + + if ((touchEventTypes & TouchEventTypes.UpDownMove) != 0) + { + eventList.Add(UIElement.PreviewTouchDownEvent); + eventList.Add(UIElement.PreviewTouchMoveEvent); + eventList.Add(UIElement.PreviewTouchUpEvent); + eventList.Add(UIElement.TouchDownEvent); + eventList.Add(UIElement.TouchMoveEvent); + eventList.Add(UIElement.TouchUpEvent); + } + + if ((touchEventTypes & TouchEventTypes.EnterLeave) != 0) + { + eventList.Add(UIElement.TouchEnterEvent); + eventList.Add(UIElement.TouchLeaveEvent); + } + + if ((touchEventTypes & TouchEventTypes.Gestures) != 0) + { + eventList.Add(UIElement.PreviewStylusSystemGestureEvent); + eventList.Add(UIElement.StylusSystemGestureEvent); + } + + if ((touchEventTypes & TouchEventTypes.GotLostCapture) != 0) + { + eventList.Add(UIElement.GotTouchCaptureEvent); + eventList.Add(UIElement.LostTouchCaptureEvent); + } + + return eventList.ToArray(); + } + + #endregion + + #region Constructor + + public TouchEventCollector(UIElement root, bool verifyEnterLeave, bool verifyGestures) + : base(TouchEventCollector.CreateTouchEvents( + TouchEventCollector.TouchEventTypes.UpDownMove | + (verifyEnterLeave ? TouchEventCollector.TouchEventTypes.EnterLeave : 0) | + (verifyGestures ? TouchEventCollector.TouchEventTypes.Gestures : 0))) + { + Debug.Assert(root != null); + this._root = root; + } + + public TouchEventCollector(UIElement root, TouchEventTypes touchEventTypes) + : base(TouchEventCollector.CreateTouchEvents(touchEventTypes)) + { + Debug.Assert(root != null); + this._root = root; + } + + #endregion + + #region Methods + + protected override void Collect(IList list, object sender, RoutedEventArgs args) + { + // add event parameters to the global list + EventParameters parameters = new EventParameters(sender, args, GetPosition(args), args.RoutedEvent); + list.Add(parameters); + + // add event parameter to the per-touch list + List collectedEventsForThisTouch; + int touchId; + if (args is StylusSystemGestureEventArgs) + { + touchId = ((StylusSystemGestureEventArgs)args).StylusDevice.TabletDevice.Id; + } + else + { + touchId = ((TouchEventArgs)args).TouchDevice.Id; + } + + if (!this._collectedEventsPerTouch.TryGetValue(touchId, out collectedEventsForThisTouch)) + { + collectedEventsForThisTouch = new List(); + this._collectedEventsPerTouch.Add(touchId, collectedEventsForThisTouch); + } + + collectedEventsForThisTouch.Add(parameters); + } + + private Point GetPosition(RoutedEventArgs args) + { + if (args is TouchEventArgs) + { + TouchEventArgs touchEventArgs = args as TouchEventArgs; + if (touchEventArgs != null) + { + return touchEventArgs.TouchDevice.GetTouchPoint(this._root).Position; + } + } + + return new Point(); + } + + public override void Clear() + { + base.Clear(); + this._collectedEventsPerTouch.Clear(); + } + + public ReadOnlyCollection CollectedEventsForTouch(int touchId) + { + List collectedEventsForThisTouch; + + if (this._collectedEventsPerTouch.TryGetValue(touchId, out collectedEventsForThisTouch)) + { + return new ReadOnlyCollection(collectedEventsForThisTouch); + } + + return new ReadOnlyCollection(new EventParameters[0]); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/TouchVerifier.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchVerifier.cs new file mode 100644 index 000000000..d1431e2e7 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/TouchVerifier.cs @@ -0,0 +1,248 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using System.Diagnostics; +using System.Collections.ObjectModel; + +namespace Microsoft.Test.Input.MultiTouch +{ + public class TouchData + { + public List snapshots; + public int currentSnapshot; + public int touchId; + public IInputElement capturedBy; + public CaptureMode captureMode; + } + + public delegate object GetPropertyValue(DependencyObject obj); + public delegate object MergePropertyValues(object oldValue, object newValue); + public delegate void AfterFrameSimulated(int frameNumber, Dictionary touchMap); + + /// + /// This is the verifier for Touch features + /// + /// Factors: + /// 1. Capture Mode - Element, SubTree, None + /// 2. Capture Location - Root Window, Element, Child, None + /// 3. Verify Location - Root Window, Parent Chain, Element + /// + /// Verify + /// 1. 4 DPs: + /// {UIElement/ContentElement/UIElement3D}.AreAnyTouchesCaptured + /// {UIElement/ContentElement/UIElement3D}.AreAnyTouchesCapturedWithin + /// {UIElement/ContentElement/UIElement3D}.AreAnyTouchesDirectlyOver + /// {UIElement/ContentElement/UIElement3D}.AreAnyTouchesOver + /// 2. Collection count: + /// {UIElement, UIElement3D, ContentElement}.TouchesCaptured - IEnumerable of TouchDevice + /// {UIElement, UIElement3D, ContentElement }.TouchesCapturedWithin - IEnumerable of TouchDevice + /// 3. Event routing and handledness correctness: + /// a. route to elements with capture and future captures to there + /// b. not route to elements without capture + /// c. The listeners are not called at element locations that follow the location where an event + /// is handled; also the other listeners on the same element location are still called + /// d. The “handledEventsToo†listeners are called at element locations that follow the location where an event is handled + /// + /// Other factors: + /// 1. Events - + /// Preview Down/Move/Up - Tunnel + /// Down/Move/Up - bubble + /// Got/LostCapture - bubble + /// Enter/Leave - direct + /// 2. Properties - IsHitTestVisible, IsEnabled, Visibility + /// 3. Visual tree changes - add / remove elements + /// + /// + public class TouchVerifier : MultiTouchVerifier + { + #region Fields + + public CaptureMode[] captureModes = new CaptureMode[] { CaptureMode.None, CaptureMode.SubTree, CaptureMode.Element }; + + public enum VerifyLocation // Verify Location - Root Window, Parent Chain, Element + { + Root = 0, + Parent = 1, + Element = 3, + } + + private static readonly List s_emptyReadOnlyTouchCollection = new List(); + + #endregion + + #region Constructor + + public TouchVerifier(UIElement element) + : base() + { + + } + + #endregion + + #region Helpers + + /// + /// Go through all elements and verify that + /// 1. AreAnyTouchesOver=false + /// 2. AreAnyTouchesDirectlyOver=false + /// 3. AreAnyTouchesCaptured=false + /// 4. AreAnyTouchesCapturedWithin=false + /// 5. TouchesCaptured is empty + /// 6. TouchesCapturedWithin is empty + /// + public void CheckNoTouchesOverOrCapture(DependencyObject dpObj) + { + foreach (DependencyObject obj in MultiTouchVerifier.EnumerateTree(dpObj, + false/*include parents*/, true/*include children*/, + true/*visual tree*/, true/*logical tree*/)) + { + object locObj = null; + + // 1. AreAnyTouchesOver + locObj = GetElementValue(obj, UIElement.AreAnyTouchesOverProperty, + ContentElement.AreAnyTouchesOverProperty, UIElement3D.AreAnyTouchesOverProperty); + + bool value = obj is IInputElement ? (bool)locObj : false; + Utils.Assert(value == false, string.Format("Invalid UIElement.AreAnyTouchesOver - expected: {0}, actual: {1}", false, value)); + + // 2. AreAnyTouchesDirectlyOver + locObj = GetElementValue(obj, UIElement.AreAnyTouchesDirectlyOverProperty, + ContentElement.AreAnyTouchesDirectlyOverProperty, UIElement3D.AreAnyTouchesDirectlyOverProperty); + + value = obj is IInputElement ? (bool)locObj : false; + Utils.Assert(value == false, "Invalid UIElement.AreAnyTouchesDirectlyOver"); + + // 3. AreAnyTouchesCaptured + locObj = GetElementValue(obj, UIElement.AreAnyTouchesCapturedProperty, + ContentElement.AreAnyTouchesCapturedProperty, UIElement3D.AreAnyTouchesCapturedProperty); + + value = obj is IInputElement ? (bool)locObj : false; + Utils.Assert(value == false, "Invalid UIElement.AreAnyTouchesCaptured"); + + // 4. AreAnyTouchesCapturedWithin + value = obj is IInputElement ? (bool)locObj : false; + Utils.Assert(value == false, "Invalid UIElement.AreAnyTouchesCapturedWithin"); + + // 5. TouchesCaptured + IEnumerable col; + if (obj is IInputElement) + { + UIElement el = obj as UIElement; + if (el != null) + { + col = el.TouchesCaptured; + } + else + { + ContentElement ce = obj as ContentElement; + if (ce != null) + { + col = ce.TouchesCaptured; + } + else + { + UIElement3D el3D = obj as UIElement3D; + if (el3D != null) + { + col = el3D.TouchesCaptured; + } + else + { + col = s_emptyReadOnlyTouchCollection; + } + } + } + + Utils.Assert(col != null, "Invalid UIElement.TouchesCaptured"); + Utils.Assert(0 == col.Count(), "Invalid Count for UIElement.TouchesCaptured"); + } + + // 6. TouchesCapturedWithin + if (obj is IInputElement) + { + UIElement el = obj as UIElement; + if (el != null) + { + col = el.TouchesCapturedWithin; + } + else + { + ContentElement ce = obj as ContentElement; + if (ce != null) + { + col = ce.TouchesCapturedWithin; + } + else + { + UIElement3D el3D = obj as UIElement3D; + if (el3D != null) + { + col = el3D.TouchesCapturedWithin; + } + else + { + col = s_emptyReadOnlyTouchCollection; + } + } + } + Utils.Assert(col != null, "Invalid UIElement.TouchesCapturedWithin"); + Utils.Assert(0 == col.Count(), "Invalid Count for UIElement.TouchesCapturedWithin"); + } + } + } + + /// + /// Get an element's property value + /// + /// + /// + /// + /// + /// + public static object GetElementValue(DependencyObject obj, + DependencyProperty expectedUIElementProperty, + DependencyProperty expectedContentElementProperty, + DependencyProperty expectedUIElement3DProperty) + { + // UIElement + UIElement uiElement = obj as UIElement; + if (uiElement != null) + { + return uiElement.GetValue(expectedUIElementProperty); + } + else // ContentElement + { + ContentElement contentElement = obj as ContentElement; + if (contentElement != null) + { + return contentElement.GetValue(expectedContentElementProperty); + } + else + { + UIElement3D uiElement3D = obj as UIElement3D; + if (uiElement3D != null) + { + return uiElement3D.GetValue(expectedUIElement3DProperty); + } + // otherwise use default value + else + { + return expectedUIElementProperty.DefaultMetadata.DefaultValue; + } + } + } + } + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/Utils.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/Utils.cs new file mode 100644 index 000000000..c23a75231 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/Utils.cs @@ -0,0 +1,1082 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Globalization; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Various utilities for multitouch testing + /// + public static class Utils + { + #region Constants + + private static readonly Random s_rand = new Random(); + + #endregion + + #region Point to PointF + + public static System.Drawing.PointF ToPointF(this Point p) + { + return new System.Drawing.PointF((float)p.X, (float)p.Y); + } + + public static System.Drawing.PointF[] ToPointFArray(this Point[] ps) + { + return (from p in ps select new System.Drawing.PointF((float)p.X, (float)p.Y)).ToArray(); + } + + #endregion + + #region Lengths and Rects + + public static RectangleR FindBox(ArrayList points) + { + double minX = double.MaxValue; + double maxX = double.MinValue; + double minY = double.MaxValue; + double maxY = double.MinValue; + + foreach (PointR p in points) + { + if (p.X < minX) + { + minX = p.X; + } + + if (p.X > maxX) + { + maxX = p.X; + } + + if (p.Y < minY) + { + minY = p.Y; + } + + if (p.Y > maxY) + { + maxY = p.Y; + } + } + + return new RectangleR(minX, minY, maxX - minX, maxY - minY); + } + + public static double Distance(PointR p1, PointR p2) + { + double dx = p2.X - p1.X; + double dy = p2.Y - p1.Y; + return Math.Sqrt(dx * dx + dy * dy); + } + + /// + /// compute the centroid of the given points + /// + /// + /// + public static PointR Centroid(ArrayList points) + { + double xsum = 0.0; + double ysum = 0.0; + + foreach (PointR p in points) + { + xsum += p.X; + ysum += p.Y; + } + + return new PointR(xsum / points.Count, ysum / points.Count); + } + + public static double PathLength(ArrayList points) + { + double length = 0; + for (int i = 1; i < points.Count; i++) + { + length += Distance((PointR)points[i - 1], (PointR)points[i]); + } + + return length; + } + + #endregion + + #region Angles and Rotations + + /// + /// Determines the angle, in degrees, between two points. the angle is defined + /// by the circle centered on the start point with a radius to the end point, + /// where 0 degrees is straight right from start (+x-axis) and 90 degrees is + /// straight down (+y-axis). + /// + /// + /// + /// + /// + public static double AngleInDegrees(PointR start, PointR end, bool positiveOnly) + { + double radians = AngleInRadians(start, end, positiveOnly); + return Rad2Deg(radians); + } + + /// + /// Determines the angle, in radians, between two points. the angle is defined + /// by the circle centered on the start point with a radius to the end point, + /// where 0 radians is straight right from start (+x-axis) and PI/2 radians is + /// straight down (+y-axis). + /// + /// + /// + /// + /// + public static double AngleInRadians(PointR start, PointR end, bool positiveOnly) + { + double radians = 0.0; + + if (start.X != end.X) + { + radians = Math.Atan2(end.Y - start.Y, end.X - start.X); + } + else // pure vertical movement + { + if (end.Y < start.Y) + { + radians = -Math.PI / 2.0; // -90 degrees for straight up + } + else if (end.Y > start.Y) + { + radians = Math.PI / 2.0; // 90 degrees for straight down + } + } + + if (positiveOnly && radians < 0.0) + { + radians += Math.PI * 2.0; + } + + return radians; + } + + public static double Rad2Deg(double rad) + { + return (rad * 180d / Math.PI); + } + + public static double Deg2Rad(double deg) + { + return (deg * Math.PI / 180d); + } + + /// + /// Rotate the points by the given degrees about their centroid + /// + /// + /// + /// + public static ArrayList RotateByDegrees(ArrayList points, double degrees) + { + double radians = Deg2Rad(degrees); + return RotateByRadians(points, radians); + } + + /// + /// Rotate the points by the given radians about their centroid + /// + /// + /// + /// + public static ArrayList RotateByRadians(ArrayList points, double radians) + { + ArrayList newPoints = new ArrayList(points.Count); + PointR c = Centroid(points); + + double cos = Math.Cos(radians); + double sin = Math.Sin(radians); + + double cx = c.X; + double cy = c.Y; + + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + + double dx = p.X - cx; + double dy = p.Y - cy; + + PointR q = PointR.Empty; + q.X = dx * cos - dy * sin + cx; + q.Y = dx * sin + dy * cos + cy; + + newPoints.Add(q); + } + return newPoints; + } + + /// + /// Rotate a point 'p' around a point 'c' by the given radians. + /// Rotation (around the origin) amounts to a 2x2 matrix of the form: + /// [ cos A -sin A ] [ p.x ] + /// [ sin A cos A ] [ p.y ] + /// Note that the C# Math coordinate system has +x-axis stright right and + /// +y-axis straight down. Rotation is clockwise such that from +x-axis to + /// +y-axis is +90 degrees, from +x-axis to -x-axis is +180 degrees, and + /// from +x-axis to -y-axis is -90 degrees. + /// + /// + /// + /// + /// + public static PointR RotatePoint(PointR p, PointR c, double radians) + { + PointR q = PointR.Empty; + q.X = (p.X - c.X) * Math.Cos(radians) - (p.Y - c.Y) * Math.Sin(radians) + c.X; + q.Y = (p.X - c.X) * Math.Sin(radians) + (p.Y - c.Y) * Math.Cos(radians) + c.Y; + return q; + } + + #endregion + + #region Translations + + /// + /// Translates the points so that the upper-left corner of their bounding box lies at 'toPt' + /// + /// + /// + /// + public static ArrayList TranslateBBoxTo(ArrayList points, PointR toPt) + { + ArrayList newPoints = new ArrayList(points.Count); + RectangleR r = Utils.FindBox(points); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X += (toPt.X - r.X); + p.Y += (toPt.Y - r.Y); + newPoints.Add(p); + } + return newPoints; + } + + /// + /// Translates the points so that their centroid lies at 'toPt' + /// + /// + /// + /// + public static ArrayList TranslateCentroidTo(ArrayList points, PointR toPt) + { + ArrayList newPoints = new ArrayList(points.Count); + PointR centroid = Centroid(points); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X += (toPt.X - centroid.X); + p.Y += (toPt.Y - centroid.Y); + newPoints.Add(p); + } + return newPoints; + } + + /// + /// Translates the points by the given delta amounts + /// + /// + /// + /// + public static ArrayList TranslateBy(ArrayList points, SizeR sz) + { + ArrayList newPoints = new ArrayList(points.Count); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X += sz.Width; + p.Y += sz.Height; + newPoints.Add(p); + } + return newPoints; + } + + #endregion + + #region Scaling + + /// + /// Scales the points so that they form the size given. Does not restore the origin of the box. + /// + /// + /// + /// + public static ArrayList ScaleTo(ArrayList points, SizeR sz) + { + ArrayList newPoints = new ArrayList(points.Count); + RectangleR r = Utils.FindBox(points); + + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + + if (r.Width != 0d) + { + p.X *= (sz.Width / r.Width); + } + + if (r.Height != 0d) + { + p.Y *= (sz.Height / r.Height); + } + + newPoints.Add(p); + } + return newPoints; + } + + /// + /// Scales by percentages contained in 'sz' parameter. values of 1.0 would result in the identity scale w/o change. + /// + /// + /// + /// + public static ArrayList ScaleBy(ArrayList points, SizeR sz) + { + ArrayList newPoints = new ArrayList(points.Count); + RectangleR r = FindBox(points); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X *= sz.Width; + p.Y *= sz.Height; + newPoints.Add(p); + } + return newPoints; + } + + /// + /// Scales the points so that the length of their longer side matches the length of the longer side of the given rect. + /// + /// + /// + /// + public static ArrayList ScaleToMax(ArrayList points, RectangleR rect) + { + ArrayList newPoints = new ArrayList(points.Count); + RectangleR r = FindBox(points); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X *= (rect.MaxSide / r.MaxSide); + p.Y *= (rect.MaxSide / r.MaxSide); + newPoints.Add(p); + } + return newPoints; + } + + /// + /// Scales the points so that the length of their shorter side matches the length of the shorter side of the given rect. + /// + /// + /// + /// + public static ArrayList ScaleToMin(ArrayList points, RectangleR rect) + { + ArrayList newPoints = new ArrayList(points.Count); + RectangleR r = FindBox(points); + for (int i = 0; i < points.Count; i++) + { + PointR p = (PointR)points[i]; + p.X *= (rect.MinSide / r.MinSide); + p.Y *= (rect.MinSide / r.MinSide); + newPoints.Add(p); + } + return newPoints; + } + + #endregion + + #region Path Sampling and Distance + + public static ArrayList Resample(ArrayList points, int n) + { + double I = PathLength(points) / (n - 1); // interval length + double D = 0.0; + + ArrayList srcPts = new ArrayList(points); + ArrayList dstPts = new ArrayList(n); + dstPts.Add(srcPts[0]); + + for (int i = 1; i < srcPts.Count; i++) + { + PointR pt1 = (PointR)srcPts[i - 1]; + PointR pt2 = (PointR)srcPts[i]; + + double d = Distance(pt1, pt2); + if ((D + d) >= I) + { + double qx = pt1.X + ((I - D) / d) * (pt2.X - pt1.X); + double qy = pt1.Y + ((I - D) / d) * (pt2.Y - pt1.Y); + PointR q = new PointR(qx, qy); + dstPts.Add(q); // append new point 'q' + srcPts.Insert(i, q); // insert 'q' at position i in points s.t. 'q' will be the next i + D = 0.0; + } + else + { + D += d; + } + } + + // at times due to rounding-error it falls short of adding the last point, so add it + if (dstPts.Count == n - 1) + { + dstPts.Add(srcPts[srcPts.Count - 1]); + } + + return dstPts; + } + + /// + /// Computes the 'distance' between two point paths by summing their corresponding point distances. + /// assumes that each path has been resampled to the same number of points at the same distance apart. + /// + /// + /// + /// + public static double PathDistance(ArrayList path1, ArrayList path2) + { + double distance = 0; + for (int i = 0; i < path1.Count; i++) + { + distance += Distance((PointR)path1[i], (PointR)path2[i]); + } + return distance / path1.Count; + } + + #endregion + + #region Random Numbers + + /// + /// Gets a random number between low and high, inclusive. + /// + /// + /// + /// + public static int Random(int low, int high) + { + return s_rand.Next(low, high + 1); + } + + /// + /// Gets multiple random numbers between low and high, inclusive. The numbers are guaranteed to be distinct. + /// + /// + /// + /// + /// + public static int[] Random(int low, int high, int num) + { + int[] array = new int[num]; + + for (int i = 0; i < num; i++) + { + array[i] = s_rand.Next(low, high + 1); + for (int j = 0; j < i; j++) + { + if (array[i] == array[j]) + { + i--; // redo i + break; + } + } + } + + return array; + } + + public static object GetRandomEnumValue(Enum enumType) + { + Random rnd; + int seed; + seed = DateTime.Now.Millisecond; + rnd = new Random(seed); + + object retVal = null; + try + { + System.Reflection.FieldInfo[] fi = enumType.GetType().GetFields(); + if (fi.Length > 0) + { + int index = rnd.Next(1, fi.Length); + retVal = fi[index].GetValue(null); + } + } + catch { } + + Utils.Assert(retVal != null); + return retVal; + } + + public static double GetRandomDouble() + { + double d = 0.0; + + int seed = DateTime.Now.Millisecond; + Random rnd = new Random(seed); + + d = rnd.NextDouble(); + + return d; + } + + /// + /// Gets a Random Point on strokecollection or outside + /// + /// + /// + /// + public static Point GetRandomPoint(StrokeCollection sc, Random rnd) + { + Point p = new Point(0, 0); + + if (sc == null || rnd == null || sc.Count == 0) + { + return new Point(rnd.Next(), rnd.Next()); + } + + //get a list of all points on the stroke + StylusPointCollection spc = new StylusPointCollection(); + foreach (Stroke s in sc) + { + spc.Add(s.StylusPoints.Reformat(spc.Description)); + } + + if (spc.Count == 0) + { + p = new Point(rnd.Next(), rnd.Next()); + } + else + { + int randomIndex = 0; + + if (rnd.NextDouble() > 0.5) // Pick either a point on the stroke or outside + { + randomIndex = rnd.Next(0, spc.Count); + p = spc[randomIndex].ToPoint(); + } + else + { + p = new Point(rnd.Next(), rnd.Next()); + } + } + + return p; + } + + public static Rect GetRandomRect(StrokeCollection sc, Random rnd) + { + Rect rc = Rect.Empty; + //error condition - not expected + if (sc == null || rnd == null) + { + return rc; + } + + Rect boundRect = sc.GetBounds(); + + if (boundRect == Rect.Empty || sc.Count == 0) + { + return rc = new Rect(GetRandomPoint(sc, rnd), new Size(rnd.Next(1, 1000), rnd.Next(1, 1000))); + } + + int option = rnd.Next() % 3; + + switch (option) + { + case 0: //whole bounding rect + rc = boundRect; + break; + + case 1: //totally random + rc = new Rect(GetRandomPoint(sc, rnd), new Size(rnd.Next(1, 1000), rnd.Next(1, 1000))); + break; + + case 2: + // with left,top inside the bounds but random size & location + double width1 = rnd.Next((int)Math.Min(1d, boundRect.Width), (int)Math.Max(100d, boundRect.Width)) + rnd.NextDouble(); + double height1 = rnd.Next((int)Math.Min(1d, boundRect.Height), (int)Math.Max(100d, boundRect.Height)) + rnd.NextDouble(); + + //just to protect ourselves again. + if (Double.IsNaN(width1) || width1 <= Double.Epsilon || Double.IsInfinity(width1)) + { + width1 = 1; + } + + if (Double.IsNaN(height1) || height1 <= Double.Epsilon || Double.IsInfinity(height1)) + { + height1 = 1; + } + + double x1 = rnd.Next((int)boundRect.X, (int)(boundRect.X + boundRect.Width)) + rnd.NextDouble(); + double y1 = rnd.Next((int)boundRect.Y, (int)(boundRect.Y + boundRect.Height)) + rnd.NextDouble(); + rc = new Rect(x1, y1, width1, height1); + + break; + } + + return rc; + } + + #endregion + + #region Stroke and Points + + /// + /// Compare two points + /// + /// + /// + /// + public static bool ComparePoints(Point a, Point b) + { + const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ + // Mean squared magnitude of point coefficients + double mag = 0.25 * (a.X * a.X + a.Y * a.Y + b.X * b.X + b.Y * b.Y); + if (mag == 0) + { + return true; + } + + // Allowing magnitude * DBL_EPSILON * 10 error, but squared + double maxError = mag * DBL_EPSILON * DBL_EPSILON * 100; + Vector delta = a - b; + + return delta.LengthSquared < maxError; + } + + /// + /// Compare points from two Stylus point collections + /// + /// + /// + /// + /// + public static bool CompareStrokes(Stroke sSrc, Stroke sDst, bool bComparePoints) + { + int nPoints = sSrc.StylusPoints.Count; + if (nPoints != sDst.StylusPoints.Count) + { + return false; + } + + if (sSrc.DrawingAttributes != sDst.DrawingAttributes) + { + return false; + } + + bool bRetCode = true; + + if (bComparePoints) + { + StylusPointCollection ptSrc = sSrc.StylusPoints; + StylusPointCollection ptDst = sDst.StylusPoints; + int i = 0; + + nPoints = ptSrc.Count; + for (; i < nPoints; ++i) + { + if (!StylusPoint.Equals(ptSrc[i], ptDst[i])) + { + break; + } + } + + bRetCode = (i == nPoints); + } + + return bRetCode; + } + + /// + /// Compare two strokecollections + /// + /// + /// + /// + /// + public static bool CompareStrokeCollections(StrokeCollection strokesSource, StrokeCollection strokesDestination, bool bComparePoints) + { + int nStrokes = strokesSource.Count; + if (nStrokes != strokesDestination.Count) return false; + + int i = 0; + + for (; i < nStrokes; ++i) + { + Stroke sSrc = strokesSource[i]; + Stroke sDst = strokesDestination[i]; + + if (!Utils.CompareStrokes(sSrc, sDst, bComparePoints)) + { + break; + } + } + + return (i == nStrokes); + } + + /// + /// Generic comparison of two arrays of type ItemType that impements Equals + /// + /// + /// + /// + public static void CompareArrays(ItemType[] first, ItemType[] second) + { + if (first.Length != second.Length) + { + throw new InvalidOperationException("Arrays do not have equal lengths"); + } + else + { + for (int i = 0; i < first.Length; i++) + { + if (!first[i].Equals(second[i])) + { + throw new InvalidOperationException(string.Format("Array item does not match at i = {0}", i)); + } + } + } + } + + /// + /// Compare two points arrays + /// + /// + /// + public static void ComparePointArrays(Point[] first, Point[] second) + { + if (first.Length != second.Length) + { + throw new InvalidOperationException("Arrays do not have equal lengths"); + } + else + { + Utils.CompareArrays(first, second); + } + } + + #endregion + + #region Asserts + + /// + /// Assert that condition is true. + /// + /// condition to test + public static void Assert(bool cond) + { + Utils.Assert(cond, String.Empty, null, null); + } + + /// + /// Do assert + /// + /// + /// + /// + public static void Assert(bool cond, string message, params object[] arg) + { + if (!cond) + { + throw new TestValidationException(string.Format(message, arg)); + } + } + + /// + /// Assert that objects are equal. The phrase "Expected: x Got: y" is automatically added to the message. + /// + /// expected value + /// actual value + /// message to display if assert fails + /// args for format tags in message + public static void AssertEqual(object expected, object actual, string message, params object[] arg) + { + if (!Object.Equals(expected, actual)) + { + if (expected == null) + { + expected = "NULL"; + } + + if (actual == null) + { + actual = "NULL"; + } + + message += String.Format(" Expected: {0} Got: {1}", expected, actual); + Utils.Assert(false, message, arg); + } + } + + /// + /// Assert that objects are equal. The phrase "Expected: x Got: y" is automatically added to the message. + /// + /// expected value + /// actual value + /// message to display if assert fails + /// args for format tags in message + public static void AssertEqual(int expected, int actual, string message, params object[] arg) + { + if (expected != actual) + { + message += String.Format(" Expected: {0} Got: {1}", expected, actual); + Utils.Assert(false, message, arg); + } + } + + /// + /// Assert that doubles are equal (up to relative error of epsion). + /// The phrase "Expected: x Got: y" is automatically added to the message. + /// + /// expected value + /// actual value + /// tolerance for relative error + /// message to display if assert fails + /// args for format tags in message + public static void AssertAreClose(double expected, double actual, double epsilon, string message, params object[] arg) + { + double tolerance = epsilon * Math.Max(Math.Abs(expected), Math.Abs(actual)); + if (Math.Abs(expected - actual) > tolerance) + { + message += String.Format(" Expected: {0} Got: {1}", expected, actual); + Utils.Assert(false, message, arg); + } + } + + /// + /// Assert that doubles are equal (up to relative error of epsion). + /// The phrase "Expected: x Got: y" is automatically added to the message. + /// + /// expected value + /// actual value + /// tolerance for relative error + /// message to display if assert fails + /// args for format tags in message + public static void AssertAreCloseNullable(double? expected, double? actual, double epsilon, string message, params object[] arg) + { + if (expected.HasValue && actual.HasValue) + { + double tolerance = epsilon * Math.Max(Math.Abs(expected.Value), Math.Abs(actual.Value)); + if (Math.Abs(expected.Value - actual.Value) > tolerance) + { + message += String.Format(" Expected: {0} Got: {1}", expected, actual); + Utils.Assert(false, message, arg); + } + } + else if (!expected.HasValue && !actual.HasValue) + { + Utils.Assert(true, message, arg); + } + else + { + Utils.Assert(false, message, arg); + } + } + + /// + /// Verifies that objects are equal, determined by their comparison methods. + /// + /// Comparable type + /// The first value to compare - Expected + /// The second value to compare + /// Description of the comparison + public static void AssertEqualGeneric(T expected, T actual, string message) where T : IComparable + { + if (expected.CompareTo(actual) == 0) + { + message += String.Format(" Expected: {0} Got: {1}", expected, actual); + Utils.Assert(false, message, null); + } + } + + #endregion + + #region Param Verifiers + + /// + /// Throws ArgumentOutOfRangeException if double value is not finite. + /// + /// + /// + /// + public static void CheckFinite(double value, string property, string paramName) + { + if (double.IsNaN(value) || double.IsInfinity(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckFinite for property [{0}]", property)); + } + } + + /// + /// Throws ArgumentOutOfRangeException if double value is not finite or NaN. + /// + /// + /// + /// + public static void CheckFiniteOrNaN(double value, string property, string paramName) + { + if (double.IsInfinity(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckFiniteOrNaN for property [{0}]", property)); + } + } + + /// + /// Throws ArgumentOutOfRangeException if double value is not positive and finite. + /// + /// + /// + /// + public static void CheckFinitePositive(double value, string property, string paramName) + { + if (value <= 0 || double.IsInfinity(value) || double.IsNaN(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckFinitePositive for property [{0}]", property)); + } + } + + /// + /// Throws ArgumentOutOfRangeException if double value is infinite or less than zero. + /// + /// + /// + /// + public static void CheckFiniteNonNegativeOrNaN(double value, string property, string paramName) + { + if (value < 0 || double.IsInfinity(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckFiniteNonNegativeOrNaN for property [{0}]", property)); + } + } + + /// + /// Throws ArgumentOutOfRangeException if double value is not finite and non-negative. + /// + /// + /// + /// + public static void CheckFiniteNonNegative(double value, string property, string paramName) + { + if (value < 0 || double.IsInfinity(value) || double.IsNaN(value)) + { + throw new ArgumentOutOfRangeException(paramName, value, string.Format(CultureInfo.InvariantCulture, "CheckFiniteNonNegative for property [{0}]", property)); + } + } + + #endregion + + #region Misc. + + /// + /// Returns the screen resolution (in pixels per inches) + /// + /// + public static Size GetScreenResolution() + { + Size retVal = Size.Empty; + IntPtr screenHDC = IntPtr.Zero; + try + { + screenHDC = MultiTouchNativeMethods.GetDC(IntPtr.Zero); + if (screenHDC == IntPtr.Zero) + { + throw new ExternalException("Native call to 'GetDC' failed w/ (error # " + Marshal.GetLastWin32Error() + ")"); + } + + int x = MultiTouchNativeMethods.GetDeviceCaps(screenHDC, (int)MultiTouchNativeMethods.LOGPIXELSX); + if (x == 0) + { + throw new ExternalException("Native call to 'GetDeviceCaps(x)' failed w/ (error # " + Marshal.GetLastWin32Error() + ")"); + } + + int y = MultiTouchNativeMethods.GetDeviceCaps(screenHDC, (int)MultiTouchNativeMethods.LOGPIXELSY); + if (y == 0) + { + throw new ExternalException("Native call to 'GetDeviceCaps(y)' failed w/ (error # " + Marshal.GetLastWin32Error() + ")"); + } + + retVal = new Size(x, y); + } + finally + { + if (screenHDC != IntPtr.Zero) + { + MultiTouchNativeMethods.ReleaseDC(IntPtr.Zero, screenHDC); screenHDC = IntPtr.Zero; + } + } + + return retVal; + } + + /// + /// Find the vertical and horizontal scale factors for different DPI setting. + /// + /// float that returns the horizontal factor + /// float that returns the vertical factor + /// + public static void HighDpiScaleFactors(out float xFactor, out float yFactor) + { + using (System.Drawing.Graphics gs = System.Drawing.Graphics.FromHwnd(IntPtr.Zero)) + { + xFactor = gs.DpiX / 96; + yFactor = gs.DpiY / 96; + } + } + + /// + /// Gets the top-most visual for the specified visual element. + /// + public static Visual GetTopMostVisual(Visual element) + { + PresentationSource source; + + if (element == null) + { + throw new ArgumentNullException("element"); + } + + source = PresentationSource.FromVisual(element); + if (source == null) + { + throw new InvalidOperationException(string.Format("The specified UiElement is not connected to a rendering Visual Tree: {0}", element)); + } + + return source.RootVisual; + } + + public static string TypeWithoutNamespace(object obj) + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + string[] astr = obj.GetType().ToString().Split('.'); + return astr[astr.Length - 1]; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTests.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTests.cs new file mode 100644 index 000000000..6cec25015 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTests.cs @@ -0,0 +1,439 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using Microsoft.Test; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Utilities for trying various combinations of valid and invalid values + /// + /// + /// The various parameter functions provided as arguments will typically be + /// taken from methods on the Values class. + /// + public static class ValueTests + { + /// + /// Try a 1-argument action with a variety of valid and invalid parameter values. + /// + /// + /// + /// + public static void Try( + System.Action tryAction, + System.Func> parameters, + string paramName) + { + Utils.Assert(tryAction != null); + Utils.Assert(parameters != null); + Utils.Assert(paramName != null); + + TryInvalid(tryAction, parameters, paramName); + TryValid(tryAction, parameters); + } + + /// + /// Try a 1-argument action with a variety of invalid parameter values. + /// + /// + /// + /// + public static void TryInvalid( + System.Action tryAction, + System.Func> parameters, + string paramName) + { + Utils.Assert(tryAction != null); + Utils.Assert(parameters != null); + Utils.Assert(paramName != null); + + // Verify invalid values in parameter + foreach (T invalidParam in parameters(false)) + { + // + + + + } + } + + /// + /// Try a 1-argument action with a variety of valid parameter values. + /// + /// + /// + public static void TryValid( + System.Action tryAction, + System.Func> parameters) + { + Utils.Assert(tryAction != null); + Utils.Assert(parameters != null); + + foreach (T validParam in parameters(true)) + { + tryAction(validParam); + } + } + + /// + /// Try a 2-argument action with a variety of valid and invalid parameter values. + /// + /// + /// + /// + public static void Try2( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + string paramName1, + string paramName2) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + + TryInvalid2( + tryAction, + params1, + params2, + paramName1, + paramName2); + + TryValid2( + tryAction, + params1, + params2); + } + + /// + /// Try a 2-argument action with a variety of invalid parameter values. + /// + /// + /// + /// + public static void TryInvalid2( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + string paramName1, + string paramName2) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + + // Verify invalid values in parameter 1 + foreach (T2 validParam2 in params2(true)) + { + TryInvalid( + (x) => tryAction(x, validParam2), + params1, + paramName1); + } + + // If both parameter 1 & 2 are invalid, it's parameter 1 that complains + foreach (T2 invalidParam2 in params2(false)) + { + TryInvalid( + (x) => tryAction(x, invalidParam2), + params1, + paramName1); + } + + // Verify invalid values in parameter 2 + foreach (T2 invalidParam2 in params2(false)) + { + // + + + + } + } + + /// + /// Try a 2-argument action with a variety of valid parameter values. + /// + /// + /// + /// + public static void TryValid2( + System.Action tryAction, + System.Func> params1, + System.Func> params2) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + + foreach (T2 validParam2 in params2(true)) + { + TryValid( + (x) => tryAction(x, validParam2), + params1); + } + } + + /// + /// Try a 3-argument action with a variety of valid and invalid parameter values. + /// + /// + /// + /// + /// + /// + /// + /// + public static void Try3( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3, + string paramName1, + string paramName2, + string paramName3) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + Utils.Assert(paramName3 != null); + + TryInvalid3( + tryAction, + params1, + params2, + params3, + paramName1, + paramName2, + paramName3); + + TryValid3( + tryAction, + params1, + params2, + params3); + } + + /// + /// Try a 3-argument action with a variety of invalid parameter values. + /// + /// + /// + /// + /// + /// + /// + /// + public static void TryInvalid3( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3, + string paramName1, + string paramName2, + string paramName3) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + Utils.Assert(paramName3 != null); + + foreach (T3 validParam3 in params3(true)) + { + TryInvalid2( + (a, b) => tryAction(a, b, validParam3), + params1, + params2, + paramName1, + paramName2); + } + + foreach (T3 invalidParam3 in params3(false)) + { + // + + + + } + } + + /// + /// Try a 3-argument action with a variety of valid parameter values. + /// + /// + /// + /// + /// + public static void TryValid3( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + + foreach (T3 param3 in params3(true)) + { + TryValid2( + (a, b) => tryAction(a, b, param3), + params1, + params2); + } + } + + + /// + /// Try a 4-argument action with a variety of valid and invalid parameter values. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Try4( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3, + System.Func> params4, + string paramName1, + string paramName2, + string paramName3, + string paramName4) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + Utils.Assert(params4 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + Utils.Assert(paramName3 != null); + Utils.Assert(paramName4 != null); + + TryInvalid4( + tryAction, + params1, + params2, + params3, + params4, + paramName1, + paramName2, + paramName3, + paramName4); + + TryValid4( + tryAction, + params1, + params2, + params3, + params4); + } + + /// + /// Try a 4-argument action with a variety of invalid parameter values. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void TryInvalid4( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3, + System.Func> params4, + string paramName1, + string paramName2, + string paramName3, + string paramName4) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + Utils.Assert(params4 != null); + Utils.Assert(paramName1 != null); + Utils.Assert(paramName2 != null); + Utils.Assert(paramName3 != null); + Utils.Assert(paramName4 != null); + + foreach (T4 validParam4 in params4(true)) + { + TryInvalid3( + (a, b, c) => tryAction(a, b, c, validParam4), + params1, + params2, + params3, + paramName1, + paramName2, + paramName3); + } + + foreach (T4 invalidParam4 in params4(false)) + { + // + + + + } + } + + /// + /// Try a 4-argument action with a variety of valid parameter values. + /// + /// + /// + /// + /// + /// + public static void TryValid4( + System.Action tryAction, + System.Func> params1, + System.Func> params2, + System.Func> params3, + System.Func> params4) + { + Utils.Assert(tryAction != null); + Utils.Assert(params1 != null); + Utils.Assert(params2 != null); + Utils.Assert(params3 != null); + Utils.Assert(params4 != null); + + foreach (T4 param4 in params4(true)) + { + TryValid3( + (a, b, c) => tryAction(a, b, c, param4), + params1, + params2, + params3); + } + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTypePropertyTest.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTypePropertyTest.cs new file mode 100644 index 000000000..0d31acf15 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/ValueTypePropertyTest.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// class for testing the behavior of a value type get/set property + /// + /// + /// This only works for value types as "owners" (the class that has the property on it); + /// the semantics of reference types don't work well for this model. + /// + /// The type of the object that has the property on it. + /// The return type of the property. Must be a value type. + public class ValueTypeProperty : Property + where TPropertyType : struct + { + #region Private Fields + + private readonly TPropertyType _defaultValue; + + #endregion + + #region Constructor + + /// + /// Constructor. + /// + /// The name of the property. + /// The default value of the property. + /// A function for enumerating valid and invalid values. + /// A function for constructing the owning type. + /// A function to get the property value. + /// An action that sets the property value. + public ValueTypeProperty( + string name, + TPropertyType defaultValue, + System.Func> values, + System.Func constructor, + System.Func getter, + System.Action setter) + : base(name, values, constructor, getter, setter) + { + this._defaultValue = defaultValue; + } + + #endregion + + #region Methods + + /// + /// Checks that the property has the expected default value. + /// + public override void CheckDefault() + { + TPropertyType ownerValue = Getter(Constructor()); + bool matches = CompareValues(this._defaultValue, ownerValue); + Utils.Assert(matches, string.Format("Property {0} has a default value of {1}. Expected: {2}", Name, ownerValue, this._defaultValue)); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/Values.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/Values.cs new file mode 100644 index 000000000..35acd3fe1 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/Values.cs @@ -0,0 +1,288 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// A set of collections of valid/invalid values + /// + /// + /// Most methods take a bool and return an IEnumerable of double values. + /// The values are valid for the method's criterion if the parameter is true, + /// and invalid for that criterion if the parameter is false. + /// + public static class Values + { + /// + /// Enumerates a set of integer values to use as IDs + /// + /// + public static IEnumerable Ids(bool getValidValues) + { + if (getValidValues) + { + for (int n = -3; n <= 3; ++n) + { + yield return n; + } + yield return int.MinValue; + yield return int.MaxValue; + yield return int.MinValue + 1; + yield return int.MaxValue - 1; + } + // no "else"; all values are valid + } + + /// + /// Enumerate values that pass (or fail) a "finite" test + /// + /// + public static IEnumerable Finite(bool getValidValues) + { + if (getValidValues) + { + // valid values + yield return double.MinValue; + yield return double.MaxValue; + yield return 0.0; + yield return 307.298; + yield return 0.3983; + yield return -49.29892; + } + else + { + // invalid values + yield return double.PositiveInfinity; + yield return double.NaN; + yield return double.NegativeInfinity; + } + } + + /// + /// Enumerate values that pass (or fail) a "finite or NaN" test. + /// + /// + /// + public static IEnumerable FiniteOrNaN(bool getValidValues) + { + if (getValidValues) + { + // valid values + foreach (double validValue in Finite(true)) + { + yield return validValue; + } + yield return double.NaN; + } + else + { + // invalid values + yield return double.PositiveInfinity; + yield return double.NegativeInfinity; + } + } + + /// + /// Enumerate values that pass (or fail) a "finite non-negative" test. + /// + /// + /// + public static IEnumerable FiniteNonNegative(bool getValidValues) + { + if (getValidValues) + { + yield return double.MaxValue; + yield return 0.0; + yield return double.Epsilon; + yield return 387.298; + yield return 0.39837; + } + else + { + yield return double.PositiveInfinity; + yield return double.NaN; + yield return double.NegativeInfinity; + yield return -float.Epsilon; + yield return -4923.2989; + } + } + + /// + /// Enumerate values that pass (or fail) a "finite and >= 1" test. + /// + /// + /// + public static IEnumerable FiniteNotLessThanOne(bool getValidValues) + { + if (getValidValues) + { + // valid values + foreach (double finite in Finite(true)) + { + if (finite >= 1.0) + { + yield return finite; + } + yield return 1.0; + } + } + else + { + // invalid values + yield return double.NaN; + yield return double.PositiveInfinity; + yield return double.NegativeInfinity; + yield return 1.0 - double.Epsilon; + foreach (double finite in Finite(true)) + { + if (finite < 1.0) + { + yield return finite; + } + } + } + } + + /// + /// Enumerate values that pass (or fail) a "NaN, or finite and >= 1" test. + /// + /// + /// + public static IEnumerable NaNOrFiniteNotLessThanOne(bool getValidValues) + { + foreach (double value in FiniteNotLessThanOne(getValidValues)) + { + if (getValidValues || !double.IsNaN(value)) + { + yield return value; + } + } + if (getValidValues) + { + yield return double.NaN; + } + } + + /// + /// Enumerates valid or invalid values for Vector. + /// + /// + /// + public static IEnumerable FiniteORNonNegative(bool getValidValues) + { + if (getValidValues) + { + yield return (new Vector(0, 0)); + yield return (new Vector(0.11, 0.11)); + yield return (new Vector(11.11, 11.11)); + yield return (new Vector(-0.11, -0.11)); + yield return (new Vector(-11.11, -11.11)); + yield return (new Vector(double.MaxValue, double.MaxValue)); + yield return (new Vector(double.MinValue, double.MinValue)); + yield return (new Vector(double.Epsilon, double.Epsilon)); + } + else + { + yield return (new Vector(double.NaN, double.Epsilon)); + yield return (new Vector(double.NaN, double.PositiveInfinity)); + yield return (new Vector(double.NaN, double.NegativeInfinity)); + } + } + + /// + /// Enumerates valid or invalid values for Point. + /// + /// + /// + public static IEnumerable FiniteValid(bool getValidValues) + { + if (getValidValues) + { + yield return (new Point(0, 0)); + yield return (new Point(16.8, 16.8)); + yield return (new Point(-16.8, -16.8)); + yield return (new Point(double.MaxValue, double.MinValue)); + yield return (new Point(double.MinValue, double.MaxValue)); + yield return (new Point(double.MinValue, double.MaxValue)); + } + else + { + yield return (new Point(double.PositiveInfinity, double.NaN)); + yield return (new Point(double.NegativeInfinity, double.PositiveInfinity)); + yield return (new Point(double.NaN, double.NegativeInfinity)); + } + } + + /// + /// Enumerate reference-type values where null is allowed but not required. + /// + /// + /// + /// + public static IEnumerable NullOrNot(bool getValidValues) + where T : class, new() + { + if (getValidValues) + { + yield return null; + yield return new T(); + } + // no "else" clause, because no values are invalid + } + + /// + /// Enumerates valid or invalid values for ManipulationModes. + /// + /// + /// + public static IEnumerable Manipulations(bool getValidValues) + { + if (getValidValues) + { + for (int n = (int)ManipulationModes.None; n < (int)ManipulationModes.All; ++n) + { + yield return (ManipulationModes)n; + } + } + else + { + yield return (ManipulationModes)int.MaxValue; + yield return (ManipulationModes)int.MinValue; + yield return (ManipulationModes)((int)ManipulationModes.None - 1); + yield return (ManipulationModes)((int)ManipulationModes.All + 1); + } + } + + /// + /// Enumerate pivots with various parameter values + /// + /// + /// + public static IEnumerable GetPivots(bool getValidValues) + { + if (getValidValues) + { + yield return null; + foreach (double validX in Values.FiniteOrNaN(true)) + { + foreach (double validY in Values.FiniteOrNaN(true)) + { + foreach (double validRadius in Values.NaNOrFiniteNotLessThanOne(true)) + { + ManipulationPivot pivot = new ManipulationPivot(); + pivot.Center = new Point(validX, validY); + pivot.Radius = validRadius; + yield return pivot; + } + } + } + } + // no "else" clause; no values are invalid + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/VectorPropertyTest.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/VectorPropertyTest.cs new file mode 100644 index 000000000..5a10f7948 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/VectorPropertyTest.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// Specializes Property for vectors + /// + /// + public class VectorProperty : ValueTypeProperty where TOwningType : new() + { + #region Constructor + + /// + /// Constructor. + /// + /// The name of the property. + /// The default value of the property. + /// A function for enumerating valid and invalid values. + /// A function to get the property value. + /// An action that sets the property value. + public VectorProperty( + string name, + Vector defaultValue, + System.Func> values, + System.Func getter, + System.Action setter) + : base(name, defaultValue, values, () => new TOwningType(), getter, setter) + { + } + + #endregion + + #region Methods + + /// + /// compare two vectors + /// + /// + /// + /// + protected override bool CompareValues(Vector value1, Vector value2) + { + return Vector.Equals(value1, value2); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Common/VisualTreeOptions.cs b/src/Test/ElementServices/FeatureTests/Part1/Common/VisualTreeOptions.cs new file mode 100644 index 000000000..18e885431 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Common/VisualTreeOptions.cs @@ -0,0 +1,215 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; + +namespace Microsoft.Test.Input.MultiTouch +{ + /// + /// provide various options to generate a visual tree + /// + public class VisualTreeOptions + { + /// + /// A delegate to get a value. + /// + /// + /// + public delegate T GetValue(); + + #region Fields + + private Thickness _extraMargin = new Thickness(-10, -10, -10, -10); + private int _addCount = 0; + private int _modifyPositionCount = 0; + private int _modifyPropertyCount = 0; + private int _removeCount = 0; + private int _brushCount = 20; + private int _penCount = 20; + private GetValue _getIsVisible; + private GetValue _getIsHitTestVisible; + private GetValue _getIsEnabled; + private bool _randomPanelTransform = false; + + /// + /// apply modification for all elements interested + /// + public const int AllElements = int.MaxValue; + + #endregion + + #region Properties + + /// + /// extra margin to place children + /// + public Thickness ExtraMargin + { + get + { + return this._extraMargin; + } + set + { + this._extraMargin = value; + } + } + + /// + /// number of child elements to generate + /// + public int AddCount + { + get + { + return this._addCount; + } + set + { + this._addCount = value; + } + } + + /// + /// number of child elements to modify + /// + public int ModifyPositionCount + { + get + { + return this._modifyPositionCount; + } + set + { + this._modifyPositionCount = value; + } + } + + /// + /// number of child elements to modify + /// + public int ModifyPropertiesCount + { + get + { + return this._modifyPropertyCount; + } + set + { + this._modifyPropertyCount = value; + } + } + + /// + /// number of child elements to remove + /// + public int RemoveCount + { + get + { + return this._removeCount; + } + set + { + this._removeCount = value; + } + } + + /// + /// number of random brushes to use + /// + public int BrushCount + { + get + { + return this._brushCount; + } + set + { + this._brushCount = value; + } + } + + /// + /// number of random pens to use + /// + public int PenCount + { + get + { + return this._penCount; + } + set + { + this._penCount = value; + } + } + + /// + /// IsVisible flag + /// + public GetValue GetIsVisible + { + get + { + return this._getIsVisible; + } + set + { + this._getIsVisible = value; + } + } + + /// + /// IsHitTestVisible flag + /// + public GetValue GetIsHitTestVisible + { + get + { + return this._getIsHitTestVisible; + } + set + { + this._getIsHitTestVisible = value; + } + } + + /// + /// IsEnabledVisible flag + /// + public GetValue GetIsEnabled + { + get + { + return this._getIsEnabled; + } + set + { + this._getIsEnabled = value; + } + } + + /// + /// the panel needs to be transformed or not + /// + public bool RandomPanelTransform + { + get + { + return this._randomPanelTransform; + } + set + { + this._randomPanelTransform = value; + } + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/Directory.build.props b/src/Test/ElementServices/FeatureTests/Part1/Directory.build.props new file mode 100644 index 000000000..cf8e42c50 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/Directory.build.props @@ -0,0 +1,6 @@ + + + + $(WpfTestBasePath)\ElementServices\FeatureTests\Part1\Common\MultiTouchTestCommon.csproj + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/dirs.proj b/src/Test/ElementServices/FeatureTests/Part1/dirs.proj new file mode 100644 index 000000000..38de6fdec --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/dirs.proj @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/CheckManipulationEventArgs.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/CheckManipulationEventArgs.cs new file mode 100644 index 000000000..0feada110 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/CheckManipulationEventArgs.cs @@ -0,0 +1,202 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Threading; +using System.Windows; +using System.Windows.Input; +using System.Windows.Input.Manipulations; +using System.Windows.Threading; +using Microsoft.Test; +using Microsoft.Test.Discovery; +using Microsoft.Test.Input.MultiTouch; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; +using Microsoft.Test.Threading; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Utils for the values of various properties on manipulation event args classes + /// + /// + + public static class CheckManipulationEventArgs + { + #region Manipulation events + + /// + /// Checks ManipulationStartingEventArgs for validity + /// + /// + public static void Starting(ManipulationStartingEventArgs e) + { + Utils.Assert(e.Mode == ManipulationModes.All, "In Starting - the default mode is not correct"); + Utils.Assert(e.ManipulationContainer is UIElement, "In Starting - the default container is not correct"); + Utils.Assert(e.Pivot == null, "In Starting - the default pivot is not null"); + Utils.Assert(e.IsSingleTouchEnabled == true, "In Starting - the default IsSingleTouchEnabled is not correct"); +//// Utils.Assert(e.Cancel == false, "In Starting - the default Cancel is not correct"); + Utils.Assert(e.RoutedEvent.RoutingStrategy == RoutingStrategy.Bubble, "In Starting - the Starting routing strategy is incorrect"); + } + + /// + /// Checks ManipulationStartedEventArgs for validity + /// + /// + public static void Started(ManipulationStartedEventArgs e) + { + Utils.Assert(IsFinite(e.ManipulationOrigin.X), string.Format("In Started - e.ManipulationOrigin.X IsFinite check failed")); + Utils.Assert(IsFinite(e.ManipulationOrigin.Y), string.Format("In Started - e.ManipulationOrigin.Y IsFinite check failed")); + Utils.Assert(e.RoutedEvent.RoutingStrategy == RoutingStrategy.Bubble, "In Started - the Started routing strategy is incorrect"); + } + + /// + /// Checks ManipulationDeltaEventArgs for validity + /// + /// Event args. + /// The set of currently supported manipulations. + /// The set of all manipulations that + /// have been supported at any time since the operation began. + public static void Delta(ManipulationDeltaEventArgs e, + ManipulationModes currentSupportedManipulations, ManipulationModes cumulativeSupportedManipulations) + { + Utils.Assert(IsFinite(e.ManipulationOrigin.X), string.Format("In Delta - e.ManipulationOrigin.X IsFinite check failed")); + Utils.Assert(IsFinite(e.ManipulationOrigin.Y), string.Format("In Delta - e.ManipulationOrigin.Y IsFinite check failed")); + Utils.Assert(e.RoutedEvent.RoutingStrategy == RoutingStrategy.Bubble, "In Delta - the Delta routing strategy is incorrect"); + + CheckValidDelta(e.DeltaManipulation); + CheckValidDelta(e.CumulativeManipulation); + + CheckAllowedDelta(e.DeltaManipulation, currentSupportedManipulations); + CheckAllowedDelta(e.CumulativeManipulation, cumulativeSupportedManipulations); + + CheckVelocities(e.Velocities, cumulativeSupportedManipulations); + } + + /// + /// Checks ManipulationInertiaStartingEventArgs for validity + /// + /// + public static void InertiaStarting(ManipulationInertiaStartingEventArgs e, + ManipulationModes cumulativeSupportedManipulations) + { + Utils.Assert(IsFinite(e.ManipulationOrigin.X), "In InertiaStarting - e.ManipulationOrigin.X IsFinite check failed"); + Utils.Assert(IsFinite(e.ManipulationOrigin.Y), "In InertiaStarting - e.ManipulationOrigin.Y IsFinite check failed"); + Utils.Assert(e.RoutedEvent.RoutingStrategy == RoutingStrategy.Bubble, "In InertiaStarting - the InertiaStarting routing strategy is incorrect"); + + CheckVelocities(e.InitialVelocities, cumulativeSupportedManipulations); + } + + /// + /// Checks ManipulationCompletedEventArgs for validity. + /// + /// Event args. + /// The set of all manipulations that + /// have been supported at any time since the operation began. + public static void Completed(ManipulationCompletedEventArgs e, ManipulationModes cumulativeSupportedManipulations) + { + Utils.Assert(IsFinite(e.ManipulationOrigin.X), "In Completed - e.ManipulationOrigin.X IsFinite check failed"); + Utils.Assert(IsFinite(e.ManipulationOrigin.Y), "In Completed - e.ManipulationOrigin.y IsFinite check failed"); + + CheckValidDelta(e.TotalManipulation); + CheckAllowedDelta(e.TotalManipulation, cumulativeSupportedManipulations); + + CheckVelocities(e.FinalVelocities, cumulativeSupportedManipulations); + } + + /// + /// Check a delta for valid values. + /// + /// + public static void CheckValidDelta(ManipulationDelta delta) + { + Utils.Assert(delta != null, "In CheckValidDelta - delta param should not be null"); + + Utils.Assert(IsFinite(delta.Translation.X), "In CheckValidDelta - IsFinite for delta.Translation.X failed"); + Utils.Assert(IsFinite(delta.Translation.Y), "In CheckValidDelta - IsFinite for delta.Translation.y failed"); + Utils.Assert(IsFinite(delta.Rotation), "In CheckValidDelta - IsFinite for delta.Rotation failed"); + Utils.Assert(IsFinite(delta.Expansion.X), "In CheckValidDelta - IsFinite for delta.Expansion.X failed"); + Utils.Assert(IsFinite(delta.Expansion.Y), "In CheckValidDelta - IsFinite for delta.Expansion.y failed"); + Utils.Assert(IsFinite(delta.Scale.X), "In CheckValidDelta - IsFinite for delta.Scale.X failed"); + Utils.Assert(IsFinite(delta.Scale.Y), "In CheckValidDelta - IsFinite for delta.Scale.X failed"); + + // + Utils.AssertEqual(delta.Expansion.X, delta.Expansion.Y, "In CheckValidDelta - non-proportional scaling detected"); + Utils.AssertEqual(delta.Scale.X, delta.Scale.Y, "In CheckValidDelta - non-proportional scaling detected"); + + Utils.Assert(delta.Scale.X > 0, "In CheckValidDelta - delta.Scale.X should be > 0"); + } + + #endregion + + #region Helpers + + /// + /// Check a manipulation delta to see whether it is consistent with + /// the specified set of supported manipulations + /// + /// + private static void CheckAllowedDelta(ManipulationDelta delta, ManipulationModes supportedManipulations) + { + CheckDeltaComponent(supportedManipulations, ManipulationModes.TranslateX, delta.Translation.X != 0); + CheckDeltaComponent(supportedManipulations, ManipulationModes.TranslateY, delta.Translation.Y != 0); + CheckDeltaComponent(supportedManipulations, ManipulationModes.Rotate, delta.Rotation != 0); + + bool hasExpansion = (delta.Expansion.X != 0) + || (delta.Expansion.Y != 0) + || (delta.Scale.X != 1) + || (delta.Scale.Y != 1); + CheckDeltaComponent(supportedManipulations, ManipulationModes.Scale, hasExpansion); + } + + /// + /// Verifies that a double value is finite. + /// + /// + /// + private static bool IsFinite(double value) + { + return !double.IsNaN(value) && !double.IsInfinity(value); + } + + /// + /// check allowed manipulation given mode and isActive + /// + /// + /// + /// + private static void CheckDeltaComponent(ManipulationModes allowed, ManipulationModes component, bool isActive) + { + bool isEnabled = (allowed & component) != ManipulationModes.None; + if (!isEnabled) + { + Utils.Assert(isActive == false, "In CheckDeltaComponent - {0} occurred when not allowed", component); + } + } + /// + /// Checks velocities to see if they're valid + /// + /// + /// + private static void CheckVelocities(ManipulationVelocities velocities, ManipulationModes supportedManipulations) + { + Utils.Assert(velocities != null, "In CheckVelocities - the param velocities should not be null"); + + Utils.Assert(IsFinite(velocities.LinearVelocity.X), "In CheckVelocities - velocities.LinearVelocity.X should be finite"); + Utils.Assert(IsFinite(velocities.LinearVelocity.Y), "In CheckVelocities - velocities.LinearVelocity.Y should be finite"); + Utils.Assert(IsFinite(velocities.AngularVelocity), "In CheckVelocities - velocities.AngularVelocity should be finite"); + Utils.Assert(IsFinite(velocities.ExpansionVelocity.X), "In CheckVelocities - velocities.ExpansionVelocity.X should be finite"); + Utils.Assert(IsFinite(velocities.ExpansionVelocity.Y), "In CheckVelocities - velocities.ExpansionVelocity.Y should be finite"); + Utils.AssertEqual(velocities.ExpansionVelocity.X, velocities.ExpansionVelocity.Y, "In CheckVelocities - non-proportional scaling detected"); + + CheckDeltaComponent(supportedManipulations, ManipulationModes.TranslateX, velocities.LinearVelocity.X != 0); + CheckDeltaComponent(supportedManipulations, ManipulationModes.TranslateY, velocities.LinearVelocity.Y != 0); + CheckDeltaComponent(supportedManipulations, ManipulationModes.Rotate, velocities.AngularVelocity != 0); + CheckDeltaComponent(supportedManipulations, ManipulationModes.Scale, velocities.ExpansionVelocity.X != 0); + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchFactory.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchFactory.cs new file mode 100644 index 000000000..ddf8c860e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchFactory.cs @@ -0,0 +1,228 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// A factory class for test windows, verifiers, etc. + /// + public class MultiTouchFactory + { + #region Properties + + public Type Type + { + get + { + return _type; + } + set + { + _type = value; + } + } + + public MultiTouchTestModes Mode + { + get + { + return _mode; + } + set + { + _mode = value; + } + } + + public string Title + { + get + { + return _title; + } + set + { + _title = value; + } + } + + #endregion + + #region Constructors + + static MultiTouchFactory() {} + + public MultiTouchFactory() : this(null, MultiTouchTestModes.Touch, null) { } + + public MultiTouchFactory(Type type) : this(type, MultiTouchTestModes.Touch, null) { } + + public MultiTouchFactory(MultiTouchTestModes mode) : this(null, mode, null) { } + + public MultiTouchFactory(Type type, MultiTouchTestModes mode, string title) + { + this.Type = type; + this.Mode = mode; + this.Title = title; + } + + #endregion + + #region Mothods + + //public static void AddHandler(DependencyObject d, RoutedEvent routedEvent, Delegate handler) + //{ + // if (routedEvent == null) + // { + // throw new ArgumentNullException("routedEvent"); + // } + + // if (handler == null) + // { + // throw new ArgumentNullException("handler"); + // } + + // if (handler.GetType() != routedEvent.HandlerType) + // { + // throw new ArgumentException("routedEvent and handler"); + // } + + // UIElement uie = d as UIElement; // + + + + + + + //public static void RemoveHandler(DependencyObject d, RoutedEvent routedEvent, Delegate handler) + //{ + // if (routedEvent == null) + // { + // throw new ArgumentNullException("routedEvent"); + // } + + // if (handler == null) + // { + // throw new ArgumentNullException("handler"); + // } + + // if (handler.GetType() != routedEvent.HandlerType) + // { + // throw new ArgumentException("routedEvent and handler"); + // } + + // UIElement uie = d as UIElement; // + + + + + + + + /// + /// create the test window by test mode w/ or w/o given test win title + /// the test window would be the generic type with major hookups + /// + /// + /// + public Window CreateTestWindow(string title) + { + switch(Mode.ToString()) + { + case "Manipulations": + _testwin = new TestManipulations(title); + break; + + case "Touch": + _testwin = new TestTouch(title); + break; + + case "Gestures": + _testwin = new MT35(); + break; + + case "Events": + _testwin = new RoutedEvents(); + break; + + default: + _testwin = new Window(); // manual build + break; + } + + return _testwin; + } + + /// + /// create the test window by window type + /// where you would like to have more control over + /// the instantiated test window + /// + /// + /// + public Window CreateTestWindow(Type type) + { + switch (type.ToString()) + { + case "MT35": + _testwin = new MT35(); + break; + + case "DrawCircles": + _testwin = new DrawCircles(); + break; + + default: + _testwin = new Window(); + break; + } + + return _testwin; + } + + /// + /// create related verifier by test mode + /// + /// + public MultiTouchVerifier CreateVerifier() + { + switch (Mode.ToString()) + { + case "Manipulations": + _verifier = new ManipulationVerifier(_testwin); + break; + + case "Touch": + _verifier = new TouchVerifier(_testwin); + break; + + case "Events": // + break; + + default: // gestures + _verifier = new GestureVerifier(_testwin); + break; + } + + return _verifier; + } + + #endregion + + #region Local Fields + + Type _type; + MultiTouchTestModes _mode; + string _title; + Window _testwin; + MultiTouchVerifier _verifier; + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTest.csproj b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTest.csproj new file mode 100644 index 000000000..500887221 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTest.csproj @@ -0,0 +1,128 @@ + + + + MultiTouchTest + Library + false + + + + + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + TestTouchControls.xaml + + + CubesTurn.xaml + + + D3DTestWindow.xaml + + + DrawCircles.xaml + + + ManipulableItem.xaml + + + ManipulatorTest.xaml + + + + RoutedEvents.xaml + + + MT35.xaml + + + MTPhotos.xaml + + + PhotoControl.xaml + + + TestManipulations.xaml + + + TestTouch.xaml + + + ModalTouchWindow.xaml + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTestBase.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTestBase.cs new file mode 100644 index 000000000..1090b1412 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MultiTouchTestBase.cs @@ -0,0 +1,404 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Threading; +using Microsoft.Test.TestTypes; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Media3D; +using Microsoft.Test.Logging; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Base class for MultiTouch testing + /// + public abstract class MultiTouchTestBase : AvalonTest + { + #region Constructors + + protected MultiTouchTestBase() + { + _dispatcher = Dispatcher.CurrentDispatcher; + s_mtTestBase = this; + } + + #endregion + + #region Public and Protected Properties + + /// + /// The root element. + /// + public FrameworkElement RootElement + { + get { return MainWindow.RootVisual as FrameworkElement; } + } + + /// + /// Get the main window. First access creates the window. + /// + /// + public HwndSource MainWindow + { + get + { + if (s_source == null) + { + HwndSourceParameters param = new HwndSourceParameters(WindowTitle); + param.SetPosition((int)WindowPosition.X, (int)WindowPosition.Y); + + if (WindowSize != Size.Empty) + { + param.SetSize((int)WindowSize.Width, (int)WindowSize.Height); + } + + s_source = new HwndSource(param); + + InitializeMainWindow(); + } + + return s_source; + } + set + { + s_source = value; + } + } + + public Dispatcher Dispatcher + { + get + { + return _dispatcher; + } + } + + /// + /// Set the Window title + /// + protected virtual string WindowTitle + { + get { return _windowTitle; } + set { _windowTitle = value; } + } + + /// + /// Set the window size. + /// + protected Size WindowSize + { + get { return _windowSize; } + set { _windowSize = value; } + } + + /// + /// Set the window position. + /// + protected Point WindowPosition + { + get { return _windowPosition; } + set { _windowPosition = value; } + } + + /// + /// Set the Window state + /// + protected WindowState WindowState + { + get { return _windowState; } + set { _windowState = value; } + } + + #endregion + + #region Public and Protected Methods + + /// + /// This is a temp solution to check only supported OS for the infra and lab run config can't support + /// OS + Version filtering yet. So we make pass the MT tests on downlevel OSs to reduce the false negative + /// caused by the limitation of the infra / lab run config filtering. + /// + /// + public TestResult PreInitialize() + { + TestResult result = TestResult.Pass; + + if (!MultiTouchVerifier.IsSupportedOS() || !(new TouchVerifier(null).IsSimulationAvailable)) + { + if (!MultiTouchVerifier.IsSupportedOS()) + { + GlobalLog.LogStatus("Unsupported OS"); + } + else + { + GlobalLog.LogStatus("Multitouch Simulator Driver not enabled, contact lab."); + } + TestLog log = null; + bool isLocalLog = false; + + if (TestLog.Current == null) + { + GlobalLog.LogStatus("Not Current TestLog"); + + log = new TestLog(this.GetType().Name); + isLocalLog = true; + } + else + { + log = TestLog.Current; + } + + log.Result = TestResult.Ignore; + result = log.Result; + + if (isLocalLog) + { + log.Close(); + } + } + return result; + } + + /// + /// Dispose the test window + /// + public void Dispose() + { + if (s_source != null) + { + s_source.Dispose(); + s_source = null; + } + } + + /// + /// Open the test window + /// + protected abstract void OpenTestWindow(); + + /// + /// close the test window + /// + protected abstract void CloseTestWindow(); + + /// + /// Do the initilization + /// + protected void InitializeMainWindow() + { + s_source.AddHook(new HwndSourceHook(ApplicationFilterMessage)); + + //SetTopMost(source.Handle, true); // + } + + /// + /// Do the uninitialization + /// + protected void UninitializeMainWindow() + { + s_source.RemoveHook(new HwndSourceHook(ApplicationFilterMessage)); + } + + /// + /// + /// + /// + protected bool DetectGesture() + { + // + return true; + } + + /// + /// + /// + /// + protected bool DetectManipulation() + { + // + return true; + } + + /// + /// Beta 2 + /// + /// + protected bool DetectTouch() + { + // + + return true; + } + + /// + /// Event which occurs when the main window is deactivated. + /// + protected virtual void OnDeactivated() + { + } + + /// + /// Make sure the element is not null + /// + /// the element being eval + protected void AssertNotNull(object element) + { + if (element == null) + { + throw new ArgumentNullException(string.Format("The param {0} should not be null", element)); + } + } + + /// + /// Make sure the element is not null + /// + /// the element being eval + protected void AssertNotNull(object element, string msg) + { + if (element == null) + { + throw new ArgumentNullException("element", msg); + } + } + + /// + /// Get the center point of the given element + /// + /// + /// + protected virtual Point GetCenterPoint(UIElement element) + { + AssertNotNull(element); + Point point = new Point(5, 5); + + if (PresentationSource.FromVisual(element) == null) + { + WaitFor(500); + } + + FrameworkElement fElement = element as FrameworkElement; + if (fElement != null) + { + // for controls + double height = fElement.ActualHeight; + double width = fElement.ActualWidth; + point = new Point(width / 2, height / 2); + + return fElement.PointToScreen(point); + } + + return point; + } + + /// + /// get the screen point + /// + /// + /// + protected virtual Point GetScreenPoint(UIElement element) + { + AssertNotNull(element); + + if (PresentationSource.FromVisual(element) != null) + { + return element.PointToScreen(new Point(5, 5)); + } + else + { + return new Point(5, 5); + } + } + + /// + /// Helper function to block till all queue items are processed, also introduce time + /// lag between subsequent test runs + /// + /// NOTE - due to te instability of the MultiTouch driver and some issue with the event routing, + /// we don't always get the expected ManipulationCompleted or TouchUp event, so use this more generic + /// method, instead of some specific waitfor + /// + public static void WaitTillQueueItemsProcessed() + { + // To keep this thread busy, we'll have to push a frame. + DispatcherFrame frame = new DispatcherFrame(); + + Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new DispatcherOperationCallback( + delegate(object arg) + { + frame.Continue = false; + return null; + }), null); + + // Keep the thread busy processing events until the timeout has expired. + Dispatcher.PushFrame(frame); + } + + #endregion + + #region Private Methods + + /// + /// For prev .NET 4.0 + /// + private void SetTouch() + { + if (MainWindow != null && MainWindow.Handle != IntPtr.Zero) + { + MultiTouchNativeMethods.SetPropMT(new HandleRef(this, MainWindow.Handle), "MicrosoftTabletPenServiceProperty", new HandleRef(null, new IntPtr(0x01000000))); + } + } + + private static IntPtr ApplicationFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + // quit the app if the source win is closed + if (msg == MultiTouchNativeMethods.WM_CLOSE) + { + s_mtTestBase.Dispatcher.BeginInvoke( + DispatcherPriority.ApplicationIdle, + new DispatcherOperationCallback(Quit), + null + ); + + handled = true; + } + + if (msg == MultiTouchNativeMethods.WM_ACTIVATE && wParam == IntPtr.Zero) + { + s_mtTestBase.OnDeactivated(); + } + + return IntPtr.Zero; + } + + private static object Quit(object arg) + { + s_mtTestBase.Dispatcher.InvokeShutdown(); + s_mtTestBase.Dispose(); + return null; + } + + #endregion + + #region Fields + + private static HwndSource s_source = null; + //private static Visual rootElement; + private static MultiTouchTestBase s_mtTestBase; + + private string _windowTitle = "MultiTouch Testing"; + private Size _windowSize = new Size(800, 600); + private Point _windowPosition = new Point(50, 50); + private WindowState _windowState; + private Dispatcher _dispatcher; + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyCustomThumb.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyCustomThumb.cs new file mode 100644 index 000000000..e3d7ba201 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyCustomThumb.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Media3D; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// A custom thumb control inherited from UIElement3D + /// + public class MyCustomThumb : UIElement3D + { + /// + /// add the model to the control when OnUpdateModel once to improve perf + /// + protected override void OnUpdateModel() + { + if (this.Visual3DModel == null) + { + this.Visual3DModel = Thumb3DModel(); + } + } + + /// + /// generate the GeometryModel3D for the control to use + /// + /// + protected GeometryModel3D Thumb3DModel() + { + MeshGeometry3D geo3D = new MeshGeometry3D(); + + Point3DCollection myPositionCollection = new Point3DCollection(); + myPositionCollection.Add(new Point3D(-2, -1, 0)); + myPositionCollection.Add(new Point3D(-1, -0.25, 4)); + myPositionCollection.Add(new Point3D(-2, 1, 0)); + myPositionCollection.Add(new Point3D(-1, 0.25, 4)); + myPositionCollection.Add(new Point3D(2, -1, 0)); + myPositionCollection.Add(new Point3D(1, -0.25, 4)); + myPositionCollection.Add(new Point3D(2, 1, 0)); + myPositionCollection.Add(new Point3D(1, 0.25, 4)); + geo3D.Positions = myPositionCollection; + + PointCollection myTextureCoordinatesCollection = new PointCollection(); + myTextureCoordinatesCollection.Add(new Point(0, 1)); + myTextureCoordinatesCollection.Add(new Point(0.2, 0.6)); + myTextureCoordinatesCollection.Add(new Point(0, 0)); + myTextureCoordinatesCollection.Add(new Point(0.2, 0.4)); + myTextureCoordinatesCollection.Add(new Point(1, 1)); + myTextureCoordinatesCollection.Add(new Point(0.8, 0.6)); + myTextureCoordinatesCollection.Add(new Point(1, 0)); + myTextureCoordinatesCollection.Add(new Point(0.8, 0.4)); + geo3D.TextureCoordinates = myTextureCoordinatesCollection; + + Int32Collection myTriangleIndicesCollection = new Int32Collection(); + myTriangleIndicesCollection.Add(0); // 0 1 2, + myTriangleIndicesCollection.Add(1); + myTriangleIndicesCollection.Add(2); + myTriangleIndicesCollection.Add(1); // 1 3 2, + myTriangleIndicesCollection.Add(3); + myTriangleIndicesCollection.Add(2); + myTriangleIndicesCollection.Add(0); // 0 2 4, + myTriangleIndicesCollection.Add(2); + myTriangleIndicesCollection.Add(4); + myTriangleIndicesCollection.Add(2); // 2 6 4, + myTriangleIndicesCollection.Add(6); + myTriangleIndicesCollection.Add(4); + myTriangleIndicesCollection.Add(0); // 0 4 1, + myTriangleIndicesCollection.Add(4); + myTriangleIndicesCollection.Add(1); + myTriangleIndicesCollection.Add(1); // 1 4 5, + myTriangleIndicesCollection.Add(4); + myTriangleIndicesCollection.Add(5); + myTriangleIndicesCollection.Add(1); // 1 5 7, + myTriangleIndicesCollection.Add(5); + myTriangleIndicesCollection.Add(7); + myTriangleIndicesCollection.Add(1); // 1 7 3, + myTriangleIndicesCollection.Add(7); + myTriangleIndicesCollection.Add(3); + myTriangleIndicesCollection.Add(4); //4 6 5, + myTriangleIndicesCollection.Add(6); + myTriangleIndicesCollection.Add(5); + myTriangleIndicesCollection.Add(7); // 7 5 6, + myTriangleIndicesCollection.Add(5); + myTriangleIndicesCollection.Add(6); + myTriangleIndicesCollection.Add(2); // 2 3 6, + myTriangleIndicesCollection.Add(3); + myTriangleIndicesCollection.Add(6); + myTriangleIndicesCollection.Add(3); // 3 7 6 + myTriangleIndicesCollection.Add(7); + myTriangleIndicesCollection.Add(6); + geo3D.TriangleIndices = myTriangleIndicesCollection; + + Material material = new DiffuseMaterial(new SolidColorBrush(Colors.DarkKhaki)); + + GeometryModel3D model3D = new GeometryModel3D(); + model3D.Geometry = geo3D; + model3D.Material = material; + + return model3D; + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyVisualHost.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyVisualHost.cs new file mode 100644 index 000000000..acdab2bd9 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/MyVisualHost.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Media; +using System.Windows.Input; +using System.Windows.Controls; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// custom visual host + /// + public class MyVisualHost : FrameworkElement + { + #region Constructor + + public MyVisualHost() + { + _children = new VisualCollection(this); + _children.Add(CreateDrawingVisualRectangle()); + ContainerVisual cv = new ContainerVisual(); + _label = new Label(); + cv.Children.Add(_label); + _children.Add(cv); + + // Add the touch event handler + this.TouchDown += new EventHandler(MyVisualHost_TouchDown); + } + + #endregion + + #region Event handler and helpers and overrides + + void MyVisualHost_TouchDown(object sender, System.Windows.Input.TouchEventArgs e) + { + e.TouchDevice.Capture(_label); + + _label.Content = string.Format("TouchesCapturedWithin={0}, TouchesOver={1}", this.TouchesCapturedWithin.ToString(), this.TouchesOver.ToString()); + } + + /// + /// create visual + /// + /// + private DrawingVisual CreateDrawingVisualRectangle() + { + DrawingVisual drawingVisual = new DrawingVisual(); + DrawingContext drawingContext = drawingVisual.RenderOpen(); + + Rect rect = new Rect(new System.Windows.Point(5, 5), new System.Windows.Size(120, 120)); + drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect); + drawingContext.Close(); + + return drawingVisual; + } + + protected override int VisualChildrenCount + { + get { return _children.Count; } + } + + protected override Visual GetVisualChild(int index) + { + if (index < 0 || index >= _children.Count) + { + throw new ArgumentOutOfRangeException(); + } + + return _children[index]; + } + + #endregion + + #region Private Fields + + private VisualCollection _children; + private Label _label; + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/SimpleTestBase.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/SimpleTestBase.cs new file mode 100644 index 000000000..618d59e0b --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/SimpleTestBase.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Test.Logging; +using Microsoft.Test.TestTypes; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// let's make things simplified + /// + public abstract class SimpleTestBase : StepsTest + { + protected SimpleTestBase() + { + } + + public TestResult PreInitialize() + { + TestResult result = TestResult.Pass; + + if (!MultiTouchVerifier.IsSupportedOS()) + { + GlobalLog.LogStatus("Not supported OS"); + + TestLog log = null; + bool isLocalLog = false; + + if (TestLog.Current == null) + { + GlobalLog.LogStatus("Not Current TestLog"); + + log = new TestLog(this.GetType().Name); + isLocalLog = true; + } + else + { + log = TestLog.Current; + } + + log.Result = TestResult.Ignore; + result = log.Result; + + if (isLocalLog) + { + log.Close(); + } + } + return result; + } + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/TestInputElement.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/TestInputElement.cs new file mode 100644 index 000000000..324968fc5 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/TestInputElement.cs @@ -0,0 +1,411 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Input; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// The purpose of this class is to have a custom implementation of IInputElement + /// so we can use one object for various invalid cases in test code + /// + /// + public class TestInputElement: IInputElement + { + #region IInputElement Members + + void IInputElement.AddHandler(RoutedEvent routedEvent, Delegate handler) + { + throw new Exception("The method or operation is not implemented."); + } + + bool IInputElement.CaptureMouse() + { + throw new Exception("The method or operation is not implemented."); + } + + bool IInputElement.CaptureStylus() + { + throw new Exception("The method or operation is not implemented."); + } + + bool IInputElement.Focus() + { + throw new Exception("The method or operation is not implemented."); + } + + bool IInputElement.Focusable + { + get + { + throw new Exception("The method or operation is not implemented."); + } + set + { + throw new Exception("The method or operation is not implemented."); + } + } + + event KeyboardFocusChangedEventHandler IInputElement.GotKeyboardFocus + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.GotMouseCapture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.GotStylusCapture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsEnabled + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsKeyboardFocusWithin + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsKeyboardFocused + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsMouseCaptured + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsMouseDirectlyOver + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsMouseOver + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsStylusCaptured + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsStylusDirectlyOver + { + get { throw new Exception("The method or operation is not implemented."); } + } + + bool IInputElement.IsStylusOver + { + get { throw new Exception("The method or operation is not implemented."); } + } + + event KeyEventHandler IInputElement.KeyDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyEventHandler IInputElement.KeyUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyboardFocusChangedEventHandler IInputElement.LostKeyboardFocus + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.LostMouseCapture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.LostStylusCapture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.MouseEnter + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.MouseLeave + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.MouseLeftButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.MouseLeftButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.MouseMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.MouseRightButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.MouseRightButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseWheelEventHandler IInputElement.MouseWheel + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyboardFocusChangedEventHandler IInputElement.PreviewGotKeyboardFocus + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyEventHandler IInputElement.PreviewKeyDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyEventHandler IInputElement.PreviewKeyUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event KeyboardFocusChangedEventHandler IInputElement.PreviewLostKeyboardFocus + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.PreviewMouseLeftButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.PreviewMouseLeftButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseEventHandler IInputElement.PreviewMouseMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.PreviewMouseRightButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseButtonEventHandler IInputElement.PreviewMouseRightButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event MouseWheelEventHandler IInputElement.PreviewMouseWheel + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusButtonEventHandler IInputElement.PreviewStylusButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusButtonEventHandler IInputElement.PreviewStylusButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusDownEventHandler IInputElement.PreviewStylusDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.PreviewStylusInAirMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.PreviewStylusInRange + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.PreviewStylusMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.PreviewStylusOutOfRange + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusSystemGestureEventHandler IInputElement.PreviewStylusSystemGesture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.PreviewStylusUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event TextCompositionEventHandler IInputElement.PreviewTextInput + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + void IInputElement.RaiseEvent(RoutedEventArgs e) + { + throw new Exception("The method or operation is not implemented."); + } + + void IInputElement.ReleaseMouseCapture() + { + throw new Exception("The method or operation is not implemented."); + } + + void IInputElement.ReleaseStylusCapture() + { + throw new Exception("The method or operation is not implemented."); + } + + void IInputElement.RemoveHandler(RoutedEvent routedEvent, Delegate handler) + { + throw new Exception("The method or operation is not implemented."); + } + + event StylusButtonEventHandler IInputElement.StylusButtonDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusButtonEventHandler IInputElement.StylusButtonUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusDownEventHandler IInputElement.StylusDown + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusEnter + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusInAirMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusInRange + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusLeave + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusMove + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusOutOfRange + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusSystemGestureEventHandler IInputElement.StylusSystemGesture + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event StylusEventHandler IInputElement.StylusUp + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + event TextCompositionEventHandler IInputElement.TextInput + { + add { throw new Exception("The method or operation is not implemented."); } + remove { throw new Exception("The method or operation is not implemented."); } + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml new file mode 100644 index 000000000..80d8a6ecb --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml.cs new file mode 100644 index 000000000..1bf27e91a --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/CubesTurn.xaml.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Media.Animation; +using System.Windows.Media.Media3D; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Interaction logic for Window1.xaml + /// + public partial class CubesTurn : Window + { + public CubesTurn() + { + InitializeComponent(); + } + + // When the ContainerUIElement3D that has the two cubes as its children gets the + // routed click event, spin the cubes in a 360 degree circle + private void ContainerMouseDown(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + + // spin the cubes around + DoubleAnimation doubleAnimation = new DoubleAnimation(0, + 360, + new Duration(TimeSpan.FromSeconds(0.5))); + containerRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, doubleAnimation); + } + + // Change the color of the first cube from Blue to Red, or vice versa, when it is clicked + private void Cube1MouseDown(object sender, MouseButtonEventArgs e) + { + cube1Material.Brush = (cube1Material.Brush == Brushes.Blue ? Brushes.Red : Brushes.Blue); + } + + // Change the color of the second cube from Green to Yellow, or vice versa, when it is clicked + private void Cube2MouseDown(object sender, MouseButtonEventArgs e) + { + cube2Material.Brush = (cube2Material.Brush == Brushes.Green ? Brushes.Yellow : Brushes.Green); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/D3DTestWindow.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/D3DTestWindow.xaml new file mode 100644 index 000000000..799add64f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/D3DTestWindow.xaml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + Translate + Rotate + Scale + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulableItem.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulableItem.xaml.cs new file mode 100644 index 000000000..9473b3bcd --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulableItem.xaml.cs @@ -0,0 +1,486 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Input.Manipulations; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Shapes; +using System.Windows.Threading; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// A simple item that can be translated, rotated, and scaled by dragging + /// with the mouse. It has checkboxes to allow enabling/disabling the + /// various types of manipulations, and a pivot indicator (which can be toggled + /// on and off by clicking it). + /// + public partial class ManipulableItem : UserControl + { + #region Fields + + private const float minLinearFlickVelocity = 0.01F; + private const float minScaleRotateRadius = 15F; + + private readonly ManipulationProcessor2D _manipulationProcessor; + private readonly InertiaProcessor2D _inertiaProcessor; + private readonly ManipulationPivot2D _pivot; + private readonly DispatcherTimer _inertiaTimer; + private UIElement _container; + private Point _dragCenter = new Point(double.NaN, double.NaN); + + #endregion + + #region Event + + /// + /// Event that fires when manipulation starts. + /// + public event EventHandler Started + { + add { this._manipulationProcessor.Started += value; } + remove { this._manipulationProcessor.Started -= value; } + } + + #endregion + + #region Constructor + + /// + /// Constructor. + /// + public ManipulableItem() + { + InitializeComponent(); + + CanTranslate.Tag = Manipulations2D.Translate; + CanRotate.Tag = Manipulations2D.Rotate; + CanScale.Tag = Manipulations2D.Scale; + CanTranslate.Checked += OnCheckedChanged; + CanTranslate.Unchecked += OnCheckedChanged; + CanRotate.Checked += OnCheckedChanged; + CanRotate.Unchecked += OnCheckedChanged; + CanScale.Checked += OnCheckedChanged; + CanScale.Unchecked += OnCheckedChanged; + PivotButton.Click += OnPivotClick; + + // The DeadZone is a little red ring that shows the area inside which + // no rotation or scaling will happen if you drag the mouse. We set + // it to four times the size of the manipulation processor's MininumScaleRotateRadius. + // Reason for the number: + // - x2, because diameter = 2 * radius + // - x2, because the number on the manipulation processor is radius from + // the center of mass of the manipulators being used, which in the case + // of this test app will be the midpoint between the mouse and the hub. + DeadZone.Width = 4 * minScaleRotateRadius; + DeadZone.Height = 4 * minScaleRotateRadius; + + this._manipulationProcessor = new ManipulationProcessor2D(SupportedManipulations); + this._manipulationProcessor.MinimumScaleRotateRadius = minScaleRotateRadius; + this._manipulationProcessor.Started += OnManipulationStarted; + this._manipulationProcessor.Delta += OnManipulationDelta; + this._manipulationProcessor.Completed += OnManipulationCompleted; + + this._inertiaProcessor = new InertiaProcessor2D(); + this._inertiaProcessor.TranslationBehavior.DesiredDeceleration = 0.0001F; + this._inertiaProcessor.RotationBehavior.DesiredDeceleration = 1e-6F; + this._inertiaProcessor.ExpansionBehavior.DesiredDeceleration = 0.0001F; + this._inertiaProcessor.Delta += OnManipulationDelta; + this._inertiaProcessor.Completed += OnInertiaCompleted; + + this._inertiaTimer = new DispatcherTimer(DispatcherPriority.Input,Dispatcher.CurrentDispatcher); + this._inertiaTimer.IsEnabled = false; + this._inertiaTimer.Interval = TimeSpan.FromMilliseconds(15); + this._inertiaTimer.Tick += OnTimerTick; + + this._pivot = new ManipulationPivot2D(); + + RenderTransformOrigin = new Point(0.5, 0.5); + + Radius = 100; + Center = new Point(0, 0); + IsPivotActive = true; + Move(Radius, Radius, 0, 1); + } + + #endregion + + #region Public Properties + + /// + /// Gets or sets the container used for manipulations. + /// + public UIElement Container + { + get { return this._container; } + set { this._container = value; } + } + + #endregion + + #region Protected Event handlers + + /// + /// mouse goes down on the item. + /// + /// + protected override void OnMouseDown(MouseButtonEventArgs e) + { + base.OnMouseDown(e); + e.MouseDevice.Capture(this); + } + + /// + /// mouse goes up. + /// + /// + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + if (e.MouseDevice.Captured == this) + { + e.MouseDevice.Capture(null); + } + } + + /// + /// capture the mouse. + /// + /// + protected override void OnGotMouseCapture(MouseEventArgs e) + { + base.OnGotMouseCapture(e); + ProcessMouse(e.MouseDevice); + } + + /// + /// lost mouse capture. + /// + /// + protected override void OnLostMouseCapture(MouseEventArgs e) + { + base.OnLostMouseCapture(e); + this._manipulationProcessor.ProcessManipulators(Timestamp, null); + } + + /// + /// mouse moves. + /// + /// + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + ProcessMouse(e.MouseDevice); + } + + #endregion + + #region Private Members - Methods, Properties, Event Handlers + + /// + /// Process a mouse event. + /// + /// + private void ProcessMouse(MouseDevice mouse) + { + if ((mouse.Captured == this) && (this._container != null)) + { + Point position = mouse.GetPosition(this._container); + List manipulators = new List(); + manipulators.Add(new Manipulator2D( + 0, + (float)(position.X), + (float)(position.Y))); + + // If translation is turned off and the pivot is turned on, + // make it act like there's a manipulator on the pivot point, + // to allow us to do scaling + if (((SupportedManipulations & Manipulations2D.Translate) == Manipulations2D.None) + && IsPivotActive) + { + manipulators.Add(new Manipulator2D( + 1, + (float)(Center.X), + (float)(Center.Y))); + } + + const Manipulations2D translateAndRotate = Manipulations2D.Translate | Manipulations2D.Rotate; + if ((manipulators.Count == 1) + && ((this._manipulationProcessor.SupportedManipulations & translateAndRotate) == translateAndRotate) + && IsPivotActive) + { + this._dragCenter = position; + } + else + { + this._dragCenter.X = double.NaN; + this._dragCenter.Y = double.NaN; + } + + this._manipulationProcessor.ProcessManipulators( + Timestamp, + manipulators); + } + } + + /// + /// Get the manipulations we should currently be supporting. + /// + private Manipulations2D SupportedManipulations + { + get + { + return GetManipulations(CanTranslate) + | GetManipulations(CanRotate) + | GetManipulations(CanScale); + } + } + + /// + /// Gets the center of the item, in container coordinates. + /// + private Point Center + { + get + { + return new Point(this._pivot.X, this._pivot.Y); + } + set + { + this._pivot.X = (float)value.X; + this._pivot.Y = (float)value.Y; + } + } + + /// + /// Gets or sets the orientation of the object, in degrees. + /// + private double Orientation { get; set; } + + /// + /// Gets or sets the radius of the object, in pixels. + /// + private double Radius + { + get + { + return this._pivot.Radius; + } + set + { + this._pivot.Radius = (float)value; + Width = 2 * value; + Height = 2 * value; + } + } + + /// + /// Gets or sets whether the pivot is active. + /// + private bool IsPivotActive + { + get + { + return this._manipulationProcessor.Pivot != null; + } + set + { + this._manipulationProcessor.Pivot = value ? this._pivot : null; + PivotButton.Opacity = value ? 1.0 : 0.3; + } + } + + /// + /// Gets the current timestamp. + /// + private static long Timestamp + { + get + { + // The question of what tick source to use is a difficult + // one in general, but for purposes of this test app, + // DateTime ticks are good enough. + return DateTime.UtcNow.Ticks; + } + } + + /// + /// when the state of a checkbox changes. + /// + /// + /// + private void OnCheckedChanged(object sender, RoutedEventArgs e) + { + this._manipulationProcessor.SupportedManipulations = SupportedManipulations; + if (this._inertiaProcessor.IsRunning) + { + this._inertiaProcessor.Complete(Timestamp); + } + } + + /// + /// when the pivot button is clicked. + /// + /// + /// + private void OnPivotClick(object sender, RoutedEventArgs e) + { + IsPivotActive = !IsPivotActive; + } + + /// + /// when manipulation starts. + /// + /// + /// + private void OnManipulationStarted(object sender, Manipulation2DStartedEventArgs e) + { + if (this._inertiaProcessor.IsRunning) + { + this._inertiaProcessor.Complete(Timestamp); + } + } + + /// + /// when manipulation gives a delta. + /// + /// + /// + private void OnManipulationDelta(object sender, Manipulation2DDeltaEventArgs e) + { + Move( + e.Delta.TranslationX, + e.Delta.TranslationY, + e.Delta.Rotation, + e.Delta.ScaleX); + } + + /// + /// when manipulation completes. + /// + /// + /// + private void OnManipulationCompleted(object sender, Manipulation2DCompletedEventArgs e) + { + this._dragCenter = new Point(double.NaN, double.NaN); + + float velocityX = e.Velocities.LinearVelocityX; + float velocityY = e.Velocities.LinearVelocityY; + float speedSquared = velocityX * velocityX + velocityY * velocityY; + if (speedSquared < minLinearFlickVelocity * minLinearFlickVelocity) + { + velocityX = velocityY = 0; + } + this._inertiaProcessor.TranslationBehavior.InitialVelocityX = velocityX; + this._inertiaProcessor.TranslationBehavior.InitialVelocityY = velocityY; + this._inertiaProcessor.RotationBehavior.InitialVelocity = e.Velocities.AngularVelocity; + this._inertiaProcessor.ExpansionBehavior.InitialVelocityX = e.Velocities.ExpansionVelocityX; + this._inertiaProcessor.ExpansionBehavior.InitialVelocityY = e.Velocities.ExpansionVelocityY; + //this.inertiaProcessor.InitialRadius = (float)Radius; // this.inertiaProcessor.InitialRadius = (float)Radius; + this._inertiaTimer.Start(); + } + + /// + /// when manipulation completes. + /// + /// + /// + private void OnInertiaCompleted(object sender, Manipulation2DCompletedEventArgs e) + { + this._inertiaTimer.Stop(); + } + + /// + /// when the inertia timer ticks. + /// + /// + /// + private void OnTimerTick(object sender, EventArgs e) + { + this._inertiaProcessor.Process(Timestamp); + } + + /// + /// Move the item as specified. + /// + /// Distance to translate along X axis. + /// Distance to translate along Y axis. + /// Amount to rotate, in radians. + /// Scale factor to apply. + private void Move(double deltaX, double deltaY, double rotation, double scale) + { + AdjustForSingleManipulatorDragRotation(ref deltaX, ref deltaY, rotation); + + MatrixTransform transform = RenderTransform as MatrixTransform; + if ((transform == null) || transform.IsFrozen) + { + transform = new MatrixTransform(); + RenderTransform = transform; + } + + double newX = Center.X + deltaX; + double newY = Center.Y + deltaY; + if (this._container != null) + { + newX = Math.Max(0, Math.Min(newX, this._container.RenderSize.Width)); + newY = Math.Max(0, Math.Min(newY, this._container.RenderSize.Height)); + } + + Center = new Point(newX, newY); + Orientation += rotation * 180.0 / Math.PI; + Radius = Math.Max(40, Math.Min(350, scale * Radius)); + + Matrix matrix = Matrix.Identity; + matrix.Rotate(Orientation); + matrix.Translate(Center.X - Radius, Center.Y - Radius); + + transform.Matrix = matrix; + } + + /// + /// If you're dragging with a single manipulator, *and* rotation and translation + /// are both enabled, *and* the pivot is turned on, then we want the object to + /// swing into line behind the drag point. This adjusts for that. + /// + /// Distance to translate along X axis. + /// Distance to translate along Y axis. + /// Amount to rotate, in radians. + private void AdjustForSingleManipulatorDragRotation(ref double deltaX, ref double deltaY, double rotation) + { + if (double.IsNaN(this._dragCenter.X) || double.IsNaN(this._dragCenter.Y)) + { + // we're not in single-manipulator-drag-rotate mode, do nothing + return; + } + + Vector toCenter = Center - this._dragCenter; + double sin = Math.Sin(rotation); + double cos = Math.Cos(rotation); + Vector rotatedToCenter = new Vector( + toCenter.X * cos - toCenter.Y * sin, + toCenter.X * sin + toCenter.Y * cos); + Vector shift = rotatedToCenter - toCenter; + deltaX += shift.X; + deltaY += shift.Y; + } + + /// + /// Get the manipulations that a checkbox specifies. + /// + /// + /// + private static Manipulations2D GetManipulations(CheckBox checkbox) + { + return (checkbox.IsChecked.Value) ? (Manipulations2D)checkbox.Tag : Manipulations2D.None; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml new file mode 100644 index 000000000..462fc245d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml.cs new file mode 100644 index 000000000..d3b36f602 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ManipulatorTest.xaml.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Interaction logic for ManipulatorTest.xaml + /// + /// + + public partial class ManipulatorTest : Window + { + #region Fields + + private readonly ManipulableItem _item; + + #endregion + + #region Constructor + + public ManipulatorTest() + { + InitializeComponent(); + + this._item = new ManipulableItem(); + this._item.Container = LayoutRoot; + + ItemHost.Children.Add(this._item); + } + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml new file mode 100644 index 000000000..1b6872d97 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml.cs new file mode 100644 index 000000000..dcdfe3583 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/ModalTouchWindow.xaml.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using Microsoft.Test.Logging; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Interaction logic for UserControl1.xaml + /// + public partial class ModalTouchWindow + { + public ModalTouchWindow() + { + InitializeComponent(); + } + + void OnNewWindowClick(object sender, RoutedEventArgs e) + { + var window = new ModalTouchWindow + { + Width = this.Width, + Height = this.Height, + Left = this.Left, + Top = this.Top, + }; + GlobalLog.LogEvidence("Opening a new ModalTouchWindow."); + window.ShowDialog(); + GlobalLog.LogEvidence("Opened a new ModalTouchWindow."); + } + + void OnCloseClick(object sender, RoutedEventArgs e) + { + GlobalLog.LogEvidence("Closing a ModalTouchWindow."); + this.Close(); + } + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/MultiPaintCanvas.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/MultiPaintCanvas.cs new file mode 100644 index 000000000..109ba0509 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/MultiPaintCanvas.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows; +using System.Windows.Media; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// + + public class MultiPaintCanvas : Canvas + { + class CustomStrokeInfo + { + public TouchPoint LastPoint { get; set; } + public Color Color { get; set; } + } + + Dictionary _StrokeInfos = new Dictionary(); + + public MultiPaintCanvas() + { + this.TouchDown += new EventHandler(OnTouchDown); + this.TouchMove += new EventHandler(OnTouchMove); + this.TouchUp += new EventHandler(OnTouchUp); + } + + protected void OnTouchDown(object sender, TouchEventArgs e) + { + var touchPoint = e.GetTouchPoint(this); + var color = GetRandomColor(); + e.TouchDevice.Capture(this); + _StrokeInfos[e.TouchDevice] = new CustomStrokeInfo { LastPoint = touchPoint, Color = color }; + } + + protected void OnTouchMove(object sender, TouchEventArgs e) + { + AddStroke(e); + _StrokeInfos[e.TouchDevice].LastPoint = e.GetTouchPoint(this); + } + + protected void OnTouchUp(object sender, TouchEventArgs e) + { + AddStroke(e); + e.TouchDevice.Capture(null); + _StrokeInfos.Remove(e.TouchDevice); + } + + private void AddStroke(TouchEventArgs e) + { + var touchPoint = e.GetTouchPoint(this); + var strokeInfo = _StrokeInfos[e.TouchDevice]; + DrawLine(strokeInfo.LastPoint, touchPoint, strokeInfo.Color); + } + + private void DrawLine(TouchPoint lastPoint, TouchPoint touchPoint, Color color) + { + // + } + + private Color GetRandomColor() + { + // + return Colors.AliceBlue; + } + + } + +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml new file mode 100644 index 000000000..145cd6ef3 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml.cs new file mode 100644 index 000000000..7db613b91 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/PhotoControl.xaml.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Interaction logic for PhotoControl.xaml + /// + public partial class PhotoControl : UserControl + { + Matrix _orgMatrix; + + public PhotoControl() + { + InitializeComponent(); + + Manipulation.SetManipulationMode(this, ManipulationModes.All); + this.RenderTransform = new MatrixTransform(); + } + + public void OnManipulationStarted(object sender, ManipulationStartedEventArgs e) + { + e.Handled = true; + _orgMatrix = ((MatrixTransform)this.RenderTransform).Matrix; + BringToFront(); + } + + public void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e) + { + var manipulation = e.CumulativeManipulation; + this.RenderTransform = CalculateMatrixTransform(manipulation, _orgMatrix); + e.Handled = true; + } + + public void OnManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) + { + } + + public void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs e) + { + } + + #region Methods + + public Uri ImagePath + { + get + { + BitmapImage bitmap = Photo.Source as BitmapImage; + + if (bitmap == null) + { + return new Uri(""); + } + + return bitmap.UriSource; + } + set + { + Photo.Source = new BitmapImage(value); + } + } + + /// + /// bring the current photo to the front most + /// + private void BringToFront() + { + Canvas parent = LogicalTreeHelper.GetParent(this) as Canvas; + if (parent != null) + { + int zIndex = Canvas.GetZIndex(this); + foreach (UIElement child in parent.Children) + { + int childIndex = Canvas.GetZIndex(child); + if (childIndex > zIndex) + { + Canvas.SetZIndex(child, childIndex - 1); + } + } + + Canvas.SetZIndex(this, parent.Children.Count - 1); + } + } + + private MatrixTransform CalculateMatrixTransform(ManipulationDelta e, Matrix matrix) + { + matrix.Translate(e.Translation.X, e.Translation.Y); + var orgCenter = new Point(this.RenderSize.Width * 0.5, this.RenderSize.Height * 0.5); + var center = matrix.Transform(orgCenter); + + matrix.RotateAt(e.Rotation, center.X, center.Y); + center = matrix.Transform(orgCenter); + + matrix.ScaleAt(e.Scale.X, e.Scale.Y, center.X, center.Y); + return new MatrixTransform(matrix); + } + + #endregion + } + +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml new file mode 100644 index 000000000..4e7dcba01 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml.cs new file mode 100644 index 000000000..0e0110c1e --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/RoutedEvents.xaml.cs @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using Microsoft.Test.Input.MultiTouch; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Interaction logic for RoutedEvents.xaml + /// + public partial class RoutedEvents : Window + { + #region Private Fields + + static readonly FontFamily s_fontfam = new FontFamily("Lucida Console"); + const string strFormat = "{0,-30} {1,-15}{2,-15} {3,-15}"; + StackPanel _stackOutput; + DateTime _dtLast; + + #endregion + + #region Constructor + + public RoutedEvents() + { + InitializeComponent(); + + TestWindow.Loaded += new RoutedEventHandler(OnLoaded); + } + + #endregion + + #region Private Methods + + /// + /// Build the UI tree + /// + /// + /// + void OnLoaded(object sender, RoutedEventArgs e) + { + Grid grid = new Grid(); + TestWindow.Content = grid; + + RowDefinition rowdef = new RowDefinition(); + rowdef.Height = GridLength.Auto; + grid.RowDefinitions.Add(rowdef); + rowdef = new RowDefinition(); + rowdef.Height = GridLength.Auto; + grid.RowDefinitions.Add(rowdef); + rowdef = new RowDefinition(); + rowdef.Height = new GridLength(100, GridUnitType.Star); + grid.RowDefinitions.Add(rowdef); + + Button btn = new Button(); + btn.HorizontalAlignment = HorizontalAlignment.Center; + btn.Margin = new Thickness(16); + btn.Padding = new Thickness(16); + grid.Children.Add(btn); + + TextBlock text = new TextBlock(); + text.FontSize = 24; + text.Text = TestWindow.Title; + btn.Content = text; + + TextBlock textHeadings = new TextBlock(); + textHeadings.FontFamily = s_fontfam; + textHeadings.Inlines.Add(new Underline(new Run( + String.Format(strFormat, + "Routed Event", "sender", "Source", "OriginalSource")))); + grid.Children.Add(textHeadings); + Grid.SetRow(textHeadings, 1); + + ScrollViewer scroll = new ScrollViewer(); + grid.Children.Add(scroll); + Grid.SetRow(scroll, 2); + + // add the stackpanel + _stackOutput = new StackPanel(); + scroll.Content = _stackOutput; + + // events + UIElement[] els = { TestWindow, grid, btn, text }; + foreach (UIElement el in els) + { + // keyboard + el.PreviewKeyDown += AllPurposeEventHandler; + el.PreviewKeyUp += AllPurposeEventHandler; + el.PreviewTextInput += AllPurposeEventHandler; + el.KeyDown += AllPurposeEventHandler; + el.KeyUp += AllPurposeEventHandler; + el.TextInput += AllPurposeEventHandler; + + // mouse + el.MouseDown += AllPurposeEventHandler; + el.MouseUp += AllPurposeEventHandler; + el.PreviewMouseDown += AllPurposeEventHandler; + el.PreviewMouseUp += AllPurposeEventHandler; + + // stylus + el.StylusDown += AllPurposeEventHandler; + el.StylusUp += AllPurposeEventHandler; + el.PreviewStylusDown += AllPurposeEventHandler; + el.PreviewStylusUp += AllPurposeEventHandler; + + // Touch + el.PreviewTouchDown += AllPurposeEventHandler; + el.PreviewTouchMove += AllPurposeEventHandler; + el.PreviewTouchUp += AllPurposeEventHandler; + el.GotTouchCapture += AllPurposeEventHandler; + el.LostTouchCapture += AllPurposeEventHandler; + el.TouchEnter += AllPurposeEventHandler; + el.TouchLeave += AllPurposeEventHandler; + el.TouchDown += AllPurposeEventHandler; + el.TouchMove += AllPurposeEventHandler; + el.TouchUp += AllPurposeEventHandler; + + // Manipulations + el.ManipulationStarting += new EventHandler(el_ManipulationStarting); + el.ManipulationStarted += AllPurposeEventHandler; + el.ManipulationDelta += AllPurposeEventHandler; + el.ManipulationInertiaStarting += AllPurposeEventHandler; + el.ManipulationCompleted += AllPurposeEventHandler; + el.ManipulationBoundaryFeedback += AllPurposeEventHandler; + + // click + el.AddHandler(Button.ClickEvent, new RoutedEventHandler(AllPurposeEventHandler)); + } + } + + void el_ManipulationStarting(object sender, ManipulationStartingEventArgs e) + { + e.Mode = ManipulationModes.All; + } + + void AllPurposeEventHandler(object sender, RoutedEventArgs args) + { + // add a blank line after 100 ms + DateTime dtNow = DateTime.Now; + if (dtNow - _dtLast > TimeSpan.FromMilliseconds(100)) + { + _stackOutput.Children.Add(new TextBlock(new Run(" "))); + } + _dtLast = dtNow; + + // display the event info + TextBlock text = new TextBlock(); + text.FontFamily = s_fontfam; + text.Text = String.Format(strFormat, + args.RoutedEvent.Name, + TypeWithoutNamespace(sender), + TypeWithoutNamespace(args.Source), + TypeWithoutNamespace(args.OriginalSource)); + + _stackOutput.Children.Add(text); + (_stackOutput.Parent as ScrollViewer).ScrollToBottom(); + } + + string TypeWithoutNamespace(object obj) + { + string[] astr = obj.GetType().ToString().Split('.'); + return astr[astr.Length-1]; + } + + #endregion + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestManipulations.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestManipulations.xaml new file mode 100644 index 000000000..3d18ce260 --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestManipulations.xaml @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouch.xaml.cs b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouch.xaml.cs new file mode 100644 index 000000000..1eca8178d --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouch.xaml.cs @@ -0,0 +1,898 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Text; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Controls.Primitives; +using System.Windows.Media.Media3D; + +namespace Microsoft.Test.Input.MultiTouch.Tests +{ + /// + /// Test raw touch + /// 1. Touch events + /// 2. Stylus to Touch + /// 3. Touch to Manipulations + /// + public partial class TestTouch : Window + { + #region Constructor + + public TestTouch(string wintitle) + { + InitializeComponent(); + + if (string.IsNullOrEmpty(wintitle)) + { + this.Title = _title; + } + else + { + this.Title = wintitle; + } + + // + Attach(); + } + + #endregion + + #region Properties + + public GeometryModel3D ThumbModel + { + get + { + return this.FindResource("Thumb3DModel") as GeometryModel3D; + } + } + + /// + /// default event handler + /// + public RoutedEventHandler DefaultEventHandler + { + get + { + return this._defaultEventHandler; + } + set + { + this._defaultEventHandler = value; + } + } + + /// + /// existing touches + /// + public Dictionary ExistingTouches + { + get + { + return this._existingTouches; + } + set + { + this._existingTouches = value; + } + } + + #endregion + + #region Touch Testing Helpers - TODOs + + /// + /// test touch related DPs + /// + /// message + /// touch map + /// delegate to get property value + /// delegate to get the expected property value + /// delegate to merge the expected + /// log filter + /// touch capture mode + /// touch capture internal + /// delegate to change visual tree + public void TestDependencyProperty(string message, Dictionary touchMap, + GetPropertyValue getActualValue, GetPropertyValue getExpectedValue, + MergePropertyValues mergeExpectedValues, Predicate logFilter, + CaptureMode captureMode, int captureInterval, AfterFrameSimulated changeVisualTree) + { + // + + try + { + // move the mouse to a well known position inside the window to avoid extra mouse movements later + // when we generate baseline values for each frame + Point mousePosition = new Point(0, 0); + MoveMouseTo(mousePosition); + + bool ok = true; + SimulateTouches(message, touchMap, + + // for each frame + delegate(int frameNumber, Dictionary currentTouchMap) + { + if (changeVisualTree != null) + { + changeVisualTree(frameNumber, currentTouchMap); + } + + // read actual value + Dictionary actualValues = MultiTouchVerifier.ReadAllValues(getActualValue, this); + + // generate baseline + Dictionary expectedValues = GenerateAllBaselineValues(ref mousePosition, currentTouchMap, + actualValues.Keys, getExpectedValue, mergeExpectedValues); + + if (!MultiTouchVerifier.ComparePropertyValues(frameNumber, expectedValues, actualValues, logFilter)) + { + ok = false; + } + }, captureMode, captureInterval); + + Utils.Assert(ok == true, "Mismatch between Mouse and Touch dependency properties."); + } + finally + { + // + } + } + + /// + /// simulate touches + /// + /// + /// + /// + /// + /// + public void SimulateTouches(string message, Dictionary touchMap, + AfterFrameSimulated afterFrameSimulated, CaptureMode captureMode, int captureInterval) + { + // simulate touches and collect events + try + { + for (int frameNumber = 0; ; frameNumber++) + { + bool existActiveTouch = false; + bool existDelayedTouch = false; + foreach (KeyValuePair pair in touchMap) + { + TouchData touchData = pair.Value; + + if (touchData.currentSnapshot < 0) + { + existDelayedTouch = true; + } + else if (touchData.currentSnapshot < touchData.snapshots.Count) + { + // + + //TouchDeviceAction action; + //if (touchData.currentSnapshot == 0) + //{ + // action = TouchDeviceAction.TouchAdd; + //} + //else if (touchData.currentSnapshot == touchData.snapshots.Count - 1) + //{ + // action = TouchDeviceAction.TouchRemove; + //} + //else + //{ + // action = TouchDeviceAction.TouchChange; + //} + + TouchDevice touch = touchData.snapshots[touchData.currentSnapshot]; + // simulate touch + // + + existActiveTouch = true; + + // capture touch + // + } + else if (touchData.currentSnapshot == touchData.snapshots.Count) + { + // hide the contact adorner and go to the next contact + // + } + } + + // no touches left + if (!existDelayedTouch && !existActiveTouch) + { + break; + } + + if (existActiveTouch) + { + // make sure that UI is updated - DoEvents(); + LocalDoEvents(); + Thread.Sleep(15); + } + + // invoke caller-provided delegate + if (afterFrameSimulated != null) + { + afterFrameSimulated(frameNumber, touchMap); + } + + // increase currentSnapshot index + foreach (KeyValuePair pair in touchMap) + { + TouchData touchData = pair.Value; + touchData.currentSnapshot++; + } + } + } + finally + { + // + } + } + + /// + /// append simultaneous touches + /// + /// + /// + /// + /// + public void AppendRandomTouchSeriesSimultaneousStart(Dictionary touchMap, int touchCount, + int touchStartId, int numberOfJoins) + { + // use Int64 to avoid overflow in arithmetic operations + int index = 0; + for (Int64 touchId64 = touchStartId; touchId64 < (Int64)touchStartId + (Int64)touchCount; touchId64++, index++) + { + int touchId = (int)(touchId64 & 0xffffffff); + + // create a contact that starts and finishes at random points inside Root element + TouchData touchData = new TouchData(); + touchData.touchId = touchId; + + //start at -1 to so there is one frame with no contacts + touchData.currentSnapshot = -1; + + touchData.snapshots = GenerateTouchSeries(TopGrid, touchId, + delegate() + { + return RandomGenerator.GetIntPoint(new Point(0, 0), new Point(TopGrid.ActualWidth, TopGrid.ActualHeight - 1)); + }, + numberOfJoins, 7); + + Utils.Assert(touchData.snapshots.Count >= 2); + + touchMap[touchId] = touchData; + } + } + + /// + /// dump logical tree + /// + /// + /// + public static string DumpLogicTree(FrameworkElement obj) + { + StringBuilder builder = new StringBuilder(1000); + DoDumpLogicalTree(obj, builder, 0); + return builder.ToString(); + } + + /// + /// build random visual tree for advanced tree change related tests + /// + public void BuildRandomVisualTree() + { + Debug.WriteLine("Building Visual Tree"); + + VisualTreeOptions options = new VisualTreeOptions(); + options.RemoveCount = VisualTreeOptions.AllElements; + options.AddCount = 50; + options.GetIsEnabled = delegate() { return RandomGenerator.GetBoolean(); }; + options.GetIsHitTestVisible = options.GetIsEnabled; + options.GetIsVisible = delegate() { return RandomGenerator.GetEnum(); }; + options.RandomPanelTransform = true; + + MultiTouchVerifier.ModifyVisualTree(TopGrid, options); + } + + /// + /// test touch down/move/up events + /// + /// + /// + /// + /// + public void TestTouchDownMoveUp(string message, Dictionary touchMap, + bool verifyParentChain, bool verifyEnterLeave) + { + try + { + // + + TouchEventCollector touchEventCollector = new TouchEventCollector(TopGrid, verifyEnterLeave, false/*verifyGestures*/); + try + { + // add event handlers + touchEventCollector.AddHandlers(this, verifyParentChain); + + // do simulations + SimulateTouches(message, touchMap, null, CaptureMode.None, -1); + } + finally + { + // remove handlers + touchEventCollector.RemoveHandlers(this, verifyParentChain); + } + + Debug.WriteLine(""); + Debug.WriteLine("ALL ACTUAL EVENTS:"); + touchEventCollector.Dump(); + + // build baseline and verify the collected events + foreach (KeyValuePair pair in touchMap) + { + // actual events for the current touch + TouchData touchData = pair.Value; + ReadOnlyCollection actualEvents = touchEventCollector.CollectedEventsForTouch(touchData.touchId); + + // build baseline using the Mouse + ReadOnlyCollection baselineEvents = null; + string error; + + if (!BaselineEventBuilder.Generate(this, TopGrid, this, verifyParentChain, verifyEnterLeave, touchData.snapshots, + delegate(TouchDevice snapshot) + { + // display touch position + MoveMouseTo(snapshot.GetTouchPoint(TopGrid).Position); + }, + out baselineEvents, out error)) + { + // failed to generate the baseline, skip this run + // + continue; + } + + // verify events against the built baseline + bool ok = EventCollector.CompareEvents(baselineEvents, actualEvents); + + Utils.Assert(ok, "Mismatch between Mouse and Contact events."); + } + } + finally + { + //todo - title change + } + } + + /// + /// move the mouse to a given point + /// + /// + private void MoveMouseTo(Point position) + { + Point globalPosistion = TopGrid.PointToScreen(position); + UserInput.MouseMove((int)globalPosistion.X, (int)globalPosistion.Y); + UserInput.MouseLeftDown(TopGrid, (int)globalPosistion.X, (int)globalPosistion.Y); + UserInput.MouseLeftUp(TopGrid); + + LocalDoEvents(); + } + + private void UpdateAllBaselineValues(IEnumerable elements, + Dictionary values, GetPropertyValue getValue, MergePropertyValues mergeValues) + { + // enumerate all child elements and read the value + foreach (DependencyObject obj in elements) + { + object newValue = getValue(obj); + object oldValue; + if (values.TryGetValue(obj, out oldValue)) + { + // merge values (simulate multi-touch) + newValue = mergeValues(oldValue, newValue); + } + values[obj] = newValue; + } + } + + /// + /// generate a baseline events from mouse counterparts + /// + /// + /// + /// + /// + /// + /// + private Dictionary GenerateAllBaselineValues(ref Point previousPosition, + Dictionary touchMap, + IEnumerable elements, + GetPropertyValue getValue, + MergePropertyValues mergeValues) + { + Dictionary values = new Dictionary(); + + // move mouse outside the window + Point outsideWindow = new Point(10000000, 10000000); + if (previousPosition != outsideWindow) + { + UserInput.MouseMove((int)outsideWindow.X, (int)outsideWindow.Y); + previousPosition = outsideWindow; + } + + // release capture + Mouse.Capture(null); + + // enumerate all child elements and read the value + UpdateAllBaselineValues(elements, values, getValue, mergeValues); + + // go through touches + foreach (KeyValuePair pair in touchMap) + { + // take a contact that has a series that is not finished yet + TouchData touchData = pair.Value; + int snapshotIndex = touchData.currentSnapshot; + if (snapshotIndex >= 0 && snapshotIndex < touchData.snapshots.Count - 1) // the last snapshot corresponds to TouchRemove, so ignore it + { + // move mouse to the touch position if it's different from the previous position + Point position = touchData.snapshots[snapshotIndex].GetTouchPoint(TopGrid).Position; + if (position != previousPosition) + { + UserInput.MouseMove((int)position.X, (int)position.Y); + previousPosition = position; + MoveMouseTo(position); + } + + // capture or release the Mouse + Mouse.Capture(touchData.capturedBy, touchData.captureMode); + + // enumerate all child elements and read the value + UpdateAllBaselineValues(elements, values, getValue, mergeValues); + } + } + + // release capture + Mouse.Capture(null); + + return values; + } + + private static List GenerateTouchSeries(Panel root, int touchtId, GetPointMethod getPoint, + int numberOfJoins, int maxIntervalBetweenSnapshots) + { + List touchSnapshots = new List(); + + // get two random points + if (numberOfJoins == 0) + { + // add two touch snapshots for Up and Down + Point point = getPoint(); // call getPoint() once to make sure that the start and end positions are the same + for (int i = 0; i < 2; i++) + { + // + } + } + else + { + Point start = getPoint(); + for (int i = 0; i < numberOfJoins; i++) + { + Point end = getPoint(); + int numberOfInternalPointsX = (int)Math.Abs(start.X - end.X) / maxIntervalBetweenSnapshots; + int numberOfInternalPointsY = (int)Math.Abs(start.Y - end.Y) / maxIntervalBetweenSnapshots; + int numberOfInternalPoints = Math.Max(numberOfInternalPointsX, numberOfInternalPointsY); + + // + // + + + if (i != numberOfJoins - 1) + { + // if this is not the last join then remove the last snapshot to avoid + // several snapshots with the same position because the next join will start + // from that point + touchSnapshots.RemoveAt(touchSnapshots.Count - 1); + } + start = end; + } + + // make sure that last two points have the same position, + // consider the last ContactChange and ContactUp events, they should have the same position + Debug.Assert(touchSnapshots.Count > 0); + touchSnapshots.Add(touchSnapshots[touchSnapshots.Count - 1]); + } + + return touchSnapshots; + } + + /// + /// private method to write out the touch over data through a logical tree + /// + /// + /// + /// + private static void DoDumpLogicalTree(FrameworkElement obj, StringBuilder builder, int indent) + { + builder.Append(new string(' ', indent)); + builder.Append(obj.Name); + builder.Append(' '); + builder.Append(obj.AreAnyTouchesOver ? "AreAnyTouchesOver=true" : ""); + + foreach (object child in LogicalTreeHelper.GetChildren(obj)) + { + FrameworkElement element = child as FrameworkElement; + if (element != null && element.Name.Length > 0 && element.Visibility == Visibility.Visible) + { + DoDumpLogicalTree(element, builder, indent + 2); + } + } + } + + /// + /// the good old helper + /// + private static void LocalDoEvents() + { + // To keep this thread busy, we'll have to push a frame. + System.Windows.Threading.DispatcherFrame frame = new System.Windows.Threading.DispatcherFrame(); + + System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, + new System.Windows.Threading.DispatcherOperationCallback( + delegate(object arg) + { + frame.Continue = false; + return null; + }), null); + + // Keep the thread busy processing events until the timeout has expired. + System.Windows.Threading.Dispatcher.PushFrame(frame); + } + + #endregion + + #region Event Handlers - Stylus, Mouse, Touch, Manipulations + + private void DefaultEventHandlerThunk(object sender, RoutedEventArgs args) + { + if (DefaultEventHandler != null) + { + DefaultEventHandler(sender, args); + } + } + + #region Stylus + + void OnStylusDownXaml(object sender, StylusDownEventArgs e) + { + // get the location for this touch + Point p = e.GetPosition(this); + AddWatchEvent(string.Format("Xaml - TT - StylusDown: p = ({0},{1})", p.X, p.Y)); + } + + void OnStylusUpXaml(object sender, StylusEventArgs e) + { + Point p = e.GetPosition(this); + AddWatchEvent(string.Format("Xaml - TT - StylusUp: p = ({0},{1})", p.X, p.Y)); + } + + void OnStylusDownWin(object sender, StylusDownEventArgs e) + { + // get the location for this touch + Point p = e.GetPosition(this); + AddWatchEvent(string.Format("TT - StylusDown: p = ({0},{1})", p.X, p.Y)); + +#if adhoc + //// attribute an id with a touch point + //if (TouchDevice1 == 0) + //{ + // TouchDevice1 = e.StylusDevice.Id; + + // // move the rectangle to the given location + // Touch1.SetValue(Canvas.LeftProperty, p.X - Touch1.Width / 2); + // Touch1.SetValue(Canvas.TopProperty, p.Y - Touch1.Height / 2); + //} + //else if (TouchDevice2 == 0) + //{ + // TouchDevice2 = e.StylusDevice.Id; + + // // move the rectangle to the given location + // Touch2.SetValue(Canvas.LeftProperty, p.X - Touch2.Width / 2); + // Touch2.SetValue(Canvas.TopProperty, p.Y - Touch2.Height / 2); + //} +#endif + } + + void OnStylusMoveWin(object sender, StylusEventArgs e) + { + Point p = e.GetPosition(this); + AddWatchEvent(string.Format("TT - StylusMove: p = ({0},{1})", p.X, p.Y)); + +#if adhoc + //// determine which touch this belongs to + //if (TouchDevice1 == e.StylusDevice.Id) + //{ + // // move the rectangle to the given location + // Touch1.SetValue(Canvas.LeftProperty, p.X - Touch1.Width / 2); + // Touch1.SetValue(Canvas.TopProperty, p.Y - Touch1.Height / 2); + //} + //else if (TouchDevice2 == e.StylusDevice.Id) + //{ + // // move the rectangle to the given location + // Touch2.SetValue(Canvas.LeftProperty, p.X - Touch2.Width / 2); + // Touch2.SetValue(Canvas.TopProperty, p.Y - Touch2.Height / 2); + //} +#endif + } + + void OnStylusUpWin(object sender, StylusEventArgs e) + { + Point p = e.GetPosition(this); + AddWatchEvent(string.Format("TT - StylusUp: p = ({0},{1})", p.X, p.Y)); + +#if adhoc + //// reinitialize touch id and hide the rectangle + //if (e.StylusDevice.Id == TouchDevice1) + //{ + // Touch1.SetValue(Canvas.LeftProperty, -Touch1.Width); + // TouchDevice1 = 0; + //} + //else if (e.StylusDevice.Id == TouchDevice2) + //{ + // Touch2.SetValue(Canvas.LeftProperty, -Touch2.Width); + // TouchDevice2 = 0; + //} +#endif + } + + private void OnStylusSystemGestureXaml(object sender, StylusSystemGestureEventArgs e) + { + AddWatchEvent(String.Format("Xaml - Gesture ({0}) - {1}", e.StylusDevice.TabletDevice.Type, e.SystemGesture)); + } + + #endregion + + #region Manipulations + + private void OnManipulationStarting(object sender, ManipulationStartingEventArgs e) + { + e.ManipulationContainer = this; + e.Mode = ManipulationModes.All; + + AddWatchEvent("TT - ManipStarting"); + } + + #endregion + + #region Touch + + private void OnTouchDownWin(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - TouchDown: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void OnTouchMoveWin(object sender, TouchEventArgs e) + { + AddWatchEvent("TT - TouchMove"); + } + + private void OnTouchUpWin(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - TouchUp: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_PreviewTouchUp(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - PreviewTouchUp: id={0}, origSource={1} ", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_PreviewTouchMove(object sender, TouchEventArgs e) + { + AddWatchEvent("TT - PreviewTouchMove"); + } + + private void TestTouch_PreviewTouchDown(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - PreviewTouchDown: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_LostTouchCapture(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - LostTouchCapture: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_GotTouchCapture(object sender, TouchEventArgs e) + { + AddWatchEvent(string.Format("TT - GotTouchCapture: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_TouchLeave(object sender, TouchEventArgs e) + { + leaveEventWin++; + AddWatchEvent(string.Format("TT - TouchLeave: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + private void TestTouch_TouchEnter(object sender, TouchEventArgs e) + { + enterEventWin++; + AddWatchEvent(string.Format("TT - TouchEnter: id={0}, orig={1}", e.TouchDevice.Id, e.OriginalSource)); + } + + #endregion + + #region Mouse + + private void TestTouch_MouseUp(object sender, MouseButtonEventArgs e) + { + AddWatchEvent("TT - MouseUp"); + } + + private void TestTouch_MouseDown(object sender, MouseButtonEventArgs e) + { + AddWatchEvent("TT - MouseDown"); + } + + private void TestTouch_MouseEnter(object sender, MouseEventArgs e) + { + AddWatchEvent("TT - MouseEnter"); + } + + private void TestTouch_MouseMove(object sender, MouseEventArgs e) + { + AddWatchEvent("TT - MouseMove"); + } + + private void LuckyButton_Click(object sender, RoutedEventArgs e) + { + AddWatchEvent("TT - LuckyButton clicked"); + } + + #endregion + + #region Others + + void onDragDelta(object sender, DragDeltaEventArgs e) + { + Canvas.SetLeft(LuckyThumb, Canvas.GetLeft(LuckyThumb) + e.HorizontalChange); + Canvas.SetTop(LuckyThumb, Canvas.GetTop(LuckyThumb) + e.VerticalChange); + } + + #endregion + + #endregion + + #region Local Helpers + + private void Attach() + { + // + + this.StylusDown += new StylusDownEventHandler(OnStylusDownWin); + this.StylusMove += new StylusEventHandler(OnStylusMoveWin); + this.StylusUp += new StylusEventHandler(OnStylusUpWin); + + this.TouchEnter += new EventHandler(TestTouch_TouchEnter); + this.TouchLeave += new EventHandler(TestTouch_TouchLeave); + this.TouchDown += new EventHandler(OnTouchDownWin); + this.TouchMove += new EventHandler(OnTouchMoveWin); + this.TouchUp += new EventHandler(OnTouchUpWin); + this.GotTouchCapture += new EventHandler(TestTouch_GotTouchCapture); + this.LostTouchCapture += new EventHandler(TestTouch_LostTouchCapture); + + this.PreviewTouchDown += new EventHandler(TestTouch_PreviewTouchDown); + this.PreviewTouchMove += new EventHandler(TestTouch_PreviewTouchMove); + this.PreviewTouchUp += new EventHandler(TestTouch_PreviewTouchUp); + + this.MouseEnter += new MouseEventHandler(TestTouch_MouseEnter); + this.MouseDown += new MouseButtonEventHandler(TestTouch_MouseDown); + this.MouseUp += new MouseButtonEventHandler(TestTouch_MouseUp); + + ResetCounters(); + } + + private void Detach() + { + // + + this.StylusDown -= new StylusDownEventHandler(OnStylusDownWin); + this.StylusMove -= new StylusEventHandler(OnStylusMoveWin); + this.StylusUp -= new StylusEventHandler(OnStylusUpWin); + + this.TouchEnter -= new EventHandler(TestTouch_TouchEnter); + this.TouchLeave -= new EventHandler(TestTouch_TouchLeave); + this.TouchDown -= new EventHandler(OnTouchDownWin); + this.TouchMove -= new EventHandler(OnTouchMoveWin); + this.TouchUp -= new EventHandler(OnTouchUpWin); + this.GotTouchCapture -= new EventHandler(TestTouch_GotTouchCapture); + this.LostTouchCapture -= new EventHandler(TestTouch_LostTouchCapture); + + this.PreviewTouchDown -= new EventHandler(TestTouch_PreviewTouchDown); + this.PreviewTouchMove -= new EventHandler(TestTouch_PreviewTouchMove); + this.PreviewTouchUp -= new EventHandler(TestTouch_PreviewTouchUp); + + this.MouseEnter -= new MouseEventHandler(TestTouch_MouseEnter); + this.MouseDown -= new MouseButtonEventHandler(TestTouch_MouseDown); + this.MouseUp -= new MouseButtonEventHandler(TestTouch_MouseUp); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + Detach(); + ResetCounters(); + this.Close(); + } + + /// + /// write the trace + /// + /// + private void AddWatchEvent(string s) + { + if (WatchList.Items.Count >= MaxWatchEvents) + { + WatchList.Items.RemoveAt(0); + } + + WatchList.Items.Add(s); + } + + /// + /// find the visual parent + /// + /// + /// + private static UIElement GetParent(object element) + { + return (UIElement)VisualTreeHelper.GetParent((UIElement)element); + } + + private void ResetCounters() + { + enterEventWin = 0; + leaveEventWin = 0; + } + + private void OnNavigateButtonClick(object sender, RoutedEventArgs e) + { + // Get URI to navigate to + Uri uri = new Uri(this.addressTextBox.Text, UriKind.RelativeOrAbsolute); + + // Only absolute URIs can be navigated to + if (!uri.IsAbsoluteUri) + { + MessageBox.Show("The Address URI must be absolute eg 'http://www.microsoft.com'"); + return; + } + + // Navigate to the desired URL by calling the .Navigate method + this.MyWebBrowser.Navigate(uri); + } + + #endregion + + #region Fields + + private string _title = "Multi-Touch Raw Touch Testing"; + private const int MaxWatchEvents = 30; + Dictionary _contactMap = new Dictionary(); + private RoutedEventHandler _defaultEventHandler = null; + private delegate Point GetPointMethod(); + private Dictionary _existingTouches = new Dictionary(); + internal int enterEventWin = 0, leaveEventWin = 0; + + #endregion + + } +} diff --git a/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouchControls.xaml b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouchControls.xaml new file mode 100644 index 000000000..cacccd43f --- /dev/null +++ b/src/Test/ElementServices/FeatureTests/Part1/multitouch/UIs/TestTouchControls.xaml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +