diff --git a/TUnit.Core.SourceGenerator/CodeGenerators/InfrastructureGenerator.cs b/TUnit.Core.SourceGenerator/CodeGenerators/InfrastructureGenerator.cs index bf25fae8cf..281ea2e7ba 100644 --- a/TUnit.Core.SourceGenerator/CodeGenerators/InfrastructureGenerator.cs +++ b/TUnit.Core.SourceGenerator/CodeGenerators/InfrastructureGenerator.cs @@ -187,8 +187,8 @@ private static bool ShouldLoadAssembly(IAssemblySymbol assembly, Compilation com return false; } - // Only load assemblies with physical locations - if (!HasPhysicalLocation(assembly, compilation)) + // Only load assemblies that will be available at runtime + if (!IsLoadableAtRuntime(assembly, compilation)) { return false; } @@ -223,12 +223,24 @@ private static bool IsTUnitFrameworkAssembly(IAssemblySymbol assembly) name.StartsWith("TUnit.Assertions.", StringComparison.Ordinal); } - private static bool HasPhysicalLocation(IAssemblySymbol assembly, Compilation compilation) + /// + /// Determines if an assembly will be loadable at runtime via Assembly.Load(). + /// Any assembly that has a corresponding reference in the compilation will be available + /// at runtime because it will either be: + /// - A compiled DLL in the output directory (for project references) + /// - A NuGet package assembly in the probing paths (for package references) + /// + private static bool IsLoadableAtRuntime(IAssemblySymbol assembly, Compilation compilation) { + // Find the MetadataReference that corresponds to this assembly symbol var correspondingReference = compilation.References.FirstOrDefault(r => SymbolEqualityComparer.Default.Equals(compilation.GetAssemblyOrModuleSymbol(r), assembly)); - return correspondingReference is PortableExecutableReference { FilePath: not null and not "" }; + // If there's a corresponding reference, the assembly will be available at runtime. + // This includes: + // - PortableExecutableReference: compiled DLLs (NuGet packages, project outputs) + // - CompilationReference: project-to-project references (will be compiled to DLLs) + return correspondingReference != null; } private static string GetAssemblyFullName(IAssemblySymbol assemblySymbol) diff --git a/TUnit.TestProject.Library/Hooks.cs b/TUnit.TestProject.Library/Hooks.cs index 217d5b6d0c..1f1ace727c 100644 --- a/TUnit.TestProject.Library/Hooks.cs +++ b/TUnit.TestProject.Library/Hooks.cs @@ -14,3 +14,28 @@ public void AfterTests(TestContext testContext) testContext.StateBag.Items["AfterHit"] = true; } } + +/// +/// Test session hook in a library project. +/// This tests the fix for https://github.com/thomhurst/TUnit/issues/4583 +/// where hooks in referenced library projects don't execute. +/// +public static class LibraryTestSessionHooks +{ + public static bool BeforeTestSessionWasExecuted { get; private set; } + public static bool AfterTestSessionWasExecuted { get; private set; } + + [Before(TestSession)] + public static Task BeforeTestSession() + { + BeforeTestSessionWasExecuted = true; + return Task.CompletedTask; + } + + [After(TestSession)] + public static Task AfterTestSession() + { + AfterTestSessionWasExecuted = true; + return Task.CompletedTask; + } +} diff --git a/TUnit.TestProject/Bugs/Issue4583/LibraryTestSessionHookTests.cs b/TUnit.TestProject/Bugs/Issue4583/LibraryTestSessionHookTests.cs new file mode 100644 index 0000000000..5a038f838e --- /dev/null +++ b/TUnit.TestProject/Bugs/Issue4583/LibraryTestSessionHookTests.cs @@ -0,0 +1,20 @@ +using TUnit.TestProject.Attributes; +using TUnit.TestProject.Library; + +namespace TUnit.TestProject.Bugs.Issue4583; + +/// +/// Reproduction test for https://github.com/thomhurst/TUnit/issues/4583 +/// Tests that [Before(TestSession)] hooks in REFERENCED LIBRARY projects are executed. +/// This is different from issue #4541 which tested hooks in the same project. +/// +[EngineTest(ExpectedResult.Pass)] +public class LibraryTestSessionHookTests +{ + [Test] + public async Task Verify_TestSession_Hook_In_Referenced_Library_Executed() + { + await Assert.That(LibraryTestSessionHooks.BeforeTestSessionWasExecuted).IsTrue() + .Because("[Before(TestSession)] hook in referenced library project should have executed"); + } +}