PageRenderTime 26ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/adinetz03/cbc/CBucks.Compiler.Tests/CompilerTestUtils.cs

#
C# | 456 lines | 241 code | 28 blank | 187 comment | 62 complexity | be6235f405092dc55e3034ce0d40a53b MD5 | raw file
Possible License(s): AGPL-3.0
  1. //#define DEB
  2. //#define FULDEB
  3. //#define PROGDEB
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Text;
  7. using System.Reflection;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Threading;
  11. namespace CBucks.Compiler.Tests {
  12. /// <summary>
  13. /// Contains utility functions for testing the compiler
  14. /// </summary>
  15. public static class CompilerTestUtils {
  16. /// <summary>
  17. /// Writes the application configuration file
  18. /// </summary>
  19. /// <param name="filename"> The name of the configuration file to write </param>
  20. /// <param name="configName"> The name config file to write as a value </param>
  21. public static void writeAppConfigFile(string filename, string configName) {
  22. using(StreamWriter sw = new StreamWriter(filename)) {
  23. sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
  24. sw.WriteLine("<configuration>");
  25. sw.WriteLine("<appSettings>");
  26. sw.Write("<add key=\"runtimeConfigFile\" value=\"");
  27. sw.Write(configName);
  28. sw.WriteLine("\"/>");
  29. sw.WriteLine("</appSettings>");
  30. sw.WriteLine("</configuration>");
  31. } // end of using()
  32. } // end of writeAppConfigFile()
  33. /// <summary>
  34. /// Compiles the list of input files with the specified target
  35. /// </summary>
  36. /// <param name="useCbRuntime"> Whether or not to use C$ runtime
  37. /// (if used, it is first initialized) </param>
  38. /// <param name="outfile"> The name of the output file </param>
  39. /// <param name="target"> The compilation target - either "exe"
  40. /// or "dll" </param>
  41. /// <param name="filenames"> The list of files to compile </param>
  42. /// <returns> The compiler return code </returns>
  43. public static int compile(bool useCbRuntime, string outfile, string target,
  44. string[] filenames) {
  45. // build the command line
  46. StringBuilder cl = new StringBuilder();
  47. if(useCbRuntime)
  48. cl.Append("-cb ");
  49. #if DEB
  50. cl.Append("-wr ");
  51. #endif
  52. #if FULDEB
  53. cl.Append("-wd ");
  54. cl.Append("-ce ");
  55. #endif
  56. cl.Append("-o ").Append(outfile).Append(" ");
  57. cl.Append("-m gen ");
  58. cl.Append("-t " + target + " ");
  59. cl.Append("-s ");
  60. foreach(string name in filenames)
  61. cl.Append(name + " ");
  62. #if PROGDEB
  63. #else
  64. cl.AppendFormat("-spe ");
  65. #endif
  66. // start compilation and wait for it to finish
  67. ProcessStartInfo psi = new ProcessStartInfo("cbc.exe", cl.ToString());
  68. // for debug purposes
  69. #if DEB
  70. #else
  71. psi.WindowStyle = ProcessWindowStyle.Hidden;
  72. #endif
  73. Process p = Process.Start(psi);
  74. p.WaitForExit();
  75. // return exit code
  76. return p.ExitCode;
  77. } // end of compile()
  78. /// <summary>
  79. /// Compiles the list of input files with the specified target
  80. /// </summary>
  81. /// <param name="outfile"> The name of the output file </param>
  82. /// <param name="target"> The compilation target - either "exe"
  83. /// or "dll" </param>
  84. /// <param name="filenames"> The list of files to compile </param>
  85. /// <returns> The compiler return code </returns>
  86. public static int compile(string outfile, string target,
  87. string[] filenames) {
  88. return compile(false, outfile, target, filenames);
  89. } // end of compile()
  90. /// <summary>
  91. /// Compiles the list of input files and returns the error code
  92. /// </summary>
  93. /// <param name="outfile"> The output file </param>
  94. /// <param name="filenames"> The names of input files </param>
  95. /// <returns> The tokenizer return code </returns>
  96. public static int compile(string outfile, params string[] filenames) {
  97. return compile(outfile, "dll", filenames);
  98. } // end of parse()
  99. /// <summary>
  100. /// Compiles the program, runs it and checks whether its output
  101. /// matches desired output.
  102. /// </summary>
  103. /// <param name="inFiles"> The input files </param>
  104. /// <param name="output"> The desired output </param>
  105. /// <returns> True if the test succeeds and false otherwise </returns>
  106. public static bool testOutput(string[] inFiles, string[] output) {
  107. return testOutput(false, inFiles, output, "");
  108. } // end of testOutput()
  109. /// <summary>
  110. /// Compiles the program, runs it and checks whether its output
  111. /// matches desired output.
  112. /// </summary>
  113. /// <param name="useCbRuntime"> Whether to use C$ runtime
  114. /// during compilation and evaluation </param>
  115. /// <param name="inFiles"> The input files </param>
  116. /// <param name="output"> The desired output </param>
  117. /// <returns> True if the test succeeds and false otherwise </returns>
  118. public static bool testOutput(bool useCbRuntime, string[] inFiles,
  119. string[] output, string configName) {
  120. // generate a random file name
  121. string outname = Guid.NewGuid().ToString() + ".exe";
  122. // compile it
  123. int r = compile(useCbRuntime, outname, "exe", inFiles);
  124. if(r != 0)
  125. return false;
  126. if(useCbRuntime) {
  127. string appConfigFile = outname + ".config";
  128. writeAppConfigFile(appConfigFile, configName);
  129. } // end of if()
  130. return checkOutput(outname, output);
  131. } // end of testOutput()
  132. /// <summary>
  133. /// Tests the output. Accepts a single input file.
  134. /// </summary>
  135. /// /// <param name="useCbRuntime"> Whether to use C$ runtime
  136. /// during compilation and evaluation </param>
  137. /// <param name="inFile"> The input file to process </param>
  138. /// <param name="output"> The desired output </param>
  139. /// <returns> True if test succeeds and false if not </returns>
  140. public static bool testOutput(string inFile, params string[] output) {
  141. return testOutput(new string[] { inFile }, output);
  142. } // end of testOutput()
  143. /// <summary>
  144. /// Tests the output. Accepts a single input file.
  145. /// </summary>
  146. /// <param name="inFile"> The input file to process </param>
  147. /// <param name="output"> The desired output </param>
  148. /// <returns> True if test succeeds and false if not </returns>
  149. public static bool testOutput(bool useCbRuntime, string configName,
  150. string inFile, params string[] output) {
  151. return testOutput(useCbRuntime, new string[] { inFile }, output,
  152. configName);
  153. } // end of testOutput()
  154. /// <summary>
  155. /// Checks the output
  156. /// </summary>
  157. /// <param name="outname"> The name of the output file </param>
  158. /// <param name="output"> The output strings </param>
  159. /// <returns> True if the real output matches the desired one
  160. /// and false otherwise </returns>
  161. public static bool checkOutput(string outname, string[] output) {
  162. ProcessStartInfo psi = new ProcessStartInfo(outname);
  163. #if PROGDEB
  164. Process p = Process.Start(psi);
  165. Thread.Sleep(Timeout.Infinite);
  166. return false;
  167. #else
  168. psi.UseShellExecute = false;
  169. psi.WindowStyle = ProcessWindowStyle.Hidden;
  170. psi.RedirectStandardOutput = true;
  171. Process p = Process.Start(psi);
  172. // get the standard output
  173. StreamReader sr = p.StandardOutput;
  174. // wait for the process to end
  175. p.WaitForExit();
  176. // read up to the end of file and check with the output
  177. int i = 0, n = output.Length;
  178. while(!sr.EndOfStream) {
  179. if(i == n)
  180. return false;
  181. string s = sr.ReadLine();
  182. if(s != output[i])
  183. return false;
  184. i++;
  185. } // end of while()
  186. return i == n;
  187. #endif
  188. } // end of checkOutput()
  189. /// <summary>
  190. /// Tests the compilation for success
  191. /// </summary>
  192. /// <param name="inFiles"> The list of input files </param>
  193. /// <param name="typeNames"> The list of desired type names </param>
  194. /// <returns> Whether the test succeeded or failed </returns>
  195. /// <remarks> Does not uses C$ runtime and compiles into a ".dll"</remarks>
  196. public static bool testSuccess(string[] inFiles, params string[] typeNames) {
  197. return testSuccess(false, "dll", inFiles, typeNames);
  198. } // end of testSuccess()
  199. /// <summary>
  200. /// Tests the compilation for success
  201. /// </summary>
  202. /// <param name="useCbRuntime"> True if to compile to use with C$ runtime
  203. /// (-cb switch) and false if not. </param>
  204. /// <param name="outputName"> The type of the output file. Must be either
  205. /// "exe" or "dll". </param>
  206. /// <param name="inFiles"> The list of input files </param>
  207. /// <param name="typeNames"> The list of desired type names </param>
  208. /// <returns> Whether the test succeeded or failed </returns>
  209. public static bool testSuccess(bool useCbRuntime, string outputType,
  210. string[] inFiles, params string[] typeNames) {
  211. // generate a random file name
  212. string name = Guid.NewGuid().ToString() + "." + outputType;
  213. // compile it
  214. int r = compile(useCbRuntime, name, outputType, inFiles);
  215. if(r != 0)
  216. return false;
  217. // check the resulting assembly
  218. return testTypes(name, typeNames);
  219. } // end of testSuccess()
  220. /// <summary>
  221. /// Tests compilation for success
  222. /// </summary>
  223. /// <param name="inFile"> The name of the input file </param>
  224. /// <param name="typeNames"> The names of the types </param>
  225. /// <returns> Whether the test succeeds or fails </returns>
  226. public static bool testSuccess(string inFile, params string[] typeNames) {
  227. return testSuccess(new string[] { inFile }, typeNames);
  228. } // end of testSuccess()
  229. /// <summary>
  230. /// Starts the type member testing
  231. /// </summary>
  232. /// <param name="inFile"> The input file for the testing </param>
  233. /// <param name="typeNames"> The names of the types being tested </param>
  234. /// <returns> The loaded assembly if the initial testing succeeds
  235. /// and null if it fails </returns>
  236. public static Assembly startTypeMemberTesting(string inFile,
  237. params string[] typeNames) {
  238. // generate a random file name
  239. string name = Guid.NewGuid().ToString() + ".dll";
  240. // compile it
  241. int r = compile(name, inFile);
  242. if(r != 0)
  243. return null;
  244. Assembly a = Assembly.LoadFrom(name);
  245. foreach(string typeName in typeNames)
  246. if(null == loadCbType(a, typeName))
  247. return null;
  248. return a;
  249. } // end of startTypeMemberTesting()
  250. /// <summary>
  251. /// Starts the type member testing
  252. /// </summary>
  253. /// <param name="inFiles"> The input files for the testing </param>
  254. /// <param name="typeNames"> The names of the types being tested </param>
  255. /// <returns> The loaded assembly if the initial testing succeeds
  256. /// and null if it fails </returns>
  257. public static Assembly startTypeMemberTesting(string[] inFiles,
  258. params string[] typeNames) {
  259. // generate a random file name
  260. string name = Guid.NewGuid().ToString() + ".dll";
  261. // compile it
  262. int r = compile(name, inFiles);
  263. if(r != 0)
  264. return null;
  265. Assembly a = Assembly.LoadFrom(name);
  266. foreach(string typeName in typeNames)
  267. if(null == loadCbType(a, typeName))
  268. return null;
  269. return a;
  270. } // end of startTypeMemberTesting()
  271. /// <summary>
  272. /// Tests whether the assembly has all of the specified list of types
  273. /// </summary>
  274. /// <param name="assName"> The name of the assembly (more precisely,
  275. /// the path to the output file) </param>
  276. /// <param name="typeNames"> The list of fully qualified
  277. /// type names </param>
  278. /// <returns> True if all the types loaded successfully and
  279. /// false otherwise </returns>
  280. public static bool testTypes(string assName,
  281. params string[] typeNames) {
  282. Assembly a = Assembly.ReflectionOnlyLoadFrom(assName);
  283. foreach(string typeName in typeNames)
  284. if(null == loadCbType(a, typeName))
  285. return false;
  286. return true;
  287. } // end of testTypes()
  288. /// <summary>
  289. /// A simple check of type definitions - checks whether the members with
  290. /// the specified names are defined. Except for names, nothing is checked.
  291. /// </summary>
  292. /// <param name="type"> The type in which to check member names </param>
  293. /// <param name="memberNames"> The member names to check </param>
  294. /// <returns> True if the check succeeds and false otherwise </returns>
  295. public static bool testTypeMembers(Type type,
  296. params string[] memberNames) {
  297. foreach(string memberName in memberNames)
  298. if(!testTypeMember(type, memberName))
  299. return false;
  300. return true;
  301. } // end of testTypeMembers()
  302. /// <summary>
  303. /// Performs advanced testing of type members
  304. /// </summary>
  305. /// <param name="type"> The type to test </param>
  306. /// <param name="memberData"> The member data </param>
  307. /// <returns> True if the test succeeds and false if it fails </returns>
  308. public static bool testAdvancedTypeMembers(Type type,
  309. params object[][] memberData) {
  310. foreach(object[] member in memberData)
  311. if(!testAdvancedTypeMember(type, member))
  312. return false;
  313. return true;
  314. } // end of testAdvancedTypeMembers()
  315. /// <summary>
  316. /// Performs advanced testing of type members
  317. /// </summary>
  318. /// <param name="a"> The assembly from which to load the type </param>
  319. /// <param name="typeName"> The name of the type to load </param>
  320. /// <param name="memberData"> The member data to be tested </param>
  321. /// <returns> True if the test succeeds and false if it fails </returns>
  322. public static bool testAdvancedTypeMembers(Assembly a,
  323. string typeName, params object[][] memberData) {
  324. Type t = a.GetType(typeName);
  325. if(null == t)
  326. return false;
  327. return testAdvancedTypeMembers(t, memberData);
  328. } // end of testAdvancedTypeMembers()
  329. /// <summary>
  330. /// Checks whether the type has a member with the specified name
  331. /// </summary>
  332. /// <param name="type"> The type to check </param>
  333. /// <param name="memberName"> The name of the member to check </param>
  334. /// <returns> True if the member if found and false if not </returns>
  335. public static bool testTypeMember(Type type, string memberName) {
  336. BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Static
  337. | BindingFlags.Public | BindingFlags.Instance |
  338. BindingFlags.DeclaredOnly;
  339. return type.GetMember(memberName, bf).Length != 0;
  340. } // end of testTypeMember()
  341. /// <summary>
  342. /// Performs and advanced type member check. Does not checks
  343. /// static/non-static, access level and purity.
  344. /// </summary>
  345. /// <param name="type"> The type whose member to check </param>
  346. /// <param name="memberData"> The array of objects which together
  347. /// describe member data. For a field, this is field name and type.
  348. /// For the method, it is the return type,
  349. /// the method name and a list of argument types (or null if there is
  350. /// no arguments). For the property, it is the type, name and types
  351. /// of accessors (get or set) </param>
  352. /// <returns> True if the member test succeeded and false otherwise </returns>
  353. public static bool testAdvancedTypeMember(Type type, object[] memberData) {
  354. BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Static
  355. | BindingFlags.Public | BindingFlags.Instance |
  356. BindingFlags.DeclaredOnly;
  357. if(memberData[0] is Type) {
  358. Type rt = (Type)memberData[0];
  359. string name = (string)memberData[1];
  360. if(memberData.Length == 2) {
  361. // check the field
  362. return null != type.GetField(name, bf);
  363. } else if(memberData[2] is string) {
  364. // a property
  365. string gs = (string)memberData[2];
  366. PropertyInfo pi = type.GetProperty(name, bf);
  367. if(null == pi)
  368. return false;
  369. if(gs.IndexOf("get") != -1 && null == pi.GetGetMethod())
  370. return false;
  371. if(gs.IndexOf("set") != -1 && null == pi.GetSetMethod())
  372. return false;
  373. return true;
  374. } else {
  375. // define the type list
  376. Type[] types = Type.EmptyTypes;
  377. if(memberData[2] != null) {
  378. List<Type> l = new List<Type>();
  379. for(int i = 2; i < memberData.Length; i++)
  380. l.Add((Type)memberData[i]);
  381. types = l.ToArray();
  382. } // end of if()
  383. // a method or constructor
  384. if(name != ".ctor" && name != "new") {
  385. MethodInfo mi = type.GetMethod(name, bf, null, types, null);
  386. if(null == mi)
  387. return false;
  388. if(mi.ReturnType != rt)
  389. return false;
  390. return true;
  391. } else {
  392. // constructor's return type is ignored
  393. return null != type.GetConstructor(bf, null, types, null);
  394. } // end of if()-else
  395. } // end of if()
  396. } // end of if()
  397. // control shall not reach here
  398. throw new NotSupportedException();
  399. } // end of testAdvancedTypeMember()
  400. /// <summary>
  401. /// Loads a single C$ type
  402. /// </summary>
  403. /// <param name="a"> The assembly from which to load a type </param>
  404. /// <param name="typeName"> The name of the type to load </param>
  405. /// <returns> The type loaded or null if it is impossible </returns>
  406. public static Type loadCbType(Assembly a, string typeName) {
  407. Type t = a.GetType(typeName, false);
  408. if(null != t)
  409. return t;
  410. // try to load a type alias attribute
  411. List<CustomAttributeData> lcads = new List<CustomAttributeData>();
  412. // ensure that "Cebacs.dll" and other necessary assemblies are preloaded
  413. // for there to be no problems with CustomAttributeData
  414. lcads.AddRange(CustomAttributeData.GetCustomAttributes(a));
  415. CustomAttributeData[] cads = lcads.ToArray();
  416. foreach(CustomAttributeData cad in cads) {
  417. if(cad.Constructor.DeclaringType.FullName != "CBucks.TypeAliasAttribute")
  418. continue;
  419. string name = (string)cad.ConstructorArguments[0].Value;
  420. string namespaceName = (string)cad.ConstructorArguments[1].Value;
  421. string fullTypeName = (string)cad.ConstructorArguments[2].Value;
  422. if(namespaceName + "." + name == typeName)
  423. return Type.GetType(fullTypeName, false);
  424. } // end of foreach()
  425. return null;
  426. } // end of loadCbType()
  427. } // end of class CompilerTestUtils
  428. }