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