PageRenderTime 58ms CodeModel.GetById 12ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 1ms

/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}