/src/NUnit/interfaces/RuntimeFramework.cs
C# | 463 lines | 311 code | 61 blank | 91 comment | 89 complexity | 0eb1c68f7979bbd2acab5a683190de7a MD5 | raw file
1// **************************************************************** 2// This is free software licensed under the NUnit license. You 3// may obtain a copy of the license as well as information regarding 4// copyright ownership at http://nunit.org. 5// **************************************************************** 6 7using System; 8using System.IO; 9using System.Reflection; 10using System.Collections; 11using Microsoft.Win32; 12 13namespace NUnit.Core 14{ 15 /// <summary> 16 /// Enumeration identifying a common language 17 /// runtime implementation. 18 /// </summary> 19 public enum RuntimeType 20 { 21 /// <summary>Any supported runtime framework</summary> 22 Any, 23 /// <summary>Microsoft .NET Framework</summary> 24 Net, 25 /// <summary>Microsoft .NET Compact Framework</summary> 26 NetCF, 27 /// <summary>Microsoft Shared Source CLI</summary> 28 SSCLI, 29 /// <summary>Mono</summary> 30 Mono 31 } 32 33 /// <summary> 34 /// RuntimeFramework represents a particular version 35 /// of a common language runtime implementation. 36 /// </summary> 37 [Serializable] 38 public sealed class RuntimeFramework 39 { 40 #region Static and Instance Fields 41 42 /// <summary> 43 /// DefaultVersion is an empty Version, used to indicate that 44 /// NUnit should select the CLR version to use for the test. 45 /// </summary> 46 public static readonly Version DefaultVersion = new Version(); 47 48 private static RuntimeFramework currentFramework; 49 private static RuntimeFramework[] availableFrameworks; 50 51 private RuntimeType runtime; 52 private Version frameworkVersion; 53 private Version clrVersion; 54 private string displayName; 55 #endregion 56 57 #region Constructor 58 59 /// <summary> 60 /// Construct from a runtime type and version 61 /// </summary> 62 /// <param name="runtime">The runtime type of the framework</param> 63 /// <param name="version">The version of the framework</param> 64 public RuntimeFramework( RuntimeType runtime, Version version) 65 { 66 this.runtime = runtime; 67 this.frameworkVersion = version; 68 69 this.clrVersion = version; 70 if (frameworkVersion.Major == 3) 71 this.clrVersion = new Version(2, 0); 72 else if (runtime == RuntimeType.Mono && version.Major == 1) 73 this.clrVersion = new Version(1, 1); 74 75 this.displayName = GetDefaultDisplayName(runtime, version); 76 } 77 78 #endregion 79 80 #region Properties 81 82 /// <summary> 83 /// Static method to return a RuntimeFramework object 84 /// for the framework that is currently in use. 85 /// </summary> 86 public static RuntimeFramework CurrentFramework 87 { 88 get 89 { 90 if (currentFramework == null) 91 { 92 Type monoRuntimeType = Type.GetType("Mono.Runtime", false); 93 bool isMono = monoRuntimeType != null; 94 95 RuntimeType runtime = isMono ? RuntimeType.Mono : RuntimeType.Net; 96 97 int major = Environment.Version.Major; 98 int minor = Environment.Version.Minor; 99 100 if (isMono && major == 1) 101 minor = 0; 102 103 currentFramework = new RuntimeFramework(runtime, new Version(major, minor)); 104 currentFramework.clrVersion = Environment.Version; 105 106 if (isMono) 107 { 108 MethodInfo getDisplayNameMethod = monoRuntimeType.GetMethod( 109 "GetDisplayName", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding); 110 if (getDisplayNameMethod != null) 111 currentFramework.displayName = (string)getDisplayNameMethod.Invoke(null, new object[0]); 112 } 113 } 114 115 return currentFramework; 116 } 117 } 118 119 /// <summary> 120 /// Gets an array of all available frameworks 121 /// </summary> 122 public static RuntimeFramework[] AvailableFrameworks 123 { 124 get 125 { 126 if (availableFrameworks == null) 127 { 128 FrameworkCollection frameworks = new FrameworkCollection(); 129 130 AppendDotNetFrameworks(frameworks); 131 AppendDefaultMonoFramework(frameworks); 132 // NYI 133 //AppendMonoFrameworks(frameworks); 134 135 availableFrameworks = frameworks.ToArray(); 136 } 137 138 return availableFrameworks; 139 } 140 } 141 142 /// <summary> 143 /// Returns true if the current RuntimeFramework is available. 144 /// In the current implementation, only Mono and Microsoft .NET 145 /// are supported. 146 /// </summary> 147 /// <returns>True if it's available, false if not</returns> 148 public bool IsAvailable 149 { 150 get 151 { 152 foreach (RuntimeFramework framework in AvailableFrameworks) 153 if (this.Matches(framework)) 154 return true; 155 156 return false; 157 } 158 } 159 160 /// <summary> 161 /// The type of this runtime framework 162 /// </summary> 163 public RuntimeType Runtime 164 { 165 get { return runtime; } 166 } 167 168 /// <summary> 169 /// The framework version for this runtime framework 170 /// </summary> 171 public Version FrameworkVersion 172 { 173 get { return frameworkVersion; } 174 } 175 176 /// <summary> 177 /// The CLR version for this runtime framework 178 /// </summary> 179 public Version ClrVersion 180 { 181 get { return clrVersion; } 182 } 183 184 /// <summary> 185 /// Return true if any CLR version may be used in 186 /// matching this RuntimeFramework object. 187 /// </summary> 188 public bool AllowAnyVersion 189 { 190 get { return this.clrVersion == DefaultVersion; } 191 } 192 193 /// <summary> 194 /// Returns the Display name for this framework 195 /// </summary> 196 public string DisplayName 197 { 198 get { return displayName; } 199 } 200 201 #endregion 202 203 #region Public Methods 204 205 /// <summary> 206 /// Parses a string representing a RuntimeFramework. 207 /// The string may be just a RuntimeType name or just 208 /// a Version or a hyphentated RuntimeType-Version or 209 /// a Version prefixed by 'v'. 210 /// </summary> 211 /// <param name="s"></param> 212 /// <returns></returns> 213 public static RuntimeFramework Parse(string s) 214 { 215 RuntimeType runtime = RuntimeType.Any; 216 Version version = DefaultVersion; 217 218 string[] parts = s.Split(new char[] { '-' }); 219 if (parts.Length == 2) 220 { 221 runtime = (RuntimeType)System.Enum.Parse(typeof(RuntimeType), parts[0], true); 222 string vstring = parts[1]; 223 if (vstring != "") 224 version = new Version(vstring); 225 } 226 else if (char.ToLower(s[0]) == 'v') 227 { 228 version = new Version(s.Substring(1)); 229 } 230 else if (IsRuntimeTypeName(s)) 231 { 232 runtime = (RuntimeType)System.Enum.Parse(typeof(RuntimeType), s, true); 233 } 234 else 235 { 236 version = new Version(s); 237 } 238 239 return new RuntimeFramework(runtime, version); 240 } 241 242 /// <summary> 243 /// Returns the best available framework that matches a target framework. 244 /// If the target framework has a build number specified, then an exact 245 /// match is needed. Otherwise, the matching framework with the highest 246 /// build number is used. 247 /// </summary> 248 /// <param name="target"></param> 249 /// <returns></returns> 250 public static RuntimeFramework GetBestAvailableFramework(RuntimeFramework target) 251 { 252 RuntimeFramework result = target; 253 254 if (target.ClrVersion.Build < 0) 255 { 256 foreach (RuntimeFramework framework in AvailableFrameworks) 257 if (framework.Matches(target) && 258 framework.ClrVersion.Build > result.ClrVersion.Build) 259 { 260 result = framework; 261 } 262 } 263 264 return result; 265 } 266 267 /// <summary> 268 /// Overridden to return the short name of the framework 269 /// </summary> 270 /// <returns></returns> 271 public override string ToString() 272 { 273 if (this.AllowAnyVersion) 274 { 275 return runtime.ToString().ToLower(); 276 } 277 else 278 { 279 string vstring = frameworkVersion.ToString(); 280 if (runtime == RuntimeType.Any) 281 return "v" + vstring; 282 else 283 return runtime.ToString().ToLower() + "-" + vstring; 284 } 285 } 286 287 /// <summary> 288 /// Returns true if this framework "matches" the one supplied 289 /// as an argument. Two frameworks match if their runtime types 290 /// are the same or either one is RuntimeType.Any and all specified 291 /// components of the CLR version are equal. Negative (i.e. unspecified) 292 /// version components are ignored. 293 /// </summary> 294 /// <param name="other">The RuntimeFramework to be matched.</param> 295 /// <returns>True on match, otherwise false</returns> 296 public bool Matches(RuntimeFramework other) 297 { 298 if (this.Runtime != RuntimeType.Any 299 && other.Runtime != RuntimeType.Any 300 && this.Runtime != other.Runtime) 301 return false; 302 303 if (this.AllowAnyVersion || other.AllowAnyVersion) 304 return true; 305 306 return this.ClrVersion.Major == other.ClrVersion.Major 307 && this.ClrVersion.Minor == other.ClrVersion.Minor 308 && ( this.ClrVersion.Build < 0 309 || other.ClrVersion.Build < 0 310 || this.ClrVersion.Build == other.ClrVersion.Build ) 311 && ( this.ClrVersion.Revision < 0 312 || other.ClrVersion.Revision < 0 313 || this.ClrVersion.Revision == other.ClrVersion.Revision ); 314 } 315 316 #endregion 317 318 #region Helper Methods 319 320 private static bool IsRuntimeTypeName(string name) 321 { 322 foreach (string item in Enum.GetNames(typeof(RuntimeType))) 323 if (item.ToLower() == name.ToLower()) 324 return true; 325 326 return false; 327 } 328 329 private static string GetDefaultDisplayName(RuntimeType runtime, Version version) 330 { 331 if (version == DefaultVersion) 332 return runtime.ToString(); 333 else if (runtime == RuntimeType.Any) 334 return "v" + version.ToString(); 335 else 336 return runtime.ToString() + " " + version.ToString(); 337 } 338 339 private static void AppendMonoFrameworks(FrameworkCollection frameworks) 340 { 341 if (Environment.OSVersion.Platform == PlatformID.Win32NT) 342 AppendAllMonoFrameworks(frameworks); 343 else 344 AppendDefaultMonoFramework(frameworks); 345 } 346 347 private static void AppendAllMonoFrameworks(FrameworkCollection frameworks) 348 { 349 // TODO: Find multiple installed Mono versions under Linux 350 if (Environment.OSVersion.Platform == PlatformID.Win32NT) 351 { 352 // Use registry to find alternate versions 353 RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Novell\Mono"); 354 if (key == null) return; 355 356 foreach (string version in key.GetSubKeyNames()) 357 { 358 RegistryKey subKey = key.OpenSubKey(version); 359 string monoPrefix = subKey.GetValue("SdkInstallRoot") as string; 360 361 AppendMonoFramework(frameworks, monoPrefix, version); 362 } 363 } 364 else 365 AppendDefaultMonoFramework(frameworks); 366 } 367 368 // This method works for Windows and Linux but currently 369 // is only called under Linux. 370 private static void AppendDefaultMonoFramework(FrameworkCollection frameworks) 371 { 372 string monoPrefix = null; 373 string version = null; 374 375 if (Environment.OSVersion.Platform == PlatformID.Win32NT) 376 { 377 RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Novell\Mono"); 378 if (key != null) 379 { 380 version = key.GetValue("DefaultCLR") as string; 381 if (version != null && version != "") 382 { 383 key = key.OpenSubKey(version); 384 if (key != null) 385 monoPrefix = key.GetValue("SdkInstallRoot") as string; 386 } 387 } 388 } 389 else // Assuming we're currently running Mono - change if more runtimes are added 390 { 391 string libMonoDir = Path.GetDirectoryName(typeof(object).Assembly.Location); 392 monoPrefix = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(libMonoDir))); 393 } 394 395 AppendMonoFramework(frameworks, monoPrefix, version); 396 } 397 398 private static void AppendMonoFramework(FrameworkCollection frameworks, string monoPrefix, string version) 399 { 400 if (monoPrefix != null) 401 { 402 string displayFmt = version != null 403 ? "Mono " + version + " - {0} Profile" 404 : "Mono {0} Profile"; 405 406 if (File.Exists(Path.Combine(monoPrefix, "lib/mono/1.0/mscorlib.dll"))) 407 { 408 RuntimeFramework framework = new RuntimeFramework(RuntimeType.Mono, new Version(1, 1, 4322)); 409 framework.displayName = string.Format(displayFmt, "1.0"); 410 frameworks.Add(framework); 411 } 412 413 if (File.Exists(Path.Combine(monoPrefix, "lib/mono/2.0/mscorlib.dll"))) 414 { 415 RuntimeFramework framework = new RuntimeFramework(RuntimeType.Mono, new Version(2, 0, 50727)); 416 framework.displayName = string.Format(displayFmt, "2.0"); 417 frameworks.Add(framework); 418 } 419 420 if (File.Exists(Path.Combine(monoPrefix, "lib/mono/4.0/mscorlib.dll"))) 421 { 422 RuntimeFramework framework = new RuntimeFramework(RuntimeType.Mono, new Version(4, 0, 30319)); 423 framework.displayName = string.Format(displayFmt, "4.0"); 424 frameworks.Add(framework); 425 } 426 } 427 } 428 429 private static void AppendDotNetFrameworks(FrameworkCollection frameworks) 430 { 431 if (Environment.OSVersion.Platform == PlatformID.Win32NT) 432 { 433 RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\.NETFramework\policy"); 434 if (key != null) 435 { 436 foreach (string name in key.GetSubKeyNames()) 437 { 438 if (name.StartsWith("v")) 439 { 440 RegistryKey key2 = key.OpenSubKey(name); 441 foreach (string build in key2.GetValueNames()) 442 frameworks.Add(new RuntimeFramework(RuntimeType.Net, new Version(name.Substring(1) + "." + build))); 443 } 444 } 445 } 446 } 447 } 448 449#if NET_2_0 450 private class FrameworkCollection : System.Collections.Generic.List<RuntimeFramework> { } 451#else 452 private class FrameworkCollection : ArrayList 453 { 454 public new RuntimeFramework[] ToArray() 455 { 456 return (RuntimeFramework[])ToArray(typeof(RuntimeFramework)); 457 } 458 } 459#endif 460 461 #endregion 462 } 463}