chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using NUnit.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Emit;
 
namespace OpenTap.UnitTests
{
    public class TypeDataTest
    {
        public class IntObject
        {
            public int SomeInt { get; set; }
        }
 
        [Browsable(false)]
        class Class1 { }
        class Class2 : Class1 { }
        [Test]
        public void InheritedAttributesTest()
        {
            var type1 = TypeData.FromType(typeof(Class1));
            var type2 = TypeData.FromType(typeof(Class2));
            Assert.IsEmpty(type2.Attributes);
            Assert.IsTrue(type1.HasAttribute<BrowsableAttribute>());
            Assert.IsTrue(type2.BaseType.HasAttribute<BrowsableAttribute>());
        }
 
        [Test]
        public void SettingPropertyToInvalidType()
        {
            var obj = new IntObject();
            var typeData = TypeData.GetTypeData(obj);
            var memberData = typeData.GetMember(nameof(IntObject.SomeInt));
            Assert.DoesNotThrow(() => memberData.SetValue(obj, 123));
            // PropertyInfo.SetValue(xx, null) does not throw an exception for value types.
            // https://docs.microsoft.com/de-de/dotnet/api/system.reflection.propertyinfo.setvalue
            Assert.DoesNotThrow(() => memberData.SetValue(obj, null));
        }
 
        
        [Test]
        public void ValueTypeCanCreateInstanceTest()
        {
            var types = new[]
            {
                typeof(int),
                typeof(double),
                typeof(DateTime),
                typeof(TimeSpan),
                typeof(KeyValuePair<string, string>),
            };
            
            foreach (var type in types)
            {
                var td = TypeData.FromType(type);
                Assert.AreEqual(type.IsValueType, td.IsValueType);
                Assert.IsTrue(td.CanCreateInstance, $"Expected type {type.FullName} to be constructable.");
                Assert.AreEqual(Activator.CreateInstance(type), td.CreateInstance());
            }
        }
 
        [Test]
        public void DynamicTypeBrowsableFalse()
        {
            // Create an empty dynamic type which is public.
            var assemblyName = "TestAssembly";
            var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run);
            var moduleBuilder = assemblyBuilder.DefineDynamicModule("TestModule");
            TypeBuilder typeBuilder = moduleBuilder.DefineType("TestType",
                TypeAttributes.Public | TypeAttributes.Class,
                typeof(object),Array.Empty<Type>());
            var type = typeBuilder.CreateType();
            var td = TypeData.FromType(type);
            
            // A problem caused these kinds of type data to have IsBrowsable set to false, even though it does not 
            // even have a BrowsableAttribute assigned.
            Assert.IsTrue(td.IsBrowsable);
 
            foreach (var browsable in new[] { true, false })
            {
                TypeBuilder typeBuilder2 = moduleBuilder.DefineType("TestType2_" + browsable,
                    TypeAttributes.Public | TypeAttributes.Class,
                    typeof(object), Array.Empty<Type>());
                CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder(
                    typeof(BrowsableAttribute).GetConstructor(new[] { typeof(bool) }), new object[] { browsable });
                typeBuilder2.SetCustomAttribute(attrBuilder);
 
                var td2 = TypeData.FromType(typeBuilder2.CreateType());
                Assert.AreEqual(browsable, td2.IsBrowsable);
            }
 
        }
 
        class MultipleEnumerableInterfacesList : List<double>, IEnumerable<int>
        {
            IEnumerator<int> IEnumerable<int>.GetEnumerator()
            {
                foreach (var value in this)
                    yield return (int)value;
            }
        }
 
        class MultipleEnumerableInterfacesList2 : IEnumerable<double>, IEnumerable<int>, IEnumerable<string>
        {
            IEnumerator<string> IEnumerable<string>.GetEnumerator()
            {
                yield return "1";
            }
 
            IEnumerator<int> IEnumerable<int>.GetEnumerator()
            {
                yield return 1;
            }
 
            IEnumerator<double> IEnumerable<double>.GetEnumerator()
            {
                yield return 1.0;
            }
 
            IEnumerator IEnumerable.GetEnumerator()
            {
                yield return 1.0;
            }
        }
        
        [Test]
        public void TestMultipleEnumerableInterfaceImplementations()
        {
            Assert.IsNull(TypeData.FromType(typeof(MultipleEnumerableInterfacesList)).ElementType);
            Assert.IsNull(TypeData.FromType(typeof(MultipleEnumerableInterfacesList2)).ElementType);
            Assert.AreEqual(TypeData.FromType(typeof(List<double>)).AsTypeData().ElementType.Type, typeof(double));
            Assert.AreEqual(TypeData.FromType(typeof(IEnumerable<double>)).AsTypeData().ElementType.Type, typeof(double));
        }
    }
}