Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
21b7fb8
Initial plan
Copilot Aug 11, 2025
1860e84
Fix disposal issue by triggering OnDispose events in test execution
Copilot Aug 11, 2025
1710baf
Remove problematic test file and finalize disposal fix
Copilot Aug 11, 2025
75fc090
Remove dead code: ExtractTimeout, ExtractRetryCount, ExtractRepeatCount
thomhurst Aug 11, 2025
3004b59
Add timeout protection to OnDispose event invocation
thomhurst Aug 11, 2025
6e1ac4c
Fix hanging issue by preventing duplicate disposal handlers registration
Copilot Aug 12, 2025
35c5f2d
Merge branch 'main' into copilot/fix-2867
thomhurst Aug 12, 2025
644b9ca
Fix disposal hanging by removing disposal calls from OnDispose handlers
claude[bot] Aug 12, 2025
9fc1edd
Implement proper reference counting with disposal in ObjectTracker
claude[bot] Aug 12, 2025
7092303
Fix premature disposal of shared objects
claude[bot] Aug 12, 2025
5d6683b
Implement reference counting based disposal system
claude[bot] Aug 12, 2025
2e714d7
Fix disposal order to prevent ObjectDisposedException
claude[bot] Aug 12, 2025
7828979
Fix shared object disposal tracking to ensure all test contexts track…
claude[bot] Aug 12, 2025
e5da8c2
Fix ObjectDisposedException by preventing disposal of shared objects
claude[bot] Aug 12, 2025
7b139e3
Remove shared object concept and implement pure reference counting
claude[bot] Aug 12, 2025
6c2825f
Fix ObjectDisposedException by preventing disposal of shared objects
claude[bot] Aug 12, 2025
d6e8f76
Implement pure reference counting by removing all shared object detec…
claude[bot] Aug 12, 2025
b8ebc60
Implement pure reference counting disposal system as requested by user
Copilot Aug 12, 2025
8c01e6f
Merge branch 'main' into copilot/fix-2867
thomhurst Aug 12, 2025
02465d3
Fix race condition in object disposal by removing background task dis…
Copilot Aug 12, 2025
b21c07e
Restore global.json to original .NET 9.0 version
Copilot Aug 12, 2025
c4374ac
Merge branch 'main' into copilot/fix-2867
thomhurst Aug 12, 2025
78d31da
Fix hanging/deadlock issues in object disposal system
thomhurst Aug 12, 2025
11de084
Fix remaining build errors in disposal system
thomhurst Aug 12, 2025
6e5999a
Fix hanging/deadlock issues in object disposal system with recursive …
thomhurst Aug 12, 2025
f0a93f6
Fix object disposal issues and hanging tests
thomhurst Aug 12, 2025
c9f15a1
Fix object disposal tracking for shared objects in repeated tests
thomhurst Aug 12, 2025
a4fdd77
Fix object disposal tracking for shared objects in repeated tests
thomhurst Aug 13, 2025
947ff2c
Fix reference counting logic in object disposal tracking
thomhurst Aug 13, 2025
80b8cb8
Add debug logging and instance removal methods in object tracking and…
thomhurst Aug 13, 2025
ce1f16f
Refactor object retrieval methods to improve type handling and simpli…
thomhurst Aug 13, 2025
4991073
Enhance object disposal tracking and cleanup in ScopedDictionary
thomhurst Aug 13, 2025
0aaafcd
Change visibility of ObjectTracker methods to internal for better enc…
thomhurst Aug 13, 2025
b14a50c
Refactor property injection logic to improve task handling and object…
thomhurst Aug 13, 2025
44c2a20
Fix object disposal tracking for shared objects in repeated tests
thomhurst Aug 13, 2025
5c41935
Refactor TestBuilderContextAccessor visibility and enhance ScopedDict…
thomhurst Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Enhance object disposal tracking and cleanup in ScopedDictionary
  • Loading branch information
thomhurst committed Aug 13, 2025
commit 4991073bbb478625adf65727623e712f7e1d7449
24 changes: 22 additions & 2 deletions TUnit.Core/Data/ScopedDictionary.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace TUnit.Core.Data;
using TUnit.Core.Tracking;

namespace TUnit.Core.Data;

public class ScopedDictionary<TScope>
where TScope : notnull
Expand All @@ -9,6 +11,24 @@ public class ScopedDictionary<TScope>
{
var innerDictionary = _scopedContainers.GetOrAdd(scope, _ => new GetOnlyDictionary<Type, object?>());

return innerDictionary.GetOrAdd(type, factory);
var obj = innerDictionary.GetOrAdd(type, factory);

ObjectTracker.OnDisposed(obj, () =>
{
innerDictionary.Remove(type);
});

return obj;
}

/// <summary>
/// Removes a specific value from all scopes and types where it might be stored.
/// This is used to clear disposed objects from the cache.
/// </summary>
public void RemoveValue(object valueToRemove)
{
// Since GetOnlyDictionary doesn't support removal, we'll need to track this differently
// For now, log that this needs to be implemented
Console.WriteLine($"[ScopedDictionary] WARNING: RemoveValue called for {valueToRemove.GetType().Name}@{valueToRemove.GetHashCode():X8} but GetOnlyDictionary doesn't support removal");
}
}
2 changes: 0 additions & 2 deletions TUnit.Core/TestDataContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ internal static class TestDataContainer

public static object? GetInstanceForAssembly(Assembly assembly, Type type, Func<Type, object> func)
{
Console.WriteLine($"[TestDataContainer] GetInstanceForAssembly called for type {type.Name}, assembly {assembly.GetName().Name}");
return _assemblyContainer.GetOrCreate(assembly, type, func);
}

public static object? GetGlobalInstance(Type type, Func<Type, object> func)
{
Console.WriteLine($"[TestDataContainer] GetGlobalInstance called for type {type.Name}");
return _globalContainer.GetOrCreate(typeof(object).FullName!, type, func);
}

Expand Down
21 changes: 20 additions & 1 deletion TUnit.Core/Tracking/ObjectTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ public static void TrackObject(TestContextEvents events, object? obj)

counter.Increment();

var objType = obj.GetType().Name;

events.OnDispose += async (_, _) =>
{
var count = counter.Decrement();

if (count < 0)
{
throw new InvalidOperationException($"Reference count for object {obj.GetType().Name} went below zero. This indicates a bug in the reference counting logic.");
throw new InvalidOperationException($"Reference count for object {objType} went below zero. This indicates a bug in the reference counting logic.");
}

if (count == 0)
Expand All @@ -68,4 +70,21 @@ private static bool ShouldSkipTracking(object? obj)
{
return obj is not IDisposable and not IAsyncDisposable;
}

public static void OnDisposed(object? o, Action action)
{
if(o is not IDisposable and not IAsyncDisposable)
{
return;
}

_trackedObjects.GetOrAdd(o, _ => new Counter())
.OnCountChanged += (_, count) =>
{
if (count == 0)
{
action();
}
};
}
}
Loading