/// <summary>
        /// Adapts the command line environment for Boost Test released in Boost 1.62
        /// </summary>
        /// <remarks>https://github.com/etas/vs-boost-unit-test-adapter/issues/158</remarks>
        /// <param name="args">The command line arguments/environment to adapt</param>
        /// <returns>An adapted 'args'</returns>
        private BoostTestRunnerCommandLineArgs AdaptArguments(BoostTestRunnerCommandLineArgs args)
        {
            // Boost Test for Boost 1.62 causes an incorrect cast issue with the --log_sink (and --report_sink) command line argument
            if (args.Log != Sink.StandardOutput)
            {
                // Make use of environment variables instead of command-line
                // arguments to retain support for Boost Test in Boost 1.61

                string logSink = args.Log.ToString();

                if (args.Log != Sink.StandardError)
                {
                    // Remove the ':' used as the volume separator since the Boost Test framework interprets it as a logger separator
                    logSink = ((Path.IsPathRooted(logSink) && (logSink[1] == ':')) ? logSink.Substring(2) : logSink);
                }

                // BOOST_TEST_LOGGER (--logger) overrides --log_sink, --log_format and --log_level
                args.Environment["BOOST_TEST_LOGGER"] = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0},{1},{2}",
                    BoostTestRunnerCommandLineArgs.OutputFormatToString(args.LogFormat),
                    BoostTestRunnerCommandLineArgs.LogLevelToString(args.LogLevel),
                    logSink
                    );
            }

            // Boost Test (Boost 1.62) --report_sink workaround - force report output to standard error due to cast issue with --report_sink
            args.Report = Sink.StandardError;
            if (string.IsNullOrEmpty(args.StandardErrorFile))
            {
                args.StandardErrorFile = TestPathGenerator.Generate(this.Source, FileExtensions.StdErrFile);
            }

            return(args);
        }
        /// <summary>
        /// Identify the version (if possible) of the Boost.Test module
        /// </summary>
        /// <param name="runner">The Boost.Test module</param>
        /// <returns>The Boost version of the Boost.Test module or the empty string if the version cannot be retrieved</returns>
        private static string GetVersion(IBoostTestRunner runner)
        {
            if (!runner.VersionSupported)
            {
                return(string.Empty);
            }

            using (TemporaryFile output = new TemporaryFile(TestPathGenerator.Generate(runner.Source, ".version.stderr.log")))
            {
                BoostTestRunnerSettings        settings = new BoostTestRunnerSettings();
                BoostTestRunnerCommandLineArgs args     = new BoostTestRunnerCommandLineArgs()
                {
                    Version           = true,
                    StandardErrorFile = output.Path
                };

                int resultCode = EXIT_SUCCESS;

                using (var context = new DefaultProcessExecutionContext())
                {
                    resultCode = runner.Execute(args, settings, context);
                }

                if (resultCode != EXIT_SUCCESS)
                {
                    Logger.Error("--version for {0} failed with exit code {1}. Skipping.", runner.Source, resultCode);
                    return(string.Empty);
                }

                var info = File.ReadAllText(args.StandardErrorFile, System.Text.Encoding.ASCII);

                var match = _versionPattern.Match(info);
                return((match.Success) ? match.Groups[1].Value : string.Empty);
            }
        }
        /// <summary>
        /// Factory function which returns an appropriate BoostTestRunnerCommandLineArgs structure
        /// </summary>
        /// <param name="source">The TestCases source</param>
        /// <param name="settings">The Boost Test adapter settings currently in use</param>
        /// <returns>A BoostTestRunnerCommandLineArgs structure for the provided source</returns>
        private BoostTestRunnerCommandLineArgs GetDefaultArguments(string source, BoostTestAdapterSettings settings)
        {
            BoostTestRunnerCommandLineArgs args = settings.CommandLineArgs.Clone();

            GetDebugConfigurationProperties(source, settings, args);

            // Specify log and report file information
            args.LogFormat = OutputFormat.XML;
            args.LogLevel  = settings.LogLevel;
            args.LogFile   = TestPathGenerator.Generate(source, FileExtensions.LogFile);

            args.ReportFormat = OutputFormat.XML;
            args.ReportLevel  = ReportLevel.Detailed;
            args.ReportFile   = TestPathGenerator.Generate(source, FileExtensions.ReportFile);

            args.StandardOutFile   = ((settings.EnableStdOutRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdOutFile) : null);
            args.StandardErrorFile = ((settings.EnableStdErrRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdErrFile) : null);

            return(args);
        }
예제 #4
0
        /// <summary>
        /// Factory function which returns an appropriate BoostTestRunnerCommandLineArgs structure
        /// </summary>
        /// <param name="source">The TestCases source</param>
        /// <param name="settings">The Boost Test adapter settings currently in use</param>
        /// <param name="debugMode">Determines whether the test should be debugged or not.</param>
        /// <returns>A BoostTestRunnerCommandLineArgs structure for the provided source</returns>
        private BoostTestRunnerCommandLineArgs GetDefaultArguments(string source, BoostTestAdapterSettings settings, bool debugMode)
        {
            BoostTestRunnerCommandLineArgs args = settings.CommandLineArgs.Clone();

            GetDebugConfigurationProperties(source, settings, args);

            // Specify log and report file information
            args.LogFormat = OutputFormat.XML;
            args.LogLevel  = settings.LogLevel;
            args.LogFile   = TestPathGenerator.Generate(source, FileExtensions.LogFile);

            args.ReportFormat = OutputFormat.XML;
            args.ReportLevel  = ReportLevel.Detailed;
            args.ReportFile   = TestPathGenerator.Generate(source, FileExtensions.ReportFile);

            args.StandardOutFile   = ((settings.EnableStdOutRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdOutFile) : null);
            args.StandardErrorFile = ((settings.EnableStdErrRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdErrFile) : null);

            // Set '--catch_system_errors' to 'yes' if the test is not being debugged
            // or if this value was not overridden via configuration before-hand
            args.CatchSystemErrors = args.CatchSystemErrors.GetValueOrDefault(false) || !debugMode;

            return(args);
        }
        public void DiscoverTests(IEnumerable <string> sources, IDiscoveryContext discoveryContext, ITestCaseDiscoverySink discoverySink)
        {
            Code.Require(sources, "sources");
            Code.Require(discoverySink, "discoverySink");

            // Populate loop-invariant attributes and settings

            BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);

            BoostTestRunnerFactoryOptions options = new BoostTestRunnerFactoryOptions()
            {
                ExternalTestRunnerSettings = settings.ExternalTestRunner
            };

            BoostTestRunnerSettings runnerSettings = new BoostTestRunnerSettings()
            {
                Timeout = settings.DiscoveryTimeoutMilliseconds
            };

            BoostTestRunnerCommandLineArgs args = new BoostTestRunnerCommandLineArgs()
            {
                ListContent = ListContentFormat.DOT
            };

            foreach (var source in sources)
            {
                try
                {
                    args.SetWorkingEnvironment(source, settings, ((_vsProvider == null) ? null : _vsProvider.Instance));
                }
                catch (COMException ex)
                {
                    Logger.Exception(ex, "Could not retrieve WorkingDirectory from Visual Studio Configuration");
                }

                try
                {
                    IBoostTestRunner runner = _factory.GetRunner(source, options);
                    using (TemporaryFile output = new TemporaryFile(TestPathGenerator.Generate(source, ".list.content.gv")))
                    {
                        // --list_content output is redirected to standard error
                        args.StandardErrorFile = output.Path;
                        Logger.Debug("list_content file: {0}", args.StandardErrorFile);

                        runner.Run(args, runnerSettings);

                        // Parse --list_content=DOT output
                        using (FileStream stream = File.OpenRead(args.StandardErrorFile))
                        {
                            TestFrameworkDOTDeserialiser deserialiser = new TestFrameworkDOTDeserialiser(source);

                            // Pass in a visitor to avoid a 2-pass loop in order to notify test cases to VS
                            //
                            // NOTE Due to deserialisation, make sure that only test cases are visited. Test
                            //      suites may be visited after their child test cases are visited.
                            deserialiser.Deserialise(stream, new VSDiscoveryVisitorTestsOnly(source, discoverySink));
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Exception(ex, "Exception caught while discovering tests for {0} ({1} - {2})", source, ex.Message, ex.HResult);
                }
            }
        }
        public void DiscoverTests(IEnumerable <string> sources, IDiscoveryContext discoveryContext, ITestCaseDiscoverySink discoverySink)
        {
            Code.Require(sources, "sources");
            Code.Require(discoverySink, "discoverySink");

            // Populate loop-invariant attributes and settings

            BoostTestAdapterSettings settings = BoostTestAdapterSettingsProvider.GetSettings(discoveryContext);

            BoostTestRunnerSettings runnerSettings = new BoostTestRunnerSettings()
            {
                Timeout = settings.DiscoveryTimeoutMilliseconds
            };

            BoostTestRunnerCommandLineArgs args = new BoostTestRunnerCommandLineArgs()
            {
                ListContent = ListContentFormat.DOT
            };

            foreach (var source in sources)
            {
                try
                {
                    var vs = _vsProvider?.Instance;
                    if (vs != null)
                    {
                        Logger.Debug("Connected to Visual Studio {0} instance", vs.Version);
                    }

                    args.SetWorkingEnvironment(source, settings, vs);
                }
                catch (ROTException ex)
                {
                    Logger.Exception(ex, "Could not retrieve WorkingDirectory from Visual Studio Configuration");
                }
                catch (COMException ex)
                {
                    Logger.Exception(ex, "Could not retrieve WorkingDirectory from Visual Studio Configuration");
                }

                try
                {
                    IBoostTestRunner runner = _factory.GetRunner(source, settings.TestRunnerFactoryOptions);
                    using (TemporaryFile output = new TemporaryFile(TestPathGenerator.Generate(source, ".list.content.gv")))
                    {
                        // --list_content output is redirected to standard error
                        args.StandardErrorFile = output.Path;
                        Logger.Debug("list_content file: {0}", args.StandardErrorFile);

                        int resultCode = EXIT_SUCCESS;

                        using (var context = new DefaultProcessExecutionContext())
                        {
                            resultCode = runner.Execute(args, runnerSettings, context);
                        }

                        // Skip sources for which the --list_content file is not available
                        if (!File.Exists(args.StandardErrorFile))
                        {
                            Logger.Error("--list_content=DOT output for {0} is not available. Skipping.", source);
                            continue;
                        }

                        // If the executable failed to exit with an EXIT_SUCCESS code, skip source and notify user accordingly
                        if (resultCode != EXIT_SUCCESS)
                        {
                            Logger.Error("--list_content=DOT for {0} failed with exit code {1}. Skipping.", source, resultCode);
                            continue;
                        }

                        // Parse --list_content=DOT output
                        using (FileStream stream = File.OpenRead(args.StandardErrorFile))
                        {
                            TestFrameworkDOTDeserialiser deserialiser = new TestFrameworkDOTDeserialiser(source);
                            TestFramework framework = deserialiser.Deserialise(stream);
                            if ((framework != null) && (framework.MasterTestSuite != null))
                            {
                                framework.MasterTestSuite.Apply(new VSDiscoveryVisitor(source, GetVersion(runner), discoverySink));
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Exception(ex, "Exception caught while discovering tests for {0} ({1} - {2})", source, ex.Message, ex.HResult);
                }
            }
        }