// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Microsoft.TestCommon.Types; namespace Microsoft.TestCommon { /// /// A base class for test data. A instance is associated with a given type, and the instance can /// provide instances of the given type to use as data in tests. The same instance can also provide instances /// of types related to the given type, such as a of the type. See the enum for all the /// variations of test data that a instance can provide. /// public abstract class TestData { /// /// Common for a . /// public static readonly ValueTypeTestData CharTestData = new ValueTypeTestData('a', Char.MinValue, Char.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData IntTestData = new ValueTypeTestData(-1, 0, 1, Int32.MinValue, Int32.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData UintTestData = new ValueTypeTestData(0, 1, UInt32.MinValue, UInt32.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData ShortTestData = new ValueTypeTestData(-1, 0, 1, Int16.MinValue, Int16.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData UshortTestData = new ValueTypeTestData(0, 1, UInt16.MinValue, UInt16.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData LongTestData = new ValueTypeTestData(-1, 0, 1, Int64.MinValue, Int64.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData UlongTestData = new ValueTypeTestData(0, 1, UInt64.MinValue, UInt64.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData ByteTestData = new ValueTypeTestData(0, 1, Byte.MinValue, Byte.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData SByteTestData = new ValueTypeTestData(-1, 0, 1, SByte.MinValue, SByte.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData BoolTestData = new ValueTypeTestData(true, false); /// /// Common for a . /// public static readonly ValueTypeTestData DoubleTestData = new ValueTypeTestData( -1.0, 0.0, 1.0, double.MinValue, double.MaxValue, double.PositiveInfinity, double.NegativeInfinity); /// /// Common for a . /// public static readonly ValueTypeTestData FloatTestData = new ValueTypeTestData( -1.0f, 0.0f, 1.0f, float.MinValue, float.MaxValue, float.PositiveInfinity, float.NegativeInfinity); /// /// Common for a . /// public static readonly ValueTypeTestData DecimalTestData = new ValueTypeTestData( -1M, 0M, 1M, decimal.MinValue, decimal.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData DateTimeTestData = new ValueTypeTestData( DateTime.Now, DateTime.UtcNow, DateTime.MaxValue, DateTime.MinValue); /// /// Common for a . /// public static readonly ValueTypeTestData TimeSpanTestData = new ValueTypeTestData( TimeSpan.MinValue, TimeSpan.MaxValue); /// /// Common for a . /// public static readonly ValueTypeTestData GuidTestData = new ValueTypeTestData( Guid.NewGuid(), Guid.Empty); /// /// Common for a . /// public static readonly ValueTypeTestData DateTimeOffsetTestData = new ValueTypeTestData( DateTimeOffset.MaxValue, DateTimeOffset.MinValue, new DateTimeOffset(DateTime.Now)); /// /// Common for an enum. /// public static readonly ValueTypeTestData SimpleEnumTestData = new ValueTypeTestData( SimpleEnum.First, SimpleEnum.Second, SimpleEnum.Third); /// /// Common for an enum implemented with a . /// public static readonly ValueTypeTestData LongEnumTestData = new ValueTypeTestData( LongEnum.FirstLong, LongEnum.SecondLong, LongEnum.ThirdLong); /// /// Common for an enum decorated with a . /// public static readonly ValueTypeTestData FlagsEnumTestData = new ValueTypeTestData( FlagsEnum.One, FlagsEnum.Two, FlagsEnum.Four); /// /// Expected permutations of non supported file paths. /// public static readonly TestData NotSupportedFilePaths = new RefTypeTestData(() => new List() { "cc:\\a\\b", }); /// /// Expected permutations of invalid file paths. /// public static readonly TestData InvalidNonNullFilePaths = new RefTypeTestData(() => new List() { String.Empty, "", " ", " ", "\t\t \n ", "c:\\ab", "c:\\a\"b", "c:\\a\tb", "c:\\a|b", "c:\\a\bb", "c:\\a\0b", }); /// /// All expected permutations of an empty string. /// public static readonly TestData NonNullEmptyStrings = new RefTypeTestData(() => new List() { String.Empty, "", " ", "\t\r\n" }); /// /// All expected permutations of an empty string. /// public static readonly TestData EmptyStrings = new RefTypeTestData(() => new List() { null, String.Empty, "", " ", "\t\r\n" }); /// /// Common for a . /// public static readonly RefTypeTestData StringTestData = new RefTypeTestData(() => new List() { "", " ", // one space " ", // multiple spaces " data ", // leading and trailing whitespace "\t\t \n ", "Some String!"}); /// /// Common for a class that implements . /// public static readonly RefTypeTestData ISerializableTypeTestData = new RefTypeTestData( ISerializableType.GetTestData); /// /// A read-only collection of value type test data. /// public static readonly ReadOnlyCollection ValueTypeTestDataCollection = new ReadOnlyCollection(new TestData[] { CharTestData, IntTestData, UintTestData, ShortTestData, UshortTestData, LongTestData, UlongTestData, ByteTestData, SByteTestData, BoolTestData, DoubleTestData, FloatTestData, DecimalTestData, TimeSpanTestData, GuidTestData, DateTimeOffsetTestData, SimpleEnumTestData, LongEnumTestData, FlagsEnumTestData}); /// /// A read-only collection of reference type test data. /// public static readonly ReadOnlyCollection RefTypeTestDataCollection = new ReadOnlyCollection(new TestData[] { StringTestData, ISerializableTypeTestData}); /// /// A read-only collection of value and reference type test data. /// public static readonly ReadOnlyCollection ValueAndRefTypeTestDataCollection = new ReadOnlyCollection( ValueTypeTestDataCollection.Concat(RefTypeTestDataCollection).ToList()); /// /// A read-only collection of representative values and reference type test data. /// Uses where exhaustive coverage is not required. /// public static readonly ReadOnlyCollection RepresentativeValueAndRefTypeTestDataCollection = new ReadOnlyCollection(new TestData[] { IntTestData, BoolTestData, SimpleEnumTestData, StringTestData, }); private Dictionary registeredTestDataVariations; /// /// Initializes a new instance of the class. /// /// The type associated with the instance. protected TestData(Type type) { if (type.ContainsGenericParameters) { throw new InvalidOperationException("Only closed generic types are supported."); } this.Type = type; this.registeredTestDataVariations = new Dictionary(); } /// /// Gets the type associated with the instance. /// public Type Type { get; private set; } /// /// Gets the supported test data variations. /// /// public IEnumerable GetSupportedTestDataVariations() { return this.registeredTestDataVariations.Keys; } /// /// Gets the related type for the given test data variation or returns null if the instance /// doesn't support the given variation. /// /// The test data variation with which to create the related . /// The related for the as given by the test data variation. /// /// For example, if the given was created for test data and the varation parameter /// was then the returned type would be . /// public Type GetAsTypeOrNull(TestDataVariations variation) { TestDataVariationProvider testDataVariation = null; if (this.registeredTestDataVariations.TryGetValue(variation, out testDataVariation)) { return testDataVariation.Type; } return null; } /// /// Gets test data for the given test data variation or returns null if the instance /// doesn't support the given variation. /// /// The test data variation with which to create the related test data. /// Test data of the type specified by the method. public object GetAsTestDataOrNull(TestDataVariations variation) { TestDataVariationProvider testDataVariation = null; if (this.registeredTestDataVariations.TryGetValue(variation, out testDataVariation)) { return testDataVariation.TestDataProvider(); } return null; } /// /// Allows derived classes to register a that will /// provide test data for a given variation. /// /// The variation with which to register the r. /// The type of the test data created by the /// A that will provide test data. protected void RegisterTestDataVariation(TestDataVariations variation, Type type, Func testDataProvider) { this.registeredTestDataVariations.Add(variation, new TestDataVariationProvider(type, testDataProvider)); } private class TestDataVariationProvider { public TestDataVariationProvider(Type type, Func testDataProvider) { this.Type = type; this.TestDataProvider = testDataProvider; } public Func TestDataProvider { get; private set; } public Type Type { get; private set; } } } /// /// A generic base class for test data. /// /// The type associated with the test data. public abstract class TestData : TestData, IEnumerable { private static readonly Type OpenIEnumerableType = typeof(IEnumerable<>); private static readonly Type OpenListType = typeof(List<>); private static readonly Type OpenIQueryableType = typeof(IQueryable<>); /// /// Initializes a new instance of the class. /// protected TestData() : base(typeof(T)) { Type[] typeParams = new Type[] { this.Type }; Type arrayType = this.Type.MakeArrayType(); Type listType = OpenListType.MakeGenericType(typeParams); Type iEnumerableType = OpenIEnumerableType.MakeGenericType(typeParams); Type iQueryableType = OpenIQueryableType.MakeGenericType(typeParams); Type[] typeArrayParams = new Type[] { arrayType }; Type[] typeListParams = new Type[] { listType }; Type[] typeIEnumerableParams = new Type[] { iEnumerableType }; Type[] typeIQueryableParams = new Type[] { iQueryableType }; this.RegisterTestDataVariation(TestDataVariations.AsInstance, this.Type, () => GetTypedTestData()); this.RegisterTestDataVariation(TestDataVariations.AsArray, arrayType, GetTestDataAsArray); this.RegisterTestDataVariation(TestDataVariations.AsIEnumerable, iEnumerableType, GetTestDataAsIEnumerable); this.RegisterTestDataVariation(TestDataVariations.AsIQueryable, iQueryableType, GetTestDataAsIQueryable); this.RegisterTestDataVariation(TestDataVariations.AsList, listType, GetTestDataAsList); } public IEnumerator GetEnumerator() { return (IEnumerator)this.GetTypedTestData().ToList().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)this.GetTypedTestData().ToList().GetEnumerator(); } /// /// Gets the test data as an array. /// /// An array of test data of the given type. public T[] GetTestDataAsArray() { return this.GetTypedTestData().ToArray(); } /// /// Gets the test data as a . /// /// A of test data of the given type. public List GetTestDataAsList() { return this.GetTypedTestData().ToList(); } /// /// Gets the test data as an . /// /// An of test data of the given type. public IEnumerable GetTestDataAsIEnumerable() { return this.GetTypedTestData().AsEnumerable(); } /// /// Gets the test data as an . /// /// An of test data of the given type. public IQueryable GetTestDataAsIQueryable() { return this.GetTypedTestData().AsQueryable(); } /// /// Must be implemented by derived types to return test data of the given type. /// /// Test data of the given type. protected abstract IEnumerable GetTypedTestData(); } }