using System; using System.Drawing; using System.IO; using System.Threading; using System.Windows.Forms; using System.Windows.Threading; using log4net; namespace Core.Common.TestUtil { /// /// Used by WindowsFormsTestHelper and WpfTestHelper /// /// TODO: invert it - use GuiTestHelper as entry point in tests. /// public class GuiTestHelper { private static GuiTestHelper instance; private static readonly ILog log = LogManager.GetLogger(typeof(WindowsFormsTestHelper)); private static Form synchronizationForm; private static Exception exception; private static bool unhandledThreadExceptionOccured; private static bool appDomainExceptionOccured; static GuiTestHelper() { Control.CheckForIllegalCrossThreadCalls = true; Application.EnableVisualStyles(); InitializeSynchronizatonObject(); Dispatcher.CurrentDispatcher.UnhandledException += CurrentDispatcher_UnhandledException; AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException; Application.ThreadException += Application_ThreadException; } public static GuiTestHelper Instance { get { if (instance == null) { instance = new GuiTestHelper(); } return instance; } } /// /// Checks build_number environment variable to determine whether we run on the build server. /// public static bool IsBuildServer { get { return File.Exists("C:\\build.server") || File.Exists("D:\\build.server") || File.Exists("/tmp/build-server") || !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("BUILD_NUMBER")); } } public Exception Exception { get { return exception; } } public void RethrowUnhandledException() { if (unhandledThreadExceptionOccured) { throw new UnhandledException("Unhandled thread exception: " + exception.Message, exception, exception.StackTrace); } if (appDomainExceptionOccured) { throw new UnhandledException("Unhandled app domain exception: " + exception.Message, exception, exception.StackTrace); } } public static void Initialize() { exception = null; unhandledThreadExceptionOccured = false; appDomainExceptionOccured = false; } private static void CurrentDispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { unhandledThreadExceptionOccured = true; exception = e.Exception; log.Error("WPF exception occured: " + e.Exception.Message, e.Exception); } private static void InitializeSynchronizatonObject() { if (synchronizationForm == null) { synchronizationForm = new Form { ShowInTaskbar = false, WindowState = FormWindowState.Minimized, FormBorderStyle = FormBorderStyle.None }; synchronizationForm.Load += (sender, args) => synchronizationForm.Size = new Size(0, 0); var handle = synchronizationForm.Handle; //force get handle synchronizationForm.Show(); } } private static void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { appDomainExceptionOccured = true; exception = e.ExceptionObject as Exception; if (exception != null) { log.Error("Exception occured: " + exception.Message, exception); } else { log.Error("Unhandled exception occured: " + e.ExceptionObject); } } private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { unhandledThreadExceptionOccured = true; exception = e.Exception; log.Error("Windows.Forms exception occured: " + e.Exception.Message, e.Exception); } /// /// Defines unhandled exception which provides stack trace of inner exception as its stack trace. /// public class UnhandledException : Exception { private readonly string stackTrace; public UnhandledException(string message, Exception innerException, string stackTrace) : base(message, innerException) { this.stackTrace = stackTrace; } public override string StackTrace { get { return stackTrace; } } } } }