/// <summary>
        /// Selects a target runtime framework for a TestPackage based on
        /// the settings in the package and the assemblies themselves.
        /// The package RuntimeFramework setting may be updated as a 
        /// result and the selected runtime is returned.
        /// </summary>
        /// <param name="package">A TestPackage</param>
        /// <returns>The selected RuntimeFramework</returns>
        public RuntimeFramework SelectRuntimeFramework(TestPackage package)
        {
            RuntimeFramework currentFramework = RuntimeFramework.CurrentFramework;
            string frameworkSetting = package.GetSetting(RunnerSettings.RuntimeFramework, "");
            RuntimeFramework requestedFramework = frameworkSetting.Length > 0
                ? RuntimeFramework.Parse(frameworkSetting)
                : new RuntimeFramework(RuntimeType.Any, RuntimeFramework.DefaultVersion);

            log.Debug("Current framework is {0}", currentFramework);
            if (requestedFramework == null)
                log.Debug("No specific framework requested");
            else
                log.Debug("Requested framework is {0}", requestedFramework);

            RuntimeType targetRuntime = requestedFramework.Runtime;
            Version targetVersion = requestedFramework.FrameworkVersion;

            if (targetRuntime == RuntimeType.Any)
                targetRuntime = currentFramework.Runtime;

            if (targetVersion == RuntimeFramework.DefaultVersion)
            {
                if (ServiceContext.UserSettings.GetSetting("Options.TestLoader.RuntimeSelectionEnabled", true))
                    foreach (string assembly in package.TestFiles)
                    {
                        using (AssemblyReader reader = new AssemblyReader(assembly))
                        {
                            Version v = new Version(reader.ImageRuntimeVersion.Substring(1));
                            log.Debug("Assembly {0} uses version {1}", assembly, v);
                            if (v > targetVersion) targetVersion = v;
                        }
                    }
                else
                    targetVersion = RuntimeFramework.CurrentFramework.ClrVersion;

                RuntimeFramework checkFramework = new RuntimeFramework(targetRuntime, targetVersion);
                if (!checkFramework.IsAvailable || !ServiceContext.TestAgency.IsRuntimeVersionSupported(targetVersion))
                {
                    log.Debug("Preferred version {0} is not installed or this NUnit installation does not support it", targetVersion);
                    if (targetVersion < currentFramework.FrameworkVersion)
                        targetVersion = currentFramework.FrameworkVersion;
                }
            }

            RuntimeFramework targetFramework = new RuntimeFramework(targetRuntime, targetVersion);
            package.Settings[RunnerSettings.RuntimeFramework] = targetFramework.ToString();

            log.Debug("Test will use {0} framework", targetFramework);

            return targetFramework;
        }
        /// <summary>
        /// Selects a target runtime framework for a TestPackage based on
        /// the settings in the package and the assemblies themselves.
        /// The package RuntimeFramework setting may be updated as a result
        /// and a string representing the selected runtime is returned.
        /// </summary>
        /// <param name="package">A TestPackage</param>
        /// <returns>A string representing the selected RuntimeFramework</returns>
        public string SelectRuntimeFramework(TestPackage package)
        {
            RuntimeFramework currentFramework = RuntimeFramework.CurrentFramework;
            string frameworkSetting = package.GetSetting(PackageSettings.RuntimeFramework, "");
            RuntimeFramework requestedFramework = frameworkSetting.Length > 0
                ? RuntimeFramework.Parse(frameworkSetting)
                : new RuntimeFramework(RuntimeType.Any, RuntimeFramework.DefaultVersion);

            log.Debug("Current framework is {0}", currentFramework);
            if (requestedFramework == null)
                log.Debug("No specific framework requested");
            else
                log.Debug("Requested framework is {0}", requestedFramework);

            RuntimeType targetRuntime = requestedFramework.Runtime;
            Version targetVersion = requestedFramework.FrameworkVersion;

            if (targetRuntime == RuntimeType.Any)
                targetRuntime = currentFramework.Runtime;

            if (targetVersion == RuntimeFramework.DefaultVersion)
            {
                var packages = package.SubPackages;
                if (packages.Count == 0)
                    packages.Add(package);

                foreach (var subPackage in packages)
                {
                    var assembly = subPackage.FullName;

                    // If the file is not an assembly or doesn't exist, then it can't
                    // contribute any information to the decision, so we skip it.
                    if (PathUtils.IsAssemblyFileType(assembly) && File.Exists(assembly))
                    {
                        using (var reader = new AssemblyReader(assembly))
                        {
                            if (!reader.IsValidPeFile)
                                log.Debug("{0} is not a valid PE file", assembly);
                            else if (!reader.IsDotNetFile)
                                log.Debug("{0} is not a managed assembly", assembly);
                            else
                            {
                                if (reader.ShouldRun32Bit)
                                {
                                    package.Settings[PackageSettings.RunAsX86] = true;
                                    log.Debug("Assembly {0} will be run x86", assembly);
                                }

                                var imageRuntimeVersion = reader.ImageRuntimeVersion;
                                if (imageRuntimeVersion != null)
                                {
                                    var v = new Version(imageRuntimeVersion.Substring(1));
                                    log.Debug("Assembly {0} uses version {1}", assembly, v);

                                    // TODO: We are doing two jobs here: (1) getting the
                                    // target version and (2) applying a policy that says
                                    // we run under the highest version of all assemblies.
                                    // We should implement the policy at a higher level.
                                    if (v > targetVersion) targetVersion = v;
                                }
                            }
                        }
                    }
                }
                
                RuntimeFramework checkFramework = new RuntimeFramework(targetRuntime, targetVersion);
                if (!checkFramework.IsAvailable)
                {
                    log.Debug("Preferred version {0} is not installed or this NUnit installation does not support it", targetVersion);
                    if (targetVersion < currentFramework.FrameworkVersion)
                        targetVersion = currentFramework.FrameworkVersion;
                }
            }

            RuntimeFramework targetFramework = new RuntimeFramework(targetRuntime, targetVersion);
            package.Settings[PackageSettings.RuntimeFramework] = targetFramework.ToString();

            log.Debug("Test will use {0} framework", targetFramework);

            return targetFramework.ToString();
        }