public void UnifyStructuralEquivalence_Pass() { var rt1 = RuntimeCompiler.CreateRecordType( new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(string) } }, true); var rt2 = RuntimeCompiler.CreateRecordType( new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(string) } }, true); var typeToSlim = new TypeToTypeSlimConverter(); var slim = typeToSlim.Visit(rt1); var unifier = new TypeUnifier(); Assert.IsTrue(unifier.Unify(rt1, slim)); Assert.IsTrue(unifier.Unify(rt2, slim)); Assert.AreEqual(1, unifier.Entries.Count); Assert.AreSame(rt1, unifier.Entries[slim]); }
public void DataModelTypeUnifier_UnifyFails_ThrowsInvalidOperation() { var record = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "zoo", typeof(int) } }, valueEquality: true); Assert.ThrowsException <InvalidOperationException>(() => Unify(typeof(IAsyncReactiveQbservable <>).MakeGenericType(record), typeof(IReactiveQbservable <Foo>)).ToArray()); }
public void DataModelTypeUnifier_UnifyRecursive() { var record = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "bar", typeof(int) } }, valueEquality: true); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQbservable <>).MakeGenericType(typeof(IAsyncReactiveQbservable <>).MakeGenericType(record)), typeof(IReactiveQbservable <IReactiveQbservable <Foo> >)).ToArray().Length); }
public void RecordType_PropertyAttribute_NoMatchingConstructor() { var props = new[] { new StructuralFieldDeclaration("bar", typeof(string), new List <CustomAttributeDeclaration> { new CustomAttributeDeclaration(typeof(FooAttribute), new List <object> { 0 }.AsReadOnly()) }.AsReadOnly()) }; Assert.ThrowsException <InvalidOperationException>(() => RuntimeCompiler.CreateRecordType(props, valueEquality: true)); }
public void DataModelTypeUnifier_UnifyParameterized() { var record1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "bar", typeof(int) } }, valueEquality: true); var record2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "qux", typeof(int) } }, valueEquality: true); Assert.AreEqual(2, Unify(typeof(Func <,>).MakeGenericType(record2, typeof(IAsyncReactiveQbservable <>).MakeGenericType(record1)), typeof(Func <Bar, IReactiveQbservable <Foo> >)).ToArray().Length); }
public void TypeSlimDerivationVisitor_RecordType_WithValueEqualitySemantics() { var rec = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("bar", typeof(int)) }, valueEquality: true); var bar = rec.GetProperty("bar"); var m = Expression.MemberInit(Expression.New(rec), Expression.Bind(bar, Expression.Constant(42))); RoundtripAndAssertStructural(m); }
public void DataModelTypeUnifier_UnifyDataModelFromStructural() { var record = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "bar", typeof(int) } }, valueEquality: true); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQbservable <>).MakeGenericType(record), typeof(IReactiveQbservable <Foo>)).ToArray().Length); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQbserver <>).MakeGenericType(record), typeof(IReactiveQbserver <Foo>)).ToArray().Length); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQubjectFactory <,>).MakeGenericType(record, record), typeof(IReactiveQubjectFactory <Foo, Foo>)).ToArray().Length); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQubscriptionFactory <>).MakeGenericType(record), typeof(IReactiveQubscriptionFactory <Foo>)).ToArray().Length); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQubject <>).MakeGenericType(record), typeof(IReactiveQubject <Foo>)).ToArray().Length); Assert.AreEqual(1, Unify(typeof(IAsyncReactiveQubject <,>).MakeGenericType(record, record), typeof(IReactiveQubject <Foo, Foo>)).ToArray().Length); }
public void RecordType_Create_StructuralFields() { foreach (var eq in new[] { true, false }) { RecordType_Impl(() => { return(RuntimeCompiler.CreateRecordType(new[] { new StructuralFieldDeclaration("Name", typeof(string)), new StructuralFieldDeclaration("Age", typeof(int)), }, eq)); }, eq); } }
public void RecordType_Create() { foreach (var eq in new[] { true, false }) { RecordType_Impl(() => { return(RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("Name", typeof(string)), new KeyValuePair <string, Type>("Age", typeof(int)), }, eq)); }, eq); } }
public void StructuralTypeEqualityComparer_StructuralNotEquals() { var rt1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) }, }, true); var rt2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(string) }, }, true); var rt3 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(int) } }, true); var at1 = RuntimeCompiler.CreateAnonymousType(new Dictionary <string, Type> { { "Foo", typeof(int) }, }, null); var at2 = RuntimeCompiler.CreateAnonymousType(new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(string) } }, null); var at3 = RuntimeCompiler.CreateAnonymousType(new Dictionary <string, Type> { { "Foo", typeof(int) }, { "Bar", typeof(int) } }, null); var eq = new StructuralTypeEqualityComparer(); Assert.IsFalse(eq.Equals(rt1, rt2)); Assert.IsFalse(eq.Equals(rt2, rt3)); Assert.IsFalse(eq.Equals(at1, at2)); Assert.IsFalse(eq.Equals(at2, at3)); }
public void DataModelTypeUnifier_UnifyStructuralRecursive() { var record1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "bar", typeof(int) } }, valueEquality: true); var record2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "obs", typeof(IAsyncReactiveQbservable <>).MakeGenericType(record1) } }, valueEquality: true); // This test is used for demonstration of how we will need to recurse into structural types to find unifications // Unfortunately, the type unifier is only informed of the expressible variants of the Reactive entity types. It // is not aware of implementation specific types, such as ISubscribable, which would more likely be found in // structural types. Assert.AreEqual(2, Unify(typeof(IAsyncReactiveQbservable <>).MakeGenericType(record2), typeof(IReactiveQbservable <Rec>)).ToArray().Length); }
public void StructuralSubstitutingTypeComparator_AreNotEqual() { var type1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(long) } }, valueEquality: true); var comparer = new StructuralSubstitutingTypeComparator(); Assert.IsFalse(comparer.Equals(type1, type2)); }
public void RecordType_PropertiesAttributes() { var expectedAttributeValue = "bing://foo"; var customAttribute = new CustomAttributeDeclaration(typeof(FooAttribute), new List <object> { expectedAttributeValue }.AsReadOnly()); var props = new[] { new StructuralFieldDeclaration("Foo", typeof(int), new List <CustomAttributeDeclaration> { customAttribute }.AsReadOnly()) }; var type = RuntimeCompiler.CreateRecordType(props, valueEquality: true); var property = type.GetProperty("Foo"); var actualAttribute = property.GetCustomAttribute <FooAttribute>(inherit: false); Assert.IsNotNull(actualAttribute); Assert.AreEqual(expectedAttributeValue, actualAttribute.Uri); }
public void RecordType_Visibility() { var props = new[] { new KeyValuePair <string, Type>("bar", typeof(Bar)) }; var props2 = new[] { new StructuralFieldDeclaration("bar", typeof(string), new List <CustomAttributeDeclaration> { new CustomAttributeDeclaration(typeof(BarAttribute), new List <object>().AsReadOnly()) }.AsReadOnly()) }; var props3 = new[] { new StructuralFieldDeclaration("bar", typeof(Bar)) }; Assert.ThrowsException <InvalidOperationException>(() => RuntimeCompiler.CreateRecordType(props, valueEquality: true)); Assert.ThrowsException <InvalidOperationException>(() => { var rtc = new RuntimeCompiler(); var atb = rtc.GetNewRecordTypeBuilder(); rtc.DefineRecordType(atb, props, valueEquality: true); }); Assert.ThrowsException <InvalidOperationException>(() => RuntimeCompiler.CreateRecordType(props2, valueEquality: true)); Assert.ThrowsException <InvalidOperationException>(() => { var rtc = new RuntimeCompiler(); var atb = rtc.GetNewRecordTypeBuilder(); rtc.DefineRecordType(atb, props2, valueEquality: true); }); Assert.ThrowsException <InvalidOperationException>(() => RuntimeCompiler.CreateRecordType(props3, valueEquality: true)); Assert.ThrowsException <InvalidOperationException>(() => { var rtc = new RuntimeCompiler(); var atb = rtc.GetNewRecordTypeBuilder(); rtc.DefineRecordType(atb, props3, valueEquality: true); }); }
public void ToCSharpString_CompilerGenerated() { var rec = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("bar", typeof(int)) }, valueEquality: true); var exp = Expression.New(rec); Assert.ThrowsException <InvalidOperationException>(() => exp.ToCSharp()); Assert.ThrowsException <InvalidOperationException>(() => exp.ToCSharpString()); Assert.ThrowsException <InvalidOperationException>(() => exp.ToCSharp(allowCompilerGeneratedNames: false)); Assert.ThrowsException <InvalidOperationException>(() => exp.ToCSharpString(allowCompilerGeneratedNames: false)); var cs1 = exp.ToCSharp(allowCompilerGeneratedNames: true); var cs2 = exp.ToCSharpString(allowCompilerGeneratedNames: true); Assert.AreEqual(cs1.Code, cs2); Assert.AreEqual("new " + rec.Name + "()", cs2); }
public void ExpressionEntityTypeAnonymizer_Constants_Simple() { var recType = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("a", typeof(int)), new KeyValuePair <string, Type>("b", typeof(Qux)) }, valueEquality: true); var rec = Activator.CreateInstance(recType); recType.GetProperty("a").SetValue(rec, 42); recType.GetProperty("b").SetValue(rec, new Qux(43)); foreach (var o in new object[] { new Qux(), new Qux(1), new Qux(1) { Foo = "bar" }, new Qux[1], new Qux[] { new Qux(1), new Qux(2) }, new List <Qux> { new Qux(1), new Qux(2) }, new Func <int, int>(x => x), 42, "bar", (Expression <Func <Qux, Qux> >)(x => x), #pragma warning disable IDE0004 // Remove Unnecessary Cast. (Only unnecessary on C# 10 or later.) (Expression <Func <Qux[]> >)(() => new Qux[] { new Qux(123) }), #pragma warning restore IDE0004 // Remove Unnecessary Cast new Tuple <Qux, int>(new Qux(), 42), new { a = 1, b = new Qux(42), c = "bar" }, rec, }) { var eta = new ExpressionEntityTypeAnonymizer(); var res = eta.Apply(Expression.Constant(o)); Assert.IsNotNull(res); // TODO: semantic equivalence checks } }
public void ExpressionSlimEntityTypeRecordizer_Constants_Simple() { var recType = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("a", typeof(int)), new KeyValuePair <string, Type>("b", typeof(Qux)) }, valueEquality: true); var rec = Activator.CreateInstance(recType); recType.GetProperty("a").SetValue(rec, 42); recType.GetProperty("b").SetValue(rec, new Qux(43)); foreach (var o in new object[] { new Qux(), new Qux(1), new Qux(1) { Foo = "bar" }, new Qux[1], new Qux[] { new Qux(1), new Qux(2) }, new List <Qux> { new Qux(1), new Qux(2) }, //new Func<int, int>(x => x), 42, "bar", (Expression <Func <Qux, Qux> >)(x => x), #pragma warning disable IDE0004 // Remove Unnecessary Cast. (Only unnecessary on C# 10 or later.) (Expression <Func <Qux[]> >)(() => new Qux[] { new Qux(123) }), #pragma warning restore IDE0004 // Remove Unnecessary Cast new Tuple <Qux, int>(new Qux(), 42), new { a = 1, b = new Qux(42), c = "bar" }, rec, }) { var res = (ConstantExpression)Roundtrip(Expression.Constant(o)); Assert.IsTrue(ObjectComparator.CreateInstance().Equals(o, res.Value)); } }
public void ExpressionEntityTypeRecordizer_Constants_Simple() { var recType = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("a", typeof(int)), new KeyValuePair <string, Type>("b", typeof(Qux)) }, valueEquality: true); var rec = Activator.CreateInstance(recType); recType.GetProperty("a").SetValue(rec, 42); recType.GetProperty("b").SetValue(rec, new Qux(43)); foreach (var o in new object[] { new Qux(), new Qux(1), new Qux(1) { Foo = "bar" }, new Qux[1], new Qux[] { new Qux(1), new Qux(2) }, new List <Qux> { new Qux(1), new Qux(2) }, new Func <int, int>(x => x), 42, "bar", (Expression <Func <Qux, Qux> >)(x => x), (Expression <Func <Qux[]> >)(() => new Qux[] { new Qux(123) }), new Tuple <Qux, int>(new Qux(), 42), new { a = 1, b = new Qux(42), c = "bar" }, rec, }) { var eta = new ExpressionEntityTypeRecordizer(); var res = (ConstantExpression)eta.Apply(Expression.Constant(o)); Assert.IsTrue(ObjectComparator.CreateInstance().Equals(o, res.Value)); } }
public void StructuralTypeSubstitutionExpressionVisitor_RecordToAnonymous_ThrowsInvalidOperation() { var type1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type2 = RuntimeCompiler.CreateAnonymousType(new Dictionary <string, Type> { { "Foo", typeof(int) } }); var expr = Expression.Constant(Activator.CreateInstance(type1)); var visitor = new StructuralTypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { type1, type2 } }); Assert.ThrowsException <InvalidOperationException>(() => visitor.Visit(expr)); }
public void StructuralSubstitutingTypeComparator_AreEqual() { var type1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var comparer = new StructuralSubstitutingTypeComparator(); Assert.IsTrue(comparer.Equals(type1, type1)); Assert.AreEqual(0, comparer.Substitutions.Count); Assert.IsTrue(comparer.Equals(type1, type2)); Assert.AreEqual(type1, comparer.Substitutions[type2]); Assert.AreEqual(1, comparer.Substitutions.Count); }
public void UnifyManOrBoy_Pass() { var record1 = RuntimeCompiler.CreateRecordType( new Dictionary <string, Type> { { "foo", typeof(int) } }, true); var record2 = RuntimeCompiler.CreateRecordType( new Dictionary <string, Type> { { "bar", record1 }, { "qux", typeof(string) } }, true); var list = typeof(List <>).MakeGenericType(new[] { record2 }); var unifier = new TypeUnifier(); var typeToSlim = new TypeToTypeSlimConverter(); var slimList = typeToSlim.Visit(list); Assert.IsTrue(unifier.Unify(list, slimList)); Assert.AreEqual(2, unifier.Entries.Count); }
public void Test() { AssertEx.ThrowsException <ArgumentNullException>(() => base.Apply(expression: null), ex => Assert.AreEqual("expression", ex.ParamName)); var prop = (PropertyInfo)ReflectionHelpers.InfoOf(() => DateTime.Now); AssertEx.ThrowsException <ArgumentNullException>(() => base.ResolveProperty(originalProperty: null, typeof(int), typeof(int), new[] { typeof(int) }), ex => Assert.AreEqual("originalProperty", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => base.ResolveProperty(prop, declaringType: null, typeof(int), new[] { typeof(int) }), ex => Assert.AreEqual("declaringType", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => base.ResolveProperty(prop, typeof(int), propertyType: null, new[] { typeof(int) }), ex => Assert.AreEqual("propertyType", ex.ParamName)); var anon1 = new { a = 1 }; var anon2 = new { a = 1, b = 2 }; var atyp1 = (StructuralDataType)DataType.FromType(anon1.GetType()); var atyp2 = (StructuralDataType)DataType.FromType(anon2.GetType()); Assert.ThrowsException <InvalidOperationException>(() => base.ConvertConstantStructuralAnonymous(anon1, atyp1, atyp2)); var tupl1 = new Tuple <int>(1); var tupl2 = new Tuple <int, int>(1, 2); var ttyp1 = (StructuralDataType)DataType.FromType(tupl1.GetType()); var ttyp2 = (StructuralDataType)DataType.FromType(tupl2.GetType()); Assert.ThrowsException <InvalidOperationException>(() => base.ConvertConstantStructuralTuple(tupl1, ttyp1, ttyp2)); var rcrt1 = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("a", typeof(int)) }, valueEquality: true); var rcrt2 = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("a", typeof(int)), new KeyValuePair <string, Type>("b", typeof(int)) }, valueEquality: true); var rtyp1 = (StructuralDataType)DataType.FromType(rcrt1); var rtyp2 = (StructuralDataType)DataType.FromType(rcrt2); var rcrd1 = Activator.CreateInstance(rcrt1); Assert.ThrowsException <InvalidOperationException>(() => base.ConvertConstantStructuralRecord(rcrd1, rtyp1, rtyp2)); var func1 = new Func <int>(() => 1); var func2 = new Func <int, int>(x => x); var ftyp1 = (FunctionDataType)DataType.FromType(func1.GetType()); var ftyp2 = (FunctionDataType)DataType.FromType(func2.GetType()); Assert.ThrowsException <InvalidOperationException>(() => base.ConvertConstantFunction(func1, ftyp1, ftyp2)); }
public void StructuralTypeSubstitutionExpressionVisitor_Record_Success() { var type1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var expr = Expression.Constant(Activator.CreateInstance(type1)); var visitor = new StructuralTypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { type1, type2 } }); var result = visitor.Visit(expr); Assert.AreEqual(type2, result.Type); }
public void StructuralSubstitutingTypeComparator_DoubleMapping_ThrowsInvalidOperation() { var type1 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type2 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var type3 = RuntimeCompiler.CreateRecordType(new Dictionary <string, Type> { { "Foo", typeof(int) } }, valueEquality: true); var comparer = new StructuralSubstitutingTypeComparator(); Assert.IsTrue(comparer.Equals(type1, type2)); Assert.ThrowsException <InvalidOperationException>(() => comparer.Equals(type3, type2)); }
public void DataTypeChecker_CheckTypes_Success() { var anon = new { x = 1, b = new bool[] { true }, c = new List <int[]>() }; var rec = RuntimeCompiler.CreateRecordType(new[] { new KeyValuePair <string, Type>("bar", typeof(int)) }, valueEquality: true); foreach (var t in new[] { typeof(Unit), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), typeof(bool), typeof(char), typeof(string), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid), typeof(Uri), typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), typeof(float?), typeof(double?), typeof(decimal?), typeof(bool?), typeof(char?), typeof(DateTime?), typeof(DateTimeOffset?), typeof(TimeSpan?), typeof(Guid?), typeof(void), typeof(ConsoleColor), typeof(ConsoleColor?), typeof(int[]), typeof(string[][]), typeof(bool[][][]), typeof(List <int>), typeof(List <bool?[]>), typeof(IList <int>), typeof(IList <bool?[]>), typeof(Tuple <short>), typeof(Tuple <short, byte>), typeof(Tuple <short, byte, double[]>), typeof(Tuple <short, byte, double[], decimal>), typeof(Tuple <short, byte, double[], decimal, long?>), typeof(Tuple <short, byte, double[], decimal, long?, float>), typeof(Tuple <short, byte, double[], decimal, long?, float, bool>), typeof(Tuple <short, byte, double[], decimal, long?, float, bool, Tuple <char> >), typeof(Tuple <short, byte, double[], decimal, long?, float, bool, Tuple <char, string> >), typeof(Func <int>), typeof(Func <int, int>), typeof(Func <int, string, bool>), typeof(Action), typeof(Action <int>), typeof(Expression), typeof(Expression <Func <int> >), typeof(Func <int?, Func <List <double[]>, Tuple <string, bool[]> > >), typeof(Bar), typeof(Bar[]), anon.GetType(), rec, }) { { Assert.IsTrue(DataType.TryCheck(t, out var err), "Type check failed for: " + t.Name); Assert.AreEqual(0, err.Count, "Type check failed for: " + t.Name); } { Assert.IsTrue(DataType.TryCheck(t, allowCycles: false, out var err), "Type check failed for: " + t.Name); Assert.AreEqual(0, err.Count, "Type check failed for: " + t.Name); } { Assert.IsTrue(DataType.TryCheck(t, allowCycles: true, out var err), "Type check failed for: " + t.Name); Assert.AreEqual(0, err.Count, "Type check failed for: " + t.Name); } DataType.Check(t); Assert.IsNotNull(DataType.FromType(t)); Assert.IsNotNull(DataType.FromType(t, allowCycles: false)); Assert.IsNotNull(DataType.FromType(t, allowCycles: true)); Assert.IsTrue(DataType.TryFromType(t, out _)); Assert.IsTrue(DataType.TryFromType(t, allowCycles: false, out _)); Assert.IsTrue(DataType.TryFromType(t, allowCycles: true, out _)); } }
public void CreateRecordType_ArgumentChecks() { AssertEx.ThrowsException <ArgumentNullException>(() => RuntimeCompiler.CreateRecordType(properties: (KeyValuePair <string, Type>[])null, valueEquality: true), ex => Assert.AreEqual("properties", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => RuntimeCompiler.CreateRecordType(properties: (StructuralFieldDeclaration[])null, valueEquality: true), ex => Assert.AreEqual("properties", ex.ParamName)); }