A game framework written with osu! in mind.
at master 3.9 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Diagnostics; 6using System.Linq; 7using System.Reflection; 8using NUnit.Framework; 9using NUnit.Framework.Internal; 10 11namespace osu.Framework.Development 12{ 13 public static class DebugUtils 14 { 15 public static bool IsNUnitRunning => is_nunit_running.Value; 16 17 private static readonly Lazy<bool> is_nunit_running = new Lazy<bool>(() => 18 { 19 var entry = Assembly.GetEntryAssembly(); 20 21 // when running under nunit + netcore, entry assembly becomes nunit itself (testhost, Version=15.0.0.0), which isn't what we want. 22 // when running under nunit + Rider > 2020.2 EAP6, entry assembly becomes ReSharperTestRunner[32|64], which isn't what we want. 23 bool entryIsKnownTestAssembly = entry != null && (entry.Location.Contains("testhost") || entry.Location.Contains("ReSharperTestRunner")); 24 25 // null assembly can indicate nunit, but it can also indicate native code (e.g. android). 26 // to distinguish nunit runs from android launches, check the class name of the current test. 27 // if no actual test is running, nunit will make up an ad-hoc test context, which we can match on 28 // to eliminate such false positives. 29 bool nullEntryWithActualTestContext = entry == null && TestContext.CurrentContext.Test.ClassName != typeof(TestExecutionContext.AdhocContext).FullName; 30 31 return entryIsKnownTestAssembly || nullEntryWithActualTestContext; 32 } 33 ); 34 35 private static readonly Lazy<Assembly> nunit_test_assembly = new Lazy<Assembly>(() => 36 { 37 Debug.Assert(IsNUnitRunning); 38 39 var testName = TestContext.CurrentContext.Test.ClassName; 40 return AppDomain.CurrentDomain.GetAssemblies().First(asm => asm.GetType(testName) != null); 41 } 42 ); 43 44 public static bool IsDebugBuild => is_debug_build.Value; 45 46 private static readonly Lazy<bool> is_debug_build = new Lazy<bool>(() => 47 isDebugAssembly(typeof(DebugUtils).Assembly) || isDebugAssembly(GetEntryAssembly()) 48 ); 49 50 /// <summary> 51 /// Whether the framework is currently logging performance issues. 52 /// This should be used only when a configuration is not available via DI or otherwise (ie. in a static context). 53 /// </summary> 54 public static bool LogPerformanceIssues { get; internal set; } 55 56 // https://stackoverflow.com/a/2186634 57 private static bool isDebugAssembly(Assembly assembly) => assembly?.GetCustomAttributes(false).OfType<DebuggableAttribute>().Any(da => da.IsJITTrackingEnabled) ?? false; 58 59 /// <summary> 60 /// Gets the entry assembly, or calling assembly otherwise. 61 /// When running under NUnit, the assembly of the current test will be returned instead. 62 /// </summary> 63 /// <returns>The entry assembly (usually obtained via <see cref="Assembly.GetEntryAssembly()"/>.</returns> 64 public static Assembly GetEntryAssembly() 65 { 66 if (IsNUnitRunning) 67 return nunit_test_assembly.Value; 68 69 return Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly(); 70 } 71 72 /// <summary> 73 /// Gets the absolute path to the directory containing the assembly determined by <see cref="GetEntryAssembly"/>. 74 /// </summary> 75 /// <returns>The entry path (usually obtained via the entry assembly's <see cref="Assembly.Location"/> directory.</returns> 76 [Obsolete("Use AppContext.BaseDirectory instead")] // Can be removed 20220211 77 public static string GetEntryPath() => AppContext.BaseDirectory; 78 } 79}