1 using System;
2 using System.IO;
3 using System.Collections.Generic;
4 using System.Globalization;
5 using System.Reflection;
6 using System.Reflection.Emit;
7 using System.Runtime.InteropServices;
8 using System.Configuration.Assemblies;
9 using NUnit.Framework;
10 
11 namespace MonoTests.System.Reflection.Emit
12 {
13 
14 [TestFixture]
15 public class SaveTest
16 {
17 	// strongname generated using "sn -k unit.snk"
18 	static byte[] strongName = {
19 		0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32,
20 		0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7F, 0x7C, 0xEA, 0x4A,
21 		0x28, 0x33, 0xD8, 0x3C, 0x86, 0x90, 0x86, 0x91, 0x11, 0xBB, 0x30, 0x0D,
22 		0x3D, 0x69, 0x04, 0x4C, 0x48, 0xF5, 0x4F, 0xE7, 0x64, 0xA5, 0x82, 0x72,
23 		0x5A, 0x92, 0xC4, 0x3D, 0xC5, 0x90, 0x93, 0x41, 0xC9, 0x1D, 0x34, 0x16,
24 		0x72, 0x2B, 0x85, 0xC1, 0xF3, 0x99, 0x62, 0x07, 0x32, 0x98, 0xB7, 0xE4,
25 		0xFA, 0x75, 0x81, 0x8D, 0x08, 0xB9, 0xFD, 0xDB, 0x00, 0x25, 0x30, 0xC4,
26 		0x89, 0x13, 0xB6, 0x43, 0xE8, 0xCC, 0xBE, 0x03, 0x2E, 0x1A, 0x6A, 0x4D,
27 		0x36, 0xB1, 0xEB, 0x49, 0x26, 0x6C, 0xAB, 0xC4, 0x29, 0xD7, 0x8F, 0x25,
28 		0x11, 0xA4, 0x7C, 0x81, 0x61, 0x97, 0xCB, 0x44, 0x2D, 0x80, 0x49, 0x93,
29 		0x48, 0xA7, 0xC9, 0xAB, 0xDB, 0xCF, 0xA3, 0x34, 0xCB, 0x6B, 0x86, 0xE0,
30 		0x4D, 0x27, 0xFC, 0xA7, 0x4F, 0x36, 0xCA, 0x13, 0x42, 0xD3, 0x83, 0xC4,
31 		0x06, 0x6E, 0x12, 0xE0, 0xA1, 0x3D, 0x9F, 0xA9, 0xEC, 0xD1, 0xC6, 0x08,
32 		0x1B, 0x3D, 0xF5, 0xDB, 0x4C, 0xD4, 0xF0, 0x2C, 0xAA, 0xFC, 0xBA, 0x18,
33 		0x6F, 0x48, 0x7E, 0xB9, 0x47, 0x68, 0x2E, 0xF6, 0x1E, 0x67, 0x1C, 0x7E,
34 		0x0A, 0xCE, 0x10, 0x07, 0xC0, 0x0C, 0xAD, 0x5E, 0xC1, 0x53, 0x70, 0xD5,
35 		0xE7, 0x25, 0xCA, 0x37, 0x5E, 0x49, 0x59, 0xD0, 0x67, 0x2A, 0xBE, 0x92,
36 		0x36, 0x86, 0x8A, 0xBF, 0x3E, 0x17, 0x04, 0xFB, 0x1F, 0x46, 0xC8, 0x10,
37 		0x5C, 0x93, 0x02, 0x43, 0x14, 0x96, 0x6A, 0xD9, 0x87, 0x17, 0x62, 0x7D,
38 		0x3A, 0x45, 0xBE, 0x35, 0xDE, 0x75, 0x0B, 0x2A, 0xCE, 0x7D, 0xF3, 0x19,
39 		0x85, 0x4B, 0x0D, 0x6F, 0x8D, 0x15, 0xA3, 0x60, 0x61, 0x28, 0x55, 0x46,
40 		0xCE, 0x78, 0x31, 0x04, 0x18, 0x3C, 0x56, 0x4A, 0x3F, 0xA4, 0xC9, 0xB1,
41 		0x41, 0xED, 0x22, 0x80, 0xA1, 0xB3, 0xE2, 0xC7, 0x1B, 0x62, 0x85, 0xE4,
42 		0x81, 0x39, 0xCB, 0x1F, 0x95, 0xCC, 0x61, 0x61, 0xDF, 0xDE, 0xF3, 0x05,
43 		0x68, 0xB9, 0x7D, 0x4F, 0xFF, 0xF3, 0xC0, 0x0A, 0x25, 0x62, 0xD9, 0x8A,
44 		0x8A, 0x9E, 0x99, 0x0B, 0xFB, 0x85, 0x27, 0x8D, 0xF6, 0xD4, 0xE1, 0xB9,
45 		0xDE, 0xB4, 0x16, 0xBD, 0xDF, 0x6A, 0x25, 0x9C, 0xAC, 0xCD, 0x91, 0xF7,
46 		0xCB, 0xC1, 0x81, 0x22, 0x0D, 0xF4, 0x7E, 0xEC, 0x0C, 0x84, 0x13, 0x5A,
47 		0x74, 0x59, 0x3F, 0x3E, 0x61, 0x00, 0xD6, 0xB5, 0x4A, 0xA1, 0x04, 0xB5,
48 		0xA7, 0x1C, 0x29, 0xD0, 0xE1, 0x11, 0x19, 0xD7, 0x80, 0x5C, 0xEE, 0x08,
49 		0x15, 0xEB, 0xC9, 0xA8, 0x98, 0xF5, 0xA0, 0xF0, 0x92, 0x2A, 0xB0, 0xD3,
50 		0xC7, 0x8C, 0x8D, 0xBB, 0x88, 0x96, 0x4F, 0x18, 0xF0, 0x8A, 0xF9, 0x31,
51 		0x9E, 0x44, 0x94, 0x75, 0x6F, 0x78, 0x04, 0x10, 0xEC, 0xF3, 0xB0, 0xCE,
52 		0xA0, 0xBE, 0x7B, 0x25, 0xE1, 0xF7, 0x8A, 0xA8, 0xD4, 0x63, 0xC2, 0x65,
53 		0x47, 0xCC, 0x5C, 0xED, 0x7D, 0x8B, 0x07, 0x4D, 0x76, 0x29, 0x53, 0xAC,
54 		0x27, 0x8F, 0x5D, 0x78, 0x56, 0xFA, 0x99, 0x45, 0xA2, 0xCC, 0x65, 0xC4,
55 		0x54, 0x13, 0x9F, 0x38, 0x41, 0x7A, 0x61, 0x0E, 0x0D, 0x34, 0xBC, 0x11,
56 		0xAF, 0xE2, 0xF1, 0x8B, 0xFA, 0x2B, 0x54, 0x6C, 0xA3, 0x6C, 0x09, 0x1F,
57 		0x0B, 0x43, 0x9B, 0x07, 0x95, 0x83, 0x3F, 0x97, 0x99, 0x89, 0xF5, 0x51,
58 		0x41, 0xF6, 0x8E, 0x5D, 0xEF, 0x6D, 0x24, 0x71, 0x41, 0x7A, 0xAF, 0xBE,
59 		0x81, 0x71, 0xAB, 0x76, 0x2F, 0x1A, 0x5A, 0xBA, 0xF3, 0xA6, 0x65, 0x7A,
60 		0x80, 0x50, 0xCE, 0x23, 0xC3, 0xC7, 0x53, 0xB0, 0x7C, 0x97, 0x77, 0x27,
61 		0x70, 0x98, 0xAE, 0xB5, 0x24, 0x66, 0xE1, 0x60, 0x39, 0x41, 0xDA, 0x54,
62 		0x01, 0x64, 0xFB, 0x10, 0x33, 0xCE, 0x8B, 0xBE, 0x27, 0xD4, 0x21, 0x57,
63 		0xCC, 0x0F, 0x1A, 0xC1, 0x3D, 0xF3, 0xCC, 0x39, 0xF0, 0x2F, 0xAE, 0xF1,
64 		0xC0, 0xCD, 0x3B, 0x23, 0x87, 0x49, 0x7E, 0x40, 0x32, 0x6A, 0xD3, 0x96,
65 		0x4A, 0xE5, 0x5E, 0x6E, 0x26, 0xFD, 0x8A, 0xCF, 0x7E, 0xFC, 0x37, 0xDE,
66 		0x39, 0x0C, 0x53, 0x81, 0x75, 0x08, 0xAF, 0x6B, 0x39, 0x6C, 0xFB, 0xC9,
67 		0x79, 0xC0, 0x9B, 0x5F, 0x34, 0x86, 0xB2, 0xDE, 0xC4, 0x19, 0x84, 0x5F,
68 		0x0E, 0xED, 0x9B, 0xB8, 0xD3, 0x17, 0xDA, 0x78 };
69 
70 	string tempDir = Path.Combine (Path.GetTempPath (), typeof (SaveTest).FullName);
71 
72 	[SetUp]
SetUp()73 	protected void SetUp ()
74 	{
75 		var rand = new Random ();
76 		string basePath = tempDir;
77 		while (Directory.Exists (tempDir))
78 			tempDir = Path.Combine (basePath, rand.Next ().ToString ());
79 		Directory.CreateDirectory (tempDir);
80 	}
81 
82 	[TearDown]
TearDown()83 	protected void TearDown ()
84 	{
85 		try {
86 			// This throws an exception under MS.NET, since the directory contains loaded
87 			// assemblies.
88 			Directory.Delete (tempDir, true);
89 		} catch (Exception) {
90 		}
91 	}
92 
93 	[Test]
Save()94 	public void Save () {
95 
96 		//
97 		// Create a test assembly, write it to disk, then read it back
98 		//
99 		AssemblyName aname = new AssemblyName ("h");
100 		// AssemblyName properties
101 		aname.ProcessorArchitecture = ProcessorArchitecture.X86;
102 		aname.Version = new Version (1, 2, 3, 4);
103 		aname.CultureInfo = new CultureInfo ("en");
104 		aname.Flags = AssemblyNameFlags.Retargetable;
105 		aname.HashAlgorithm = AssemblyHashAlgorithm.SHA256;
106 		var ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave, tempDir);
107 
108 		string strongfile = Path.Combine (tempDir, "strongname.snk");
109 		using (FileStream fs = File.OpenWrite (strongfile)) {
110 			fs.Write (strongName, 0, strongName.Length);
111 			fs.Close ();
112 		}
113 		ab.SetCustomAttribute (new CustomAttributeBuilder (typeof (AssemblyKeyFileAttribute).GetConstructor (new Type [] { typeof (string) }), new object [] { strongfile }));
114 		ab.SetCustomAttribute (new CustomAttributeBuilder (typeof (AssemblyDelaySignAttribute).GetConstructor (new Type [] { typeof (bool) }), new object [] { true }));
115 
116 		var cattrb = new CustomAttributeBuilder (typeof (AttributeUsageAttribute).GetConstructor (new Type [] { typeof (AttributeTargets) }), new object [] { AttributeTargets.Class },
117 												 new PropertyInfo[] { typeof (AttributeUsageAttribute).GetProperty ("AllowMultiple") },
118 												 new object[] { true },
119 												 new FieldInfo [0], new object [0]);
120 		ab.SetCustomAttribute (cattrb);
121 
122 		var moduleb = ab.DefineDynamicModule ("h.exe", "h.exe");
123 		moduleb.SetCustomAttribute (cattrb);
124 
125 		TypeBuilder iface1 = moduleb.DefineType ("iface1", TypeAttributes.Public|TypeAttributes.Interface, typeof (object));
126 		iface1.CreateType ();
127 
128 		// Interfaces, attributes, class size, packing size
129 		TypeBuilder tb1 = moduleb.DefineType ("type1", TypeAttributes.Public|TypeAttributes.SequentialLayout, typeof (object), PackingSize.Size2, 16);
130 		tb1.AddInterfaceImplementation (iface1);
131 		tb1.AddInterfaceImplementation (typeof (IComparable));
132 		tb1.SetCustomAttribute (cattrb);
133 		tb1.CreateType ();
134 
135 		// Nested type
136 		TypeBuilder tb_nested = tb1.DefineNestedType ("type_nested", TypeAttributes.NestedPublic, typeof (object));
137 		tb_nested.CreateType ();
138 
139 		// Generics
140 		TypeBuilder tbg = moduleb.DefineType ("gtype1", TypeAttributes.Public, typeof (object));
141 		var gparams = tbg.DefineGenericParameters ("K", "T");
142 		// Constraints
143 		gparams [0].SetBaseTypeConstraint (null);
144 		gparams [0].SetInterfaceConstraints (new Type [] { typeof (IComparable) });
145 		gparams [0].SetCustomAttribute (cattrb);
146 		gparams [1].SetBaseTypeConstraint (tbg);
147 		// Type param
148 		tbg.DefineField ("field_gparam", tbg.GetGenericArguments () [0], FieldAttributes.Public|FieldAttributes.Static);
149 		// Open type
150 		tbg.DefineField ("field_open", typeof (List<>).MakeGenericType (new Type [] { tbg.GetGenericArguments () [1] }), FieldAttributes.Public|FieldAttributes.Static);
151 		tbg.CreateType ();
152 
153 		TypeBuilder tbg2 = moduleb.DefineType ("gtype2", TypeAttributes.Public, typeof (object));
154 		tbg2.DefineGenericParameters ("K", "T");
155 		tbg2.CreateType ();
156 
157 		TypeBuilder tb3 = moduleb.DefineType ("type3", TypeAttributes.Public, typeof (object));
158 		// Nested type
159 		tb3.DefineField ("field_nested", tb_nested, FieldAttributes.Public|FieldAttributes.Static);
160 		// Nested type ref
161 		tb3.DefineField ("field_nested_ref", typeof (TimeZoneInfo.AdjustmentRule), FieldAttributes.Public|FieldAttributes.Static);
162 		// Primitive types
163 		tb3.DefineField ("field_int", typeof (int), FieldAttributes.Public|FieldAttributes.Static);
164 		// Typeref array
165 		tb3.DefineField ("field_array_typeref", typeof (object[]), FieldAttributes.Public|FieldAttributes.Static);
166 		// Type szarray
167 		tb3.DefineField ("field_szarray", tb1.MakeArrayType (), FieldAttributes.Public|FieldAttributes.Static);
168 		// Multi-dim non szarray
169 		tb3.DefineField ("field_non_szarray", Array.CreateInstance (typeof (int), new int [] { 10 }, new int [] { 1 }).GetType (), FieldAttributes.Public|FieldAttributes.Static);
170 		// Multi-dim array
171 		tb3.DefineField ("field_multi_dim_array", Array.CreateInstance (typeof (int), new int [] { 10, 10 }, new int [] { 1, 1 }).GetType (), FieldAttributes.Public|FieldAttributes.Static);
172 		// Type pointer
173 		tb3.DefineField ("field_pointer", tb1.MakePointerType (), FieldAttributes.Public|FieldAttributes.Static);
174 		// Generic instance
175 		tb3.DefineField ("field_ginst", typeof (List<int>), FieldAttributes.Public|FieldAttributes.Static);
176 		// Generic instance of tbuilder
177 		tb3.DefineField ("field_ginst_tbuilder", tbg2.MakeGenericType (new Type [] { typeof (int), typeof (string) }), FieldAttributes.Public|FieldAttributes.Static);
178 		tb3.CreateType ();
179 
180 		// Fields
181 		TypeBuilder tb_fields = moduleb.DefineType ("type4", TypeAttributes.Public, typeof (object));
182 		// Field with a constant
183 		tb_fields.DefineField ("field_int", typeof (int), FieldAttributes.Public|FieldAttributes.Static|FieldAttributes.HasDefault).SetConstant (42);
184 		// Field with an offset
185 		tb_fields.DefineField ("field_offset", typeof (int), FieldAttributes.Public|FieldAttributes.Static).SetOffset (64);
186 		// Modreq/modopt
187 		tb_fields.DefineField ("field_modopt", typeof (int), new Type [] { typeof (int) }, new Type [] { typeof (uint) }, FieldAttributes.Public|FieldAttributes.Static);
188 		// Marshal
189 		var fb = tb_fields.DefineField ("field_marshal1", typeof (int), FieldAttributes.Public);
190 		fb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.U4 }));
191 		fb = tb_fields.DefineField ("field_marshal_byval_array", typeof (int), FieldAttributes.Public);
192 		fb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.ByValArray },
193 														   new FieldInfo[] { typeof (MarshalAsAttribute).GetField ("SizeConst") },
194 														   new object[] { 16 }));
195 		fb = tb_fields.DefineField ("field_marshal_byval_tstr", typeof (int), FieldAttributes.Public);
196 		fb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.ByValTStr },
197 														   new FieldInfo[] { typeof (MarshalAsAttribute).GetField ("SizeConst") },
198 														   new object[] { 16 }));
199 #if false
200 		fb = tb_fields.DefineField ("field_marshal_custom", typeof (int), FieldAttributes.Public);
201 		fb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.CustomMarshaler },
202 														   new FieldInfo[] { typeof (MarshalAsAttribute).GetField ("MarshalTypeRef"),
203 																			 typeof (MarshalAsAttribute).GetField ("MarshalCookie") },
204 														   new object [] { typeof (object), "Cookie" }));
205 #endif
206 		// Cattr
207 		fb = tb_fields.DefineField ("field_cattr", typeof (int), FieldAttributes.Public|FieldAttributes.Static);
208 		fb.SetCustomAttribute (cattrb);
209 		tb_fields.CreateType ();
210 
211 		// Data
212 		moduleb.DefineUninitializedData ("data1", 16, FieldAttributes.Public);
213 		moduleb.DefineInitializedData ("data2", new byte[] { 1, 2, 3, 4, 5, 6 }, FieldAttributes.Public);
214 
215 		// Methods and signatures
216 		TypeBuilder tb5 = moduleb.DefineType ("type_methods", TypeAttributes.Public, typeof (object));
217 		// .ctor
218 		var cmods_req_1 = new Type [] { typeof (object) };
219 		var cmods_opt_1 = new Type [] { typeof (int) };
220 		var ctorb = tb5.DefineConstructor (MethodAttributes.Public, CallingConventions.VarArgs, new Type [] { typeof (int), typeof (object) }, new Type[][] { cmods_req_1, null }, new Type [][] { cmods_opt_1, null });
221 		ctorb.SetImplementationFlags (MethodImplAttributes.NoInlining);
222 		ctorb.GetILGenerator ().Emit (OpCodes.Ret);
223 		// Parameters
224 		var paramb = ctorb.DefineParameter (1, ParameterAttributes.None, "param1");
225 		paramb.SetConstant (16);
226 		paramb.SetCustomAttribute (cattrb);
227 		paramb = ctorb.DefineParameter (2, ParameterAttributes.Out, "param2");
228 		//paramb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.U4 }));
229 		// .cctor
230 		var ctorb2 = tb5.DefineConstructor (MethodAttributes.Public|MethodAttributes.Static, CallingConventions.Standard, new Type [] { typeof (int), typeof (object) });
231 		ctorb2.GetILGenerator ().Emit (OpCodes.Ret);
232 		// method
233 		var mb = tb5.DefineMethod ("method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), cmods_req_1, cmods_opt_1, new Type [] { typeof (int), typeof (object) }, new Type [][] { cmods_req_1, null }, new Type [][] { cmods_opt_1, null });
234 		mb.SetImplementationFlags (MethodImplAttributes.NoInlining);
235 		mb.GetILGenerator ().Emit (OpCodes.Ret);
236 		gparams = mb.DefineGenericParameters ("K", "T");
237 		// Constraints
238 		gparams [0].SetBaseTypeConstraint (null);
239 		gparams [0].SetInterfaceConstraints (new Type [] { typeof (IComparable) });
240 		paramb = mb.DefineParameter (1, ParameterAttributes.None, "param1");
241 		paramb.SetConstant (16);
242 		paramb = mb.DefineParameter (2, ParameterAttributes.Out, "param2");
243 		//paramb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.U4 }));
244 		// return value
245 		paramb = mb.DefineParameter (0, ParameterAttributes.None, "ret");
246 		//paramb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MarshalAsAttribute).GetConstructor (new Type [] { typeof (UnmanagedType) }), new object [] { UnmanagedType.U4 }));
247 		paramb.SetCustomAttribute (cattrb);
248 		// override method
249 		tb5.AddInterfaceImplementation (typeof (IComparable));
250 		mb = tb5.DefineMethod ("method_override", MethodAttributes.Public|MethodAttributes.Virtual, CallingConventions.Standard|CallingConventions.HasThis, typeof (int), new Type [] { typeof (object) });
251 		mb.GetILGenerator ().Emit (OpCodes.Ret);
252 		tb5.DefineMethodOverride (mb, typeof (IComparable).GetMethod ("CompareTo"));
253 		tb5.CreateType ();
254 
255 		// Properties
256 		TypeBuilder tb_properties = moduleb.DefineType ("type_properties", TypeAttributes.Public, typeof (object));
257 		var mb_get = tb_properties.DefineMethod ("get_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
258 		mb_get.GetILGenerator ().Emit (OpCodes.Ret);
259 		var mb_set = tb_properties.DefineMethod ("set_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
260 		mb_set.GetILGenerator ().Emit (OpCodes.Ret);
261 		var mb_other = tb_properties.DefineMethod ("other_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
262 		mb_other.GetILGenerator ().Emit (OpCodes.Ret);
263 		var propertyb = tb_properties.DefineProperty ("AProperty", PropertyAttributes.HasDefault, typeof (int), new Type[] { typeof (object) });
264 		propertyb.SetCustomAttribute (cattrb);
265 		propertyb.SetConstant (1);
266 		propertyb.SetGetMethod (mb_get);
267 		propertyb.SetSetMethod (mb_set);
268 		propertyb.AddOtherMethod (mb_other);
269 		tb_properties.CreateType ();
270 
271 		// Events
272 		TypeBuilder tb_events = moduleb.DefineType ("type_events", TypeAttributes.Public, typeof (object));
273 		var mb_add = tb_events.DefineMethod ("add_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
274 		mb_add.GetILGenerator ().Emit (OpCodes.Ret);
275 		var mb_raise = tb_events.DefineMethod ("raise_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
276 		mb_raise.GetILGenerator ().Emit (OpCodes.Ret);
277 		var mb_remove = tb_events.DefineMethod ("remove_method1", MethodAttributes.Public, CallingConventions.Standard, typeof (int), new Type [] { });
278 		mb_remove.GetILGenerator ().Emit (OpCodes.Ret);
279 		var eventb = tb_events.DefineEvent ("Event1", EventAttributes.SpecialName, typeof (int));
280 		eventb.SetCustomAttribute (cattrb);
281 		eventb.SetAddOnMethod (mb_add);
282 		eventb.SetRaiseMethod (mb_raise);
283 		eventb.SetRemoveOnMethod (mb_remove);
284 		tb_events.CreateType ();
285 
286 		ab.Save ("h.exe");
287 
288 		// Read the assembly and check data
289 		Assembly a = Assembly.LoadFrom (Path.Combine (tempDir, "h.exe"));
290 		Assert.IsTrue (a != ab);
291 		CheckAssembly (a);
292 	}
293 
CheckCattr(ICustomAttributeProvider obj)294 	void CheckCattr (ICustomAttributeProvider obj) {
295 		var cattrs = obj.GetCustomAttributes (typeof (AttributeUsageAttribute), false);
296 		Assert.AreEqual (1, cattrs.Length);
297 		var cattr = (AttributeUsageAttribute)cattrs [0];
298 		Assert.AreEqual (AttributeTargets.Class, cattr.ValidOn);
299 		Assert.IsTrue (cattr.AllowMultiple);
300 	}
301 
CheckAssembly(Assembly a)302 	void CheckAssembly (Assembly a) {
303 		// AssemblyName properties
304 		var aname = a.GetName (false);
305 		Assert.AreEqual (new Version (1, 2, 3, 4), aname.Version);
306 		Assert.AreEqual ("en", aname.CultureInfo.Name);
307 		Assert.IsTrue ((aname.Flags & AssemblyNameFlags.Retargetable) > 0);
308 		//Assert.AreEqual (AssemblyHashAlgorithm.SHA256, aname.HashAlgorithm);
309 		CheckCattr (a);
310 
311 		var iface1 = a.GetType ("iface1");
312 		var gtype2 = a.GetType ("gtype2");
313 
314 		var type1 = a.GetType ("type1");
315 		Assert.IsNotNull (type1);
316 
317 		// Type attributes
318 		Assert.AreEqual (TypeAttributes.Public|TypeAttributes.SequentialLayout, type1.Attributes);
319 		// Interfaces
320 		var ifaces = type1.GetInterfaces ();
321 		Assert.AreEqual (2, ifaces.Length);
322 		Assert.IsTrue (iface1 == ifaces [0] || iface1 == ifaces [1]);
323 		Assert.IsTrue (typeof (IComparable) == ifaces [0] || typeof (IComparable) == ifaces [1]);
324 		CheckCattr (type1);
325 		// FIXME: Class size/packing size
326 
327 		// Nested types
328 		var type_nested = a.GetType ("type1/type_nested");
329 		Assert.IsNotNull (type_nested);
330 
331 		// Generics
332 		var gtype1 = a.GetType ("gtype1");
333 		Assert.IsTrue (gtype1.IsGenericTypeDefinition);
334 		// Generic parameters
335 		var gparams = gtype1.GetGenericArguments ();
336 		Assert.AreEqual (2, gparams.Length);
337 		Assert.AreEqual ("K", gparams [0].Name);
338 		Assert.AreEqual ("T", gparams [1].Name);
339 		var constraints = gparams [0].GetGenericParameterConstraints ();
340 		Assert.AreEqual (2, constraints.Length);
341 		Assert.AreEqual (typeof (object), constraints [0]);
342 		Assert.AreEqual (typeof (IComparable), constraints [1]);
343 		CheckCattr (gparams [0]);
344 		constraints = gparams [1].GetGenericParameterConstraints ();
345 		Assert.AreEqual (1, constraints.Length);
346 		Assert.AreEqual (gtype1, constraints [0]);
347 		// Type param encoding
348 		var field = gtype1.GetField ("field_gparam");
349 		Assert.AreEqual (gparams [0], field.FieldType);
350 		field = gtype1.GetField ("field_open");
351 		Assert.AreEqual (typeof (List<>).MakeGenericType (new Type [] { gparams [1] }), field.FieldType);
352 
353 		// Type encoding
354 		var t = a.GetType ("type3");
355 		Assert.AreEqual (type_nested, t.GetField ("field_nested").FieldType);
356 		Assert.AreEqual (typeof (TimeZoneInfo.AdjustmentRule), t.GetField ("field_nested_ref").FieldType);
357 		Assert.AreEqual (typeof (int), t.GetField ("field_int").FieldType);
358 		Assert.AreEqual (typeof (object[]), t.GetField ("field_array_typeref").FieldType);
359 		Assert.AreEqual (type1.MakeArrayType (), t.GetField ("field_szarray").FieldType);
360 		var arraytype1 = Array.CreateInstance (typeof (int), new int [] { 10 }, new int [] { 1 }).GetType ();
361 		// FIXME:
362 		//Assert.AreEqual (arraytype1, t.GetField ("field_non_szarray").FieldType);
363 		arraytype1 = Array.CreateInstance (typeof (int), new int [] { 10, 10 }, new int [] { 1, 1 }).GetType ();
364 		Assert.AreEqual (arraytype1, t.GetField ("field_multi_dim_array").FieldType);
365 		Assert.AreEqual (type1.MakePointerType (), t.GetField ("field_pointer").FieldType);
366 		Assert.AreEqual (typeof (List<int>), t.GetField ("field_ginst").FieldType);
367 		var ginsttype = gtype2.MakeGenericType (new Type [] { typeof (int), typeof (string) });
368 		Assert.AreEqual (ginsttype, t.GetField ("field_ginst_tbuilder").FieldType);
369 
370 		// Field properties
371 		var type4 = a.GetType ("type4");
372 		// FIXME: constant
373 		field = type4.GetField ("field_int");
374 		// FIXME: field offset
375 		field = type4.GetField ("field_offset");
376 		//var attrs = field.GetCustomAttributes (typeof (FieldOffsetAttribute), true);
377 		field = type4.GetField ("field_modopt");
378 		var cmods = field.GetRequiredCustomModifiers ();
379 		Assert.AreEqual (1, cmods.Length);
380 		Assert.AreEqual (typeof (int), cmods [0]);
381 		cmods = field.GetOptionalCustomModifiers ();
382 		Assert.AreEqual (1, cmods.Length);
383 		Assert.AreEqual (typeof (uint), cmods [0]);
384 		// FIXME: marshal
385 		// Simple marshal
386 		field = type4.GetField ("field_marshal1");
387 		var attrs = field.GetCustomAttributes (typeof (MarshalAsAttribute), true);
388 		Assert.AreEqual (1, attrs.Length);
389 		var marshal = attrs [0] as MarshalAsAttribute;
390 		Assert.AreEqual (UnmanagedType.U4, marshal.Value);
391 		// ByValArray
392 		field = type4.GetField ("field_marshal_byval_array");
393 		attrs = field.GetCustomAttributes (typeof (MarshalAsAttribute), true);
394 		Assert.AreEqual (1, attrs.Length);
395 		marshal = attrs [0] as MarshalAsAttribute;
396 		Assert.AreEqual (UnmanagedType.ByValArray, marshal.Value);
397 		Assert.AreEqual (16, marshal.SizeConst);
398 		// ByValTStr
399 		field = type4.GetField ("field_marshal_byval_tstr");
400 		attrs = field.GetCustomAttributes (typeof (MarshalAsAttribute), true);
401 		Assert.AreEqual (1, attrs.Length);
402 		marshal = attrs [0] as MarshalAsAttribute;
403 		Assert.AreEqual (UnmanagedType.ByValTStr, marshal.Value);
404 		Assert.AreEqual (16, marshal.SizeConst);
405 #if false
406 		// Custom marshaler
407 		field = type4.GetField ("field_marshal_custom");
408 		attrs = field.GetCustomAttributes (typeof (MarshalAsAttribute), true);
409 		Assert.AreEqual (1, attrs.Length);
410 		marshal = attrs [0] as MarshalAsAttribute;
411 		Assert.AreEqual (UnmanagedType.CustomMarshaler, marshal.Value);
412 		Assert.AreEqual (typeof (object), marshal.MarshalTypeRef);
413 		Assert.AreEqual ("Cookie", marshal.MarshalCookie);
414 #endif
415 		field = type4.GetField ("field_cattr");
416 		CheckCattr (field);
417 
418 		// Global fields
419 		field = a.ManifestModule.GetField ("data1");
420 		Assert.IsNotNull (field);
421 		field = a.ManifestModule.GetField ("data2");
422 		Assert.IsNotNull (field);
423 
424 		// Methods and signatures
425 		var type_methods = a.GetType ("type_methods");
426 		var ctors = type_methods.GetConstructors (BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
427 		Assert.AreEqual (2, ctors.Length);
428 		// .ctor
429 		var ctor = type_methods.GetConstructor (new Type[] { typeof (int), typeof (object) });
430 		Assert.IsNotNull (ctor);
431 		Assert.AreEqual (MethodImplAttributes.NoInlining|MethodImplAttributes.IL, ctor.GetMethodImplementationFlags ());
432 		//Assert.AreEqual (CallingConventions.VarArgs, ctor.CallingConvention);
433 		// .cctor
434 		ctors = type_methods.GetConstructors (BindingFlags.Public|BindingFlags.Static);
435 		Assert.AreEqual (1, ctors.Length);
436 		// parameters
437 		ctor = type_methods.GetConstructor (new Type[] { typeof (int), typeof (object) });
438 		Assert.IsNotNull (ctor);
439 		var parameters = ctor.GetParameters ();
440 		Assert.AreEqual (2, parameters.Length);
441 		Assert.AreEqual ("param1", parameters [0].Name);
442 		Assert.AreEqual (typeof (int), parameters [0].ParameterType);
443 		Assert.AreEqual (ParameterAttributes.HasDefault, parameters [0].Attributes);
444 		Assert.AreEqual (16, parameters [0].RawDefaultValue);
445 		CheckCattr (parameters [0]);
446 		cmods = parameters [0].GetRequiredCustomModifiers ();
447 		Assert.AreEqual (1, cmods.Length);
448 		Assert.AreEqual (typeof (object), cmods [0]);
449 		cmods = parameters [0].GetOptionalCustomModifiers ();
450 		Assert.AreEqual (1, cmods.Length);
451 		Assert.AreEqual (typeof (int), cmods [0]);
452 		Assert.AreEqual ("param2", parameters [1].Name);
453 #if false
454 		Assert.AreEqual (ParameterAttributes.Out|ParameterAttributes.HasFieldMarshal, parameters [1].Attributes);
455 		Assert.AreEqual (typeof (object), parameters [1].ParameterType);
456 		attrs = parameters [1].GetCustomAttributes (typeof (MarshalAsAttribute), true);
457 		Assert.AreEqual (1, attrs.Length);
458 		marshal = attrs [0] as MarshalAsAttribute;
459 		Assert.AreEqual (UnmanagedType.U4, marshal.Value);
460 #endif
461 		// methods
462 		var method = type_methods.GetMethod ("method1");
463 		Assert.IsNotNull (method);
464 		Assert.AreEqual (typeof (int), method.ReturnType);
465 		Assert.AreEqual (MethodImplAttributes.NoInlining|MethodImplAttributes.IL, method.GetMethodImplementationFlags ());
466 		gparams = gtype1.GetGenericArguments ();
467 		Assert.AreEqual (2, gparams.Length);
468 		Assert.AreEqual ("K", gparams [0].Name);
469 		Assert.AreEqual ("T", gparams [1].Name);
470 		constraints = gparams [0].GetGenericParameterConstraints ();
471 		Assert.AreEqual (2, constraints.Length);
472 		Assert.AreEqual (typeof (object), constraints [0]);
473 		Assert.AreEqual (typeof (IComparable), constraints [1]);
474 		parameters = method.GetParameters ();
475 		// method parameters
476 		Assert.AreEqual (2, parameters.Length);
477 		Assert.AreEqual ("param1", parameters [0].Name);
478 		Assert.AreEqual (typeof (int), parameters [0].ParameterType);
479 		Assert.AreEqual (ParameterAttributes.HasDefault, parameters [0].Attributes);
480 		Assert.AreEqual (16, parameters [0].RawDefaultValue);
481 		cmods = parameters [0].GetRequiredCustomModifiers ();
482 		Assert.AreEqual (1, cmods.Length);
483 		Assert.AreEqual (typeof (object), cmods [0]);
484 		cmods = parameters [0].GetOptionalCustomModifiers ();
485 		Assert.AreEqual (1, cmods.Length);
486 		Assert.AreEqual (typeof (int), cmods [0]);
487 		Assert.AreEqual ("param2", parameters [1].Name);
488 #if false
489 		Assert.AreEqual (ParameterAttributes.Out|ParameterAttributes.HasFieldMarshal, parameters [1].Attributes);
490 		Assert.AreEqual (typeof (object), parameters [1].ParameterType);
491 		attrs = parameters [1].GetCustomAttributes (typeof (MarshalAsAttribute), true);
492 		Assert.AreEqual (1, attrs.Length);
493 		marshal = attrs [0] as MarshalAsAttribute;
494 		Assert.AreEqual (UnmanagedType.U4, marshal.Value);
495 #endif
496 		// return type
497 		var rparam = method.ReturnParameter;
498 		cmods = rparam.GetRequiredCustomModifiers ();
499 		Assert.AreEqual (1, cmods.Length);
500 		Assert.AreEqual (typeof (object), cmods [0]);
501 		cmods = rparam.GetOptionalCustomModifiers ();
502 		Assert.AreEqual (1, cmods.Length);
503 		Assert.AreEqual (typeof (int), cmods [0]);
504 #if false
505 		attrs = rparam.GetCustomAttributes (typeof (MarshalAsAttribute), true);
506 		Assert.AreEqual (1, attrs.Length);
507 		marshal = attrs [0] as MarshalAsAttribute;
508 		Assert.AreEqual (UnmanagedType.U4, marshal.Value);
509 #endif
510 		CheckCattr (rparam);
511 
512 		// Properties
513 		var type_props = a.GetType ("type_properties");
514 		var prop = type_props.GetProperty ("AProperty");
515 		Assert.IsNotNull (prop);
516 		Assert.AreEqual (PropertyAttributes.HasDefault, prop.Attributes);
517 		var getter = prop.GetGetMethod ();
518 		Assert.IsNotNull (getter);
519 		Assert.AreEqual ("get_method1", getter.Name);
520 		var setter = prop.GetSetMethod ();
521 		Assert.IsNotNull (setter);
522 		Assert.AreEqual ("set_method1", setter.Name);
523 		CheckCattr (prop);
524 
525 		// Events
526 		var type_events = a.GetType ("type_events");
527 		var ev = type_events.GetEvent ("Event1");
528 		Assert.IsNotNull (ev);
529 		var m = ev.AddMethod;
530 		Assert.IsNotNull (m);
531 		Assert.AreEqual ("add_method1", m.Name);
532 		m = ev.RemoveMethod;
533 		Assert.IsNotNull (m);
534 		Assert.AreEqual ("remove_method1", m.Name);
535 		m = ev.RaiseMethod;
536 		Assert.IsNotNull (m);
537 		Assert.AreEqual ("raise_method1", m.Name);
538 		Assert.AreEqual (EventAttributes.SpecialName, ev.Attributes);
539 		CheckCattr (ev);
540 	}
541 }
542 }
543