([]);
-
- const nodeTypes = {
- arrange: ArrangeNode,
- act: ActNode,
- assert: AssertNode,
- loop: LoopNode,
- conditional: ConditionalNode
- };
-
- const onNodeDragStop = (event: any, node: Node) => {
- // Update node position
- };
-
- const onConnect = (params: any) => {
- // Create new edge
- setEdges(eds => addEdge(params, eds));
- };
-
- const generateCode = async () => {
- const visual = {
- nodes,
- connections: edges,
- className: 'GeneratedTest',
- testName: 'TestMethod'
- };
-
- const response = await fetch('/api/visual-designer/compile', {
- method: 'POST',
- body: JSON.stringify(visual)
- });
-
- const { code } = await response.json();
- showGeneratedCode(code);
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-// Execution Heatmap
-import { HeatMapGrid } from 'react-grid-heatmap';
-
-export const TestExecutionHeatmap: React.FC = () => {
- const [data, setData] = useState(null);
-
- useEffect(() => {
- const eventSource = new EventSource('/api/visualization/heatmap/stream');
-
- eventSource.onmessage = (event) => {
- const update = JSON.parse(event.data);
- setData(current => mergeHeatmapData(current, update));
- };
-
- return () => eventSource.close();
- }, []);
-
- return (
- (
- showTestDetails(x, y)}
- />
- )}
- xLabelsStyle={() => ({
- fontSize: '0.8rem',
- transform: 'rotate(-45deg)'
- })}
- cellStyle={(x, y, value) => ({
- background: getHeatmapColor(value),
- cursor: 'pointer'
- })}
- />
- );
-};
-```
-
-### Real-time Dashboard
-```typescript
-// WebSocket connection for live updates
-export const LiveTestDashboard: React.FC = () => {
- const [connection, setConnection] = useState(null);
- const [testStats, setTestStats] = useState({});
-
- useEffect(() => {
- const newConnection = new HubConnectionBuilder()
- .withUrl('/testhub')
- .withAutomaticReconnect()
- .build();
-
- newConnection.on('TestUpdated', (event: TestExecutionEvent) => {
- setTestStats(current => updateStats(current, event));
- });
-
- newConnection.start();
- setConnection(newConnection);
-
- return () => {
- newConnection.stop();
- };
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-```
-
-### Integration Points
-1. **Test Execution Events**: Hook into test runner for real-time data
-2. **Code Coverage Tools**: Import coverage data for visualization
-3. **Git Integration**: Show test changes across commits
-4. **IDE Plugins**: Launch visualizations from IDE
-
-### Challenges & Solutions
-- **Large Test Suites**: Implement virtualization and pagination
-- **Real-time Performance**: Use WebSockets and incremental updates
-- **3D Rendering Performance**: LOD (Level of Detail) for large graphs
-- **Cross-browser Compatibility**: Progressive enhancement approach
-
----
-
-## 7. Semantic Snapshot Testing
-
-### Overview
-Built-in snapshot testing that understands the semantic meaning of changes, providing intelligent diffs and automatic versioning.
-
-### Key Benefits
-- **Intelligent Diffs**: Understand structural vs. cosmetic changes
-- **Partial Acceptance**: Accept some changes while rejecting others
-- **Format Awareness**: JSON, XML, HTML, Image-specific handling
-- **AI-Powered Analysis**: Explain why snapshots changed
-
-### Implementation Architecture
-
-#### Components
-1. **Snapshot Engine**
- - Format-specific serializers
- - Semantic diff algorithms
-
-2. **Storage System**
- - Version control integration
- - Efficient storage with deduplication
-
-3. **Review Interface**
- - Interactive diff viewer
- - Partial acceptance UI
-
-### Implementation Plan
-
-```csharp
-namespace TUnit.Snapshots
-{
- // Core snapshot testing infrastructure
- public class SnapshotAssertion
- {
- private readonly ISnapshotStore _store;
- private readonly ISnapshotSerializer _serializer;
- private readonly ISemanticDiffer _differ;
-
- public async Task MatchAsync(
- T actual,
- [CallerMemberName] string testName = "",
- [CallerFilePath] string filePath = "")
- {
- var snapshotId = GenerateSnapshotId(testName, filePath);
- var serialized = await _serializer.SerializeAsync(actual);
-
- var existing = await _store.GetSnapshotAsync(snapshotId);
- if (existing == null)
- {
- // First run - create snapshot
- await _store.SaveSnapshotAsync(snapshotId, serialized);
- throw new SnapshotNotFoundException(
- $"Snapshot created for {testName}. Review and commit.");
- }
-
- var diff = await _differ.CompareAsync(existing, serialized);
- if (!diff.IsEquivalent)
- {
- var analysis = await AnalyzeDifferenceAsync(diff);
- throw new SnapshotMismatchException(diff, analysis);
- }
- }
- }
-
- // Semantic diff engine
- public interface ISemanticDiffer
- {
- Task CompareAsync(Snapshot expected, Snapshot actual);
- }
-
- public class JsonSemanticDiffer : ISemanticDiffer
- {
- public async Task CompareAsync(Snapshot expected, Snapshot actual)
- {
- var expectedJson = JToken.Parse(expected.Content);
- var actualJson = JToken.Parse(actual.Content);
-
- var diff = new SemanticDiff();
- await CompareNodesAsync(expectedJson, actualJson, "", diff);
-
- // Classify changes
- foreach (var change in diff.Changes)
- {
- change.Severity = ClassifyChangeSeverity(change);
- change.Category = ClassifyChangeCategory(change);
- }
-
- return diff;
- }
-
- private async Task CompareNodesAsync(
- JToken expected,
- JToken actual,
- string path,
- SemanticDiff diff)
- {
- if (expected?.Type != actual?.Type)
- {
- diff.AddChange(new SemanticChange
- {
- Path = path,
- Type = ChangeType.TypeMismatch,
- Expected = expected?.Type.ToString(),
- Actual = actual?.Type.ToString()
- });
- return;
- }
-
- switch (expected)
- {
- case JObject expectedObj:
- await CompareObjectsAsync(
- expectedObj,
- (JObject)actual,
- path,
- diff);
- break;
-
- case JArray expectedArr:
- await CompareArraysAsync(
- expectedArr,
- (JArray)actual,
- path,
- diff);
- break;
-
- case JValue expectedVal:
- CompareValues(expectedVal, (JValue)actual, path, diff);
- break;
- }
- }
-
- private async Task CompareArraysAsync(
- JArray expected,
- JArray actual,
- string path,
- SemanticDiff diff)
- {
- // Try to match array elements semantically
- var matcher = new ArrayElementMatcher();
- var matches = await matcher.MatchElementsAsync(expected, actual);
-
- foreach (var match in matches)
- {
- if (match.IsMatch)
- {
- await CompareNodesAsync(
- match.Expected,
- match.Actual,
- $"{path}[{match.Index}]",
- diff);
- }
- else if (match.Expected != null)
- {
- diff.AddChange(new SemanticChange
- {
- Path = $"{path}[{match.Index}]",
- Type = ChangeType.Removed,
- Expected = match.Expected.ToString()
- });
- }
- else
- {
- diff.AddChange(new SemanticChange
- {
- Path = $"{path}[{match.Index}]",
- Type = ChangeType.Added,
- Actual = match.Actual.ToString()
- });
- }
- }
- }
- }
-
- // Image snapshot comparison
- public class ImageSemanticDiffer : ISemanticDiffer
- {
- private readonly IImageComparison _imageComparison;
-
- public async Task CompareAsync(Snapshot expected, Snapshot actual)
- {
- var expectedImage = LoadImage(expected.Content);
- var actualImage = LoadImage(actual.Content);
-
- var diff = new SemanticDiff();
-
- // Structural comparison
- if (expectedImage.Width != actualImage.Width ||
- expectedImage.Height != actualImage.Height)
- {
- diff.AddChange(new SemanticChange
- {
- Type = ChangeType.StructuralChange,
- Description = $"Image dimensions changed from " +
- $"{expectedImage.Width}x{expectedImage.Height} to " +
- $"{actualImage.Width}x{actualImage.Height}"
- });
- }
-
- // Visual comparison
- var visualDiff = await _imageComparison.CompareAsync(
- expectedImage,
- actualImage);
-
- if (visualDiff.DifferencePercentage > 0.01) // 1% threshold
- {
- diff.AddChange(new SemanticChange
- {
- Type = ChangeType.VisualChange,
- Description = $"{visualDiff.DifferencePercentage:P} visual difference",
- Metadata = new Dictionary
- {
- ["diffImage"] = visualDiff.DifferenceImage,
- ["regions"] = visualDiff.ChangedRegions
- }
- });
- }
-
- // Perceptual comparison (using SSIM)
- var perceptualSimilarity = CalculateSSIM(expectedImage, actualImage);
- if (perceptualSimilarity < 0.98)
- {
- diff.AddChange(new SemanticChange
- {
- Type = ChangeType.PerceptualChange,
- Description = $"Perceptual similarity: {perceptualSimilarity:P}"
- });
- }
-
- return diff;
- }
- }
-
- // AI-powered analysis
- public class AISnapshotAnalyzer
- {
- private readonly ILLMService _llmService;
-
- public async Task AnalyzeDifferenceAsync(
- SemanticDiff diff,
- Snapshot expected,
- Snapshot actual)
- {
- var prompt = BuildAnalysisPrompt(diff, expected, actual);
- var response = await _llmService.GenerateAsync(prompt);
-
- return new SnapshotAnalysis
- {
- Summary = response.Summary,
- LikelyReason = response.Reason,
- IsBreakingChange = response.IsBreaking,
- SuggestedAction = response.SuggestedAction,
- RelatedChanges = await FindRelatedChangesAsync(diff)
- };
- }
-
- private string BuildAnalysisPrompt(
- SemanticDiff diff,
- Snapshot expected,
- Snapshot actual)
- {
- return $@"
- Analyze this snapshot change:
-
- Expected: {expected.Content}
- Actual: {actual.Content}
-
- Changes detected:
- {string.Join("\n", diff.Changes.Select(c => c.ToString()))}
-
- Determine:
- 1. What likely caused this change
- 2. Is this a breaking change
- 3. Should this be accepted or investigated
- 4. Summarize the change in one sentence
- ";
- }
- }
-
- // Interactive review interface
- public class SnapshotReviewService
- {
- public class ReviewSession
- {
- public string SessionId { get; set; }
- public List Changes { get; set; }
- public Dictionary Decisions { get; set; }
- }
-
- public async Task StartReviewAsync(TestRun run)
- {
- var changes = await GetSnapshotChangesAsync(run);
-
- return new ReviewSession
- {
- SessionId = Guid.NewGuid().ToString(),
- Changes = changes,
- Decisions = new Dictionary()
- };
- }
-
- public async Task AcceptChangeAsync(
- string sessionId,
- string snapshotId,
- PartialAcceptance partial = null)
- {
- var session = await GetSessionAsync(sessionId);
- var change = session.Changes.First(c => c.SnapshotId == snapshotId);
-
- if (partial != null)
- {
- // Accept only specific parts of the change
- var newSnapshot = ApplyPartialAcceptance(
- change.Expected,
- change.Actual,
- partial);
-
- await _store.SaveSnapshotAsync(snapshotId, newSnapshot);
- }
- else
- {
- // Accept entire change
- await _store.SaveSnapshotAsync(snapshotId, change.Actual);
- }
-
- session.Decisions[snapshotId] = ReviewDecision.Accepted;
- }
- }
-}
-
-// Snapshot attributes for configuration
-[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
-public class SnapshotConfigAttribute : Attribute
-{
- public SnapshotFormat Format { get; set; } = SnapshotFormat.Auto;
- public bool IgnoreWhitespace { get; set; } = true;
- public bool IgnoreOrder { get; set; } = false;
- public string[] IgnoreProperties { get; set; }
- public double ImageTolerance { get; set; } = 0.01;
-}
-
-// Usage examples
-public class SnapshotTests
-{
- [Test]
- [SnapshotConfig(IgnoreProperties = new[] { "timestamp", "id" })]
- public async Task ApiResponse_MatchesSnapshot()
- {
- var response = await _api.GetUserAsync(123);
- await Snapshot.MatchAsync(response);
- }
-
- [Test]
- [SnapshotConfig(Format = SnapshotFormat.Image, ImageTolerance = 0.02)]
- public async Task UIRendering_MatchesSnapshot()
- {
- var screenshot = await _browser.TakeScreenshotAsync();
- await Snapshot.MatchAsync(screenshot);
- }
-
- [Test]
- public async Task HtmlOutput_MatchesSnapshot()
- {
- var html = RenderComponent();
-
- // Semantic HTML comparison ignores cosmetic changes
- await Snapshot.MatchAsync(html, options => options
- .IgnoreAttributes("class", "style")
- .NormalizeWhitespace()
- .IgnoreComments());
- }
-}
-```
-
-### Snapshot Storage Format
-```json
-{
- "version": "1.0",
- "id": "TestClass.TestMethod",
- "format": "json",
- "content": "...",
- "metadata": {
- "created": "2024-01-15T10:00:00Z",
- "lastModified": "2024-01-20T15:30:00Z",
- "hash": "sha256:abc123...",
- "testFrameworkVersion": "1.2.3"
- },
- "history": [
- {
- "version": 1,
- "date": "2024-01-15T10:00:00Z",
- "author": "user@example.com",
- "reason": "Initial snapshot"
- }
- ]
-}
-```
-
-### Integration Points
-1. **Version Control**: Git integration for snapshot files
-2. **CI/CD**: Automatic snapshot updates in PRs
-3. **Review Tools**: Web UI for reviewing changes
-4. **IDE Integration**: Inline snapshot preview and acceptance
-
-### Challenges & Solutions
-- **Large Snapshots**: Implement compression and deduplication
-- **Binary Files**: Use perceptual hashing for images
-- **Merge Conflicts**: Provide merge tools for snapshot files
-- **Performance**: Cache parsed snapshots in memory
-
----
-
-## 8. AI-Powered Test Generation and Maintenance
-
-### Overview
-Leverage LLMs to automatically generate test cases, suggest missing scenarios, and maintain tests when code changes.
-
-### Key Benefits
-- **Automatic Test Creation**: Generate tests from signatures and docs
-- **Natural Language Tests**: Describe intent, get implementation
-- **Test Maintenance**: Auto-update tests during refactoring
-- **Coverage Analysis**: AI suggests missing test scenarios
-
-### Implementation Architecture
-
-#### Components
-1. **LLM Integration Layer**
- - Multiple provider support (OpenAI, Anthropic, local models)
- - Prompt engineering and optimization
-
-2. **Code Analysis Engine**
- - Extract method signatures and documentation
- - Understand code intent and behavior
-
-3. **Test Generation Pipeline**
- - Generate, validate, and refine tests
- - Ensure compilable and runnable output
-
-### Implementation Plan
-
-```csharp
-namespace TUnit.AI
-{
- // Core AI test generation service
- public class AITestGenerationService
- {
- private readonly ILLMProvider _llmProvider;
- private readonly ICodeAnalyzer _codeAnalyzer;
- private readonly ITestValidator _testValidator;
-
- public async Task GenerateTestsAsync(
- MethodInfo method,
- TestGenerationOptions options = null)
- {
- options ??= TestGenerationOptions.Default;
-
- // Analyze method to understand behavior
- var analysis = await _codeAnalyzer.AnalyzeMethodAsync(method);
-
- // Build comprehensive prompt
- var prompt = BuildTestGenerationPrompt(analysis, options);
-
- // Generate tests with LLM
- var generatedCode = await _llmProvider.GenerateAsync(prompt, new LLMOptions
- {
- Temperature = 0.3, // Low temperature for consistent code
- MaxTokens = 2000,
- Model = options.PreferredModel ?? "gpt-4"
- });
-
- // Parse and validate generated tests
- var tests = ParseGeneratedTests(generatedCode);
- var validationResults = await _testValidator.ValidateAsync(tests);
-
- // Refine tests that don't compile or have issues
- if (validationResults.HasErrors)
- {
- tests = await RefineTestsAsync(tests, validationResults);
- }
-
- return new GeneratedTests
- {
- Method = method,
- Tests = tests,
- Coverage = await EstimateCoverageAsync(tests, method)
- };
- }
-
- private TestGenerationPrompt BuildTestGenerationPrompt(
- MethodAnalysis analysis,
- TestGenerationOptions options)
- {
- return new TestGenerationPrompt
- {
- SystemPrompt = @"
- You are an expert test engineer. Generate comprehensive unit tests
- for the given method. Include:
- - Happy path tests
- - Edge cases and boundary conditions
- - Error handling scenarios
- - Null/empty input handling
- - Performance considerations if relevant
-
- Use TUnit framework syntax and follow these patterns:
- - Use descriptive test names
- - Follow AAA pattern (Arrange, Act, Assert)
- - Include relevant test attributes
- - Mock dependencies appropriately
- ",
-
- UserPrompt = $@"
- Generate comprehensive tests for this method:
-
- ```csharp
- {analysis.MethodSignature}
- {analysis.MethodBody}
- ```
-
- Method Documentation:
- {analysis.Documentation}
-
- Dependencies:
- {string.Join("\n", analysis.Dependencies)}
-
- Related Types:
- {string.Join("\n", analysis.RelatedTypes)}
-
- Test Style: {options.TestStyle}
- Mocking Framework: {options.MockingFramework}
- Assertion Style: {options.AssertionStyle}
- "
- };
- }
- }
-
- // Natural language test description
- public class NaturalLanguageTestGenerator
- {
- private readonly ILLMProvider _llmProvider;
- private readonly ICodeGenerator _codeGenerator;
-
- public async Task GenerateFromDescriptionAsync(
- string description,
- TestContext context)
- {
- // Understand intent from natural language
- var intent = await _llmProvider.GenerateAsync($@"
- Analyze this test description and extract:
- 1. What is being tested
- 2. Setup requirements
- 3. Actions to perform
- 4. Expected outcomes
- 5. Edge cases mentioned
-
- Description: {description}
-
- Context:
- Project: {context.ProjectName}
- Class Under Test: {context.TargetClass}
- ");
-
- // Generate test implementation
- var testCode = await _codeGenerator.GenerateTestAsync(intent);
-
- // Add natural language as comment
- return $@"
- // Test Intent: {description}
- {testCode}
- ";
- }
- }
-
- // Automatic test repair/maintenance
- public class TestMaintenanceService
- {
- private readonly IChangeDetector _changeDetector;
- private readonly ITestRewriter _testRewriter;
- private readonly ILLMProvider _llmProvider;
-
- public async Task MaintainTestsAsync(
- CodeChange change)
- {
- // Detect what changed
- var impact = await _changeDetector.AnalyzeImpactAsync(change);
-
- if (impact.AffectedTests.Count == 0)
- return MaintenanceResult.NoChangesNeeded;
-
- var results = new List();
-
- foreach (var test in impact.AffectedTests)
- {
- var update = await UpdateTestAsync(test, change, impact);
- if (update.HasChanges)
- {
- results.Add(update);
- }
- }
-
- return new MaintenanceResult
- {
- UpdatedTests = results,
- Summary = await GenerateMaintenanceSummaryAsync(results)
- };
- }
-
- private async Task UpdateTestAsync(
- TestInfo test,
- CodeChange change,
- ImpactAnalysis impact)
- {
- // Determine update strategy
- var strategy = DetermineUpdateStrategy(change, impact);
-
- switch (strategy)
- {
- case UpdateStrategy.RenameOnly:
- return await _testRewriter.RenameReferencesAsync(test, change);
-
- case UpdateStrategy.SignatureChange:
- return await AdaptToSignatureChangeAsync(test, change);
-
- case UpdateStrategy.BehaviorChange:
- return await RegenerateTestAsync(test, change);
-
- default:
- return TestUpdate.NoChange;
- }
- }
-
- private async Task AdaptToSignatureChangeAsync(
- TestInfo test,
- CodeChange change)
- {
- var prompt = $@"
- The following method signature changed:
-
- Old: {change.OldSignature}
- New: {change.NewSignature}
-
- Update this test to work with the new signature:
- ```csharp
- {test.SourceCode}
- ```
-
- Preserve the test intent and assertions.
- Only modify what's necessary for compatibility.
- ";
-
- var updatedCode = await _llmProvider.GenerateAsync(prompt);
-
- return new TestUpdate
- {
- Test = test,
- NewCode = updatedCode,
- Reason = "Method signature changed",
- Confidence = 0.85
- };
- }
- }
-
- // Missing test scenario suggester
- public class TestScenarioSuggester
- {
- private readonly ICodeCoverageAnalyzer _coverageAnalyzer;
- private readonly ILLMProvider _llmProvider;
-
- public async Task> SuggestMissingTestsAsync(
- ClassInfo classInfo,
- TestCoverage currentCoverage)
- {
- // Analyze uncovered code paths
- var uncoveredPaths = await _coverageAnalyzer.GetUncoveredPathsAsync(
- classInfo,
- currentCoverage);
-
- var suggestions = new List();
-
- // Generate suggestions for each uncovered path
- foreach (var path in uncoveredPaths)
- {
- var suggestion = await GenerateSuggestionAsync(path, classInfo);
- if (suggestion.Priority > 0.5) // Threshold for relevance
- {
- suggestions.Add(suggestion);
- }
- }
-
- // Use AI to suggest additional scenarios
- var aiSuggestions = await GenerateAISuggestionsAsync(classInfo, currentCoverage);
- suggestions.AddRange(aiSuggestions);
-
- return suggestions.OrderByDescending(s => s.Priority).ToList();
- }
-
- private async Task> GenerateAISuggestionsAsync(
- ClassInfo classInfo,
- TestCoverage coverage)
- {
- var prompt = $@"
- Analyze this class and suggest missing test scenarios:
-
- Class: {classInfo.Name}
- Methods: {string.Join(", ", classInfo.Methods.Select(m => m.Name))}
- Current Coverage: {coverage.LinePercentage}%
-
- Existing Tests:
- {string.Join("\n", coverage.Tests.Select(t => t.Name))}
-
- Suggest important test scenarios that are likely missing.
- Focus on:
- - Edge cases
- - Error conditions
- - Boundary values
- - Concurrency issues
- - Security considerations
- ";
-
- var response = await _llmProvider.GenerateAsync(prompt);
- return ParseSuggestions(response);
- }
- }
-
- // Integration with IDE
- public class AITestGeneratorExtension : IVsPackage
- {
- public void GenerateTestsCommand(DTE2 dte)
- {
- var activeDocument = dte.ActiveDocument;
- var selection = GetSelectedMethod(activeDocument);
-
- if (selection != null)
- {
- var dialog = new TestGenerationDialog
- {
- Method = selection,
- Options = TestGenerationOptions.Default
- };
-
- if (dialog.ShowDialog() == true)
- {
- Task.Run(async () =>
- {
- var tests = await _generator.GenerateTestsAsync(
- selection,
- dialog.Options);
-
- AddTestsToProject(tests);
- });
- }
- }
- }
- }
-}
-
-// Configuration and options
-public class TestGenerationOptions
-{
- public string PreferredModel { get; set; } = "gpt-4";
- public TestStyle TestStyle { get; set; } = TestStyle.AAA;
- public string MockingFramework { get; set; } = "Moq";
- public string AssertionStyle { get; set; } = "FluentAssertions";
- public bool IncludeEdgeCases { get; set; } = true;
- public bool IncludePerformanceTests { get; set; } = false;
- public bool GenerateDataDrivenTests { get; set; } = true;
- public int MaxTestsPerMethod { get; set; } = 10;
-}
-
-// Usage examples
-public class AITestUsageExamples
-{
- [GenerateTests] // Attribute to auto-generate tests
- public int CalculateDiscount(Order order, Customer customer)
- {
- // AI will analyze this method and generate comprehensive tests
- if (order == null) throw new ArgumentNullException(nameof(order));
-
- var discount = 0;
- if (customer.IsVIP) discount += 10;
- if (order.Total > 100) discount += 5;
- if (order.Items.Count > 5) discount += 3;
-
- return Math.Min(discount, 20);
- }
-
- [NaturalLanguageTest(@"
- Test that VIP customers get 10% discount,
- regular customers with orders over $100 get 5% discount,
- and the maximum discount is capped at 20%
- ")]
- public void DiscountCalculation_TestScenarios()
- {
- // Test implementation generated from natural language description
- }
-}
-```
-
-### LLM Provider Abstraction
-```csharp
-public interface ILLMProvider
-{
- Task GenerateAsync(string prompt, LLMOptions options = null);
- Task> GenerateMultipleAsync(string prompt, int count, LLMOptions options = null);
- Task GetEmbeddingAsync(string text);
-}
-
-public class OpenAIProvider : ILLMProvider
-{
- private readonly OpenAIClient _client;
-
- public async Task GenerateAsync(string prompt, LLMOptions options = null)
- {
- var response = await _client.Completions.CreateAsync(new CompletionRequest
- {
- Model = options?.Model ?? "gpt-4",
- Prompt = prompt,
- Temperature = options?.Temperature ?? 0.7,
- MaxTokens = options?.MaxTokens ?? 1000
- });
-
- return response.Choices[0].Text;
- }
-}
-
-public class LocalLLMProvider : ILLMProvider
-{
- // Implementation for local models (LLaMA, etc.)
-}
-```
-
-### Integration Points
-1. **IDE Plugins**: Context menu options for test generation
-2. **CLI Tools**: Command-line test generation
-3. **Git Hooks**: Auto-update tests on commit
-4. **CI/CD**: Generate missing tests in PR checks
-
-### Challenges & Solutions
-- **Code Quality**: Validate and refine generated tests
-- **Context Limits**: Chunk large methods and combine results
-- **Cost Management**: Cache results and use local models when possible
-- **Security**: Never send sensitive code to external APIs
-
----
-
-## 9. Performance Profiling Built-In
-
-### Overview
-Automatic performance profiling and regression detection integrated directly into the test framework.
-
-### Key Benefits
-- **Automatic Regression Detection**: Catch performance issues early
-- **Memory Leak Detection**: Identify memory issues in tests
-- **Historical Tracking**: Track performance over time
-- **Flame Graphs**: Visualize performance bottlenecks
-
-### Implementation Architecture
-
-#### Components
-1. **Profiling Engine**
- - CPU and memory profiling
- - Minimal overhead instrumentation
-
-2. **Regression Detector**
- - Statistical analysis of performance
- - Automatic baseline management
-
-3. **Visualization Tools**
- - Flame graphs and timeline views
- - Performance dashboards
-
-### Implementation Plan
-
-```csharp
-namespace TUnit.Performance
-{
- // Performance profiling attributes
- [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
- public class PerformanceTestAttribute : TestAttribute
- {
- public int WarmupIterations { get; set; } = 3;
- public int Iterations { get; set; } = 10;
- public double MaxDurationMs { get; set; } = double.MaxValue;
- public double MaxMemoryMB { get; set; } = double.MaxValue;
- public double RegressionThreshold { get; set; } = 0.1; // 10%
- }
-
- [AttributeUsage(AttributeTargets.Method)]
- public class BenchmarkAttribute : PerformanceTestAttribute
- {
- public bool TrackHistory { get; set; } = true;
- public bool GenerateFlameGraph { get; set; } = false;
- }
-
- // Core profiling engine
- public class PerformanceProfiler
- {
- private readonly IProfilerSession _session;
- private readonly IMetricsCollector _metrics;
-
- public async Task ProfileAsync(
- Func action,
- ProfileOptions options)
- {
- // Warmup iterations
- for (int i = 0; i < options.WarmupIterations; i++)
- {
- await action();
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- }
-
- var results = new List();
-
- // Actual profiling iterations
- for (int i = 0; i < options.Iterations; i++)
- {
- var iteration = await ProfileIterationAsync(action);
- results.Add(iteration);
- }
-
- return new PerformanceResult
- {
- Duration = CalculateStats(results.Select(r => r.Duration)),
- Memory = CalculateStats(results.Select(r => r.MemoryDelta)),
- Allocations = CalculateStats(results.Select(r => r.Allocations)),
- GCCollections = CalculateGCStats(results),
- CPUProfile = options.CaptureCPUProfile ?
- await CaptureCPUProfileAsync(action) : null,
- FlameGraph = options.GenerateFlameGraph ?
- await GenerateFlameGraphAsync(action) : null
- };
- }
-
- private async Task ProfileIterationAsync(Func action)
- {
- // Start profiling
- _session.Start();
-
- var startMemory = GC.GetTotalMemory(false);
- var startAllocations = GC.GetTotalAllocatedBytes();
- var startGC = GetGCCounts();
-
- var stopwatch = Stopwatch.StartNew();
-
- try
- {
- await action();
- }
- finally
- {
- stopwatch.Stop();
- _session.Stop();
- }
-
- var endMemory = GC.GetTotalMemory(false);
- var endAllocations = GC.GetTotalAllocatedBytes();
- var endGC = GetGCCounts();
-
- return new IterationResult
- {
- Duration = stopwatch.Elapsed,
- MemoryDelta = endMemory - startMemory,
- Allocations = endAllocations - startAllocations,
- GCGen0 = endGC.Gen0 - startGC.Gen0,
- GCGen1 = endGC.Gen1 - startGC.Gen1,
- GCGen2 = endGC.Gen2 - startGC.Gen2,
- ProfileData = _session.GetData()
- };
- }
- }
-
- // Memory leak detection
- public class MemoryLeakDetector
- {
- private readonly WeakReferenceTracker _tracker;
-
- public async Task DetectLeaksAsync(
- Func testAction)
- {
- // Track objects before test
- _tracker.StartTracking();
-
- // Run test
- await testAction();
-
- // Force garbage collection
- for (int i = 0; i < 3; i++)
- {
- GC.Collect();
- GC.WaitForPendingFinalizers();
- }
-
- // Check for leaked objects
- var leakedObjects = _tracker.GetLeakedObjects();
-
- if (leakedObjects.Any())
- {
- return new MemoryLeakReport
- {
- HasLeaks = true,
- LeakedObjects = leakedObjects,
- RetentionPaths = await AnalyzeRetentionPathsAsync(leakedObjects)
- };
- }
-
- return MemoryLeakReport.NoLeaks;
- }
-
- private async Task> AnalyzeRetentionPathsAsync(
- List objects)
- {
- var paths = new List();
-
- foreach (var obj in objects)
- {
- var path = await FindRetentionPathAsync(obj);
- if (path != null)
- {
- paths.Add(path);
- }
- }
-
- return paths;
- }
- }
-
- // Performance regression detection
- public class RegressionDetector
- {
- private readonly IPerformanceHistory _history;
- private readonly IStatisticalAnalyzer _analyzer;
-
- public async Task AnalyzeAsync(
- string testId,
- PerformanceResult current)
- {
- // Get historical data
- var history = await _history.GetHistoryAsync(testId, days: 30);
-
- if (history.Count < 5)
- {
- return RegressionAnalysis.InsufficientData;
- }
-
- // Calculate baseline using statistical methods
- var baseline = CalculateBaseline(history);
-
- // Perform statistical tests
- var durationRegression = _analyzer.DetectRegression(
- baseline.Duration,
- current.Duration,
- RegressionType.Duration);
-
- var memoryRegression = _analyzer.DetectRegression(
- baseline.Memory,
- current.Memory,
- RegressionType.Memory);
-
- return new RegressionAnalysis
- {
- HasRegression = durationRegression.IsSignificant ||
- memoryRegression.IsSignificant,
- DurationAnalysis = durationRegression,
- MemoryAnalysis = memoryRegression,
- Baseline = baseline,
- Current = current,
- Confidence = CalculateConfidence(history.Count)
- };
- }
-
- private PerformanceBaseline CalculateBaseline(
- List history)
- {
- // Use robust statistics (median, MAD) to handle outliers
- return new PerformanceBaseline
- {
- Duration = new RobustStats
- {
- Median = Median(history.Select(h => h.Duration.Median)),
- MAD = MedianAbsoluteDeviation(history.Select(h => h.Duration.Median)),
- P95 = Percentile(history.Select(h => h.Duration.P95), 95)
- },
- Memory = new RobustStats
- {
- Median = Median(history.Select(h => h.Memory.Median)),
- MAD = MedianAbsoluteDeviation(history.Select(h => h.Memory.Median)),
- P95 = Percentile(history.Select(h => h.Memory.P95), 95)
- }
- };
- }
- }
-
- // Flame graph generation
- public class FlameGraphGenerator
- {
- private readonly IStackTraceCollector _collector;
-
- public async Task GenerateAsync(
- Func action,
- FlameGraphOptions options)
- {
- // Collect stack traces
- var stacks = await _collector.CollectAsync(action, options.SampleRate);
-
- // Build flame graph data structure
- var root = new FlameGraphNode("root");
-
- foreach (var stack in stacks)
- {
- var current = root;
- foreach (var frame in stack.Frames.Reverse())
- {
- var child = current.GetOrAddChild(frame.Method);
- child.Samples++;
- child.Duration += stack.Duration;
- current = child;
- }
- }
-
- // Prune insignificant nodes
- PruneTree(root, options.MinSamplePercent);
-
- return new FlameGraph
- {
- Root = root,
- TotalSamples = stacks.Count,
- TotalDuration = stacks.Sum(s => s.Duration),
- Metadata = CollectMetadata(stacks)
- };
- }
-
- public string RenderSVG(FlameGraph graph)
- {
- var svg = new StringBuilder();
- svg.AppendLine(@"");
- return svg.ToString();
- }
- }
-
- // Historical tracking
- public class PerformanceHistory
- {
- private readonly IHistoryStore _store;
-
- public async Task RecordAsync(
- string testId,
- PerformanceResult result)
- {
- var entry = new HistoryEntry
- {
- TestId = testId,
- Timestamp = DateTime.UtcNow,
- Result = result,
- Environment = CaptureEnvironment(),
- GitCommit = GetCurrentGitCommit()
- };
-
- await _store.SaveAsync(entry);
-
- // Update trends
- await UpdateTrendsAsync(testId, result);
- }
-
- public async Task GetTrendAsync(
- string testId,
- TimeSpan window)
- {
- var history = await _store.GetHistoryAsync(testId, window);
-
- return new PerformanceTrend
- {
- TestId = testId,
- DataPoints = history.Select(h => new TrendPoint
- {
- Timestamp = h.Timestamp,
- Duration = h.Result.Duration.Median,
- Memory = h.Result.Memory.Median
- }).ToList(),
- DurationTrend = CalculateTrend(history.Select(h => h.Result.Duration.Median)),
- MemoryTrend = CalculateTrend(history.Select(h => h.Result.Memory.Median)),
- Anomalies = DetectAnomalies(history)
- };
- }
- }
-}
-
-// Usage examples
-public class PerformanceTests
-{
- [Benchmark(Iterations = 100, GenerateFlameGraph = true)]
- public async Task DatabaseQuery_Performance()
- {
- await _repository.GetUsersAsync();
- }
-
- [PerformanceTest(MaxDurationMs = 100, MaxMemoryMB = 10)]
- public async Task CriticalPath_MeetsPerformanceRequirements()
- {
- var result = await ProcessOrderAsync(CreateTestOrder());
- // Test will fail if duration > 100ms or memory > 10MB
- }
-
- [Test]
- [DetectMemoryLeaks]
- public async Task NoMemoryLeaks_InLongRunningOperation()
- {
- for (int i = 0; i < 1000; i++)
- {
- await PerformOperationAsync();
- }
- // Test will fail if memory leaks are detected
- }
-}
-```
-
-### Integration Points
-1. **CI/CD Integration**: Performance gates in build pipelines
-2. **Monitoring Systems**: Export metrics to Prometheus/Grafana
-3. **IDE Integration**: Show performance hints in editor
-4. **Git Integration**: Track performance per commit
-
-### Challenges & Solutions
-- **Overhead**: Use sampling profilers for low overhead
-- **Noise**: Statistical methods to filter out noise
-- **Environment Differences**: Normalize results across environments
-- **Storage**: Efficient storage with data retention policies
-
----
-
-## 10. Test Context Preservation
-
-### Overview
-Save and share complete test execution contexts including database states, file systems, and external dependencies.
-
-### Key Benefits
-- **Reproducible Failures**: Share exact failure conditions
-- **Team Collaboration**: Share test contexts across team
-- **Environment Provisioning**: Automatic setup from saved contexts
-- **Time Travel**: Restore to any previous test state
-
-### Implementation Architecture
-
-#### Components
-1. **Context Capture Engine**
- - Database state snapshots
- - File system captures
- - External service mocking
-
-2. **Context Storage**
- - Efficient storage with deduplication
- - Version control for contexts
-
-3. **Context Replay Engine**
- - Restore saved contexts
- - Environment provisioning
-
-### Implementation Plan
-
-```csharp
-namespace TUnit.ContextPreservation
-{
- // Core context preservation system
- public class TestContextManager
- {
- private readonly List _providers;
- private readonly IContextStore _store;
-
- public async Task CaptureAsync(string testId)
- {
- var context = new TestContext
- {
- Id = Guid.NewGuid().ToString(),
- TestId = testId,
- Timestamp = DateTime.UtcNow,
- Providers = new Dictionary()
- };
-
- // Capture from all providers
- foreach (var provider in _providers)
- {
- var providerContext = await provider.CaptureAsync();
- context.Providers[provider.Name] = providerContext;
- }
-
- // Store context
- await _store.SaveAsync(context);
-
- return context;
- }
-
- public async Task RestoreAsync(string contextId)
- {
- var context = await _store.LoadAsync(contextId);
-
- // Restore in dependency order
- var sortedProviders = TopologicalSort(_providers);
-
- foreach (var provider in sortedProviders)
- {
- if (context.Providers.TryGetValue(provider.Name, out var providerContext))
- {
- await provider.RestoreAsync(providerContext);
- }
- }
- }
- }
-
- // Database context provider
- public class DatabaseContextProvider : IContextProvider
- {
- private readonly IDbConnection _connection;
-
- public async Task CaptureAsync()
- {
- var tables = await GetTablesAsync();
- var context = new DatabaseContext();
-
- foreach (var table in tables)
- {
- // Capture schema
- context.Schemas[table] = await CaptureSchemaAsync(table);
-
- // Capture data
- context.Data[table] = await CaptureDataAsync(table);
-
- // Capture indexes and constraints
- context.Indexes[table] = await CaptureIndexesAsync(table);
- context.Constraints[table] = await CaptureConstraintsAsync(table);
- }
-
- // Capture sequences, triggers, etc.
- context.Sequences = await CaptureSequencesAsync();
- context.Triggers = await CaptureTriggersAsync();
-
- return context;
- }
-
- public async Task RestoreAsync(ProviderContext context)
- {
- var dbContext = context as DatabaseContext;
-
- // Begin transaction for atomic restore
- using var transaction = _connection.BeginTransaction();
-
- try
- {
- // Disable constraints temporarily
- await DisableConstraintsAsync();
-
- // Clear existing data
- foreach (var table in dbContext.Data.Keys)
- {
- await TruncateTableAsync(table);
- }
-
- // Restore schemas if needed
- foreach (var (table, schema) in dbContext.Schemas)
- {
- await EnsureSchemaAsync(table, schema);
- }
-
- // Restore data
- foreach (var (table, data) in dbContext.Data)
- {
- await BulkInsertAsync(table, data);
- }
-
- // Restore sequences
- foreach (var sequence in dbContext.Sequences)
- {
- await RestoreSequenceAsync(sequence);
- }
-
- // Re-enable constraints
- await EnableConstraintsAsync();
-
- transaction.Commit();
- }
- catch
- {
- transaction.Rollback();
- throw;
- }
- }
- }
-
- // File system context provider
- public class FileSystemContextProvider : IContextProvider
- {
- private readonly string _rootPath;
-
- public async Task CaptureAsync()
- {
- var context = new FileSystemContext();
-
- // Capture directory structure
- context.Structure = await CaptureDirectoryStructureAsync(_rootPath);
-
- // Capture file contents and metadata
- await CaptureFilesAsync(_rootPath, context);
-
- // Compress for efficient storage
- context.CompressedData = await CompressContextAsync(context);
-
- return context;
- }
-
- private async Task CaptureFilesAsync(string path, FileSystemContext context)
- {
- foreach (var file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
- {
- var relativePath = Path.GetRelativePath(_rootPath, file);
-
- context.Files[relativePath] = new FileContext
- {
- Content = await File.ReadAllBytesAsync(file),
- Attributes = File.GetAttributes(file),
- CreatedTime = File.GetCreationTimeUtc(file),
- ModifiedTime = File.GetLastWriteTimeUtc(file),
- Permissions = GetFilePermissions(file)
- };
- }
- }
- }
-
- // HTTP service context provider
- public class HttpServiceContextProvider : IContextProvider
- {
- private readonly HttpClient _httpClient;
- private readonly List _endpoints;
-
- public async Task CaptureAsync()
- {
- var context = new HttpServiceContext();
-
- foreach (var endpoint in _endpoints)
- {
- // Capture current state
- var response = await _httpClient.GetAsync(endpoint.StateUrl);
- context.States[endpoint.Name] = await response.Content.ReadAsStringAsync();
-
- // Capture mock responses if in mock mode
- if (endpoint.IsMocked)
- {
- context.MockResponses[endpoint.Name] = await CaptureMockResponsesAsync(endpoint);
- }
- }
-
- return context;
- }
-
- public async Task RestoreAsync(ProviderContext context)
- {
- var httpContext = context as HttpServiceContext;
-
- foreach (var (service, state) in httpContext.States)
- {
- var endpoint = _endpoints.First(e => e.Name == service);
-
- if (endpoint.IsMocked)
- {
- // Configure mock responses
- await ConfigureMockAsync(endpoint, httpContext.MockResponses[service]);
- }
- else
- {
- // Restore actual service state if possible
- await RestoreServiceStateAsync(endpoint, state);
- }
- }
- }
- }
-
- // Context sharing and collaboration
- public class ContextSharingService
- {
- private readonly IContextStore _localStore;
- private readonly ICloudStorage _cloudStorage;
-
- public async Task ShareContextAsync(string contextId, ShareOptions options)
- {
- var context = await _localStore.LoadAsync(contextId);
-
- // Upload to cloud storage
- var cloudUrl = await _cloudStorage.UploadAsync(context, options);
-
- // Generate shareable link
- var shareLink = GenerateShareLink(cloudUrl, options);
-
- // Create share record
- await RecordShareAsync(new ShareRecord
- {
- ContextId = contextId,
- ShareLink = shareLink,
- ExpiresAt = options.Expiration,
- Permissions = options.Permissions
- });
-
- return shareLink;
- }
-
- public async Task ImportSharedContextAsync(string shareLink)
- {
- // Validate and parse share link
- var shareInfo = ParseShareLink(shareLink);
-
- // Download from cloud storage
- var context = await _cloudStorage.DownloadAsync(shareInfo.CloudUrl);
-
- // Validate integrity
- if (!await ValidateContextIntegrityAsync(context))
- {
- throw new CorruptedContextException();
- }
-
- // Import to local store
- await _localStore.SaveAsync(context);
-
- return context;
- }
- }
-
- // Context-aware test execution
- public class ContextAwareTestRunner
- {
- private readonly ITestRunner _testRunner;
- private readonly TestContextManager _contextManager;
-
- public async Task RunWithContextAsync(
- TestCase test,
- string contextId = null)
- {
- // Restore context if provided
- if (!string.IsNullOrEmpty(contextId))
- {
- await _contextManager.RestoreAsync(contextId);
- }
-
- try
- {
- // Run test
- var result = await _testRunner.RunAsync(test);
-
- // Capture context on failure
- if (result.Failed && test.CaptureContextOnFailure)
- {
- result.FailureContext = await _contextManager.CaptureAsync(test.Id);
- }
-
- return result;
- }
- finally
- {
- // Cleanup if needed
- if (test.CleanupAfterRun)
- {
- await CleanupContextAsync();
- }
- }
- }
- }
-}
-
-// Configuration
-public class ContextPreservationConfig
-{
- public bool EnableAutoCapture { get; set; } = true;
- public bool CaptureOnFailure { get; set; } = true;
- public List ProvidersToInclude { get; set; } = new() { "Database", "FileSystem" };
- public StorageOptions Storage { get; set; } = new()
- {
- MaxSizeMB = 100,
- CompressionLevel = CompressionLevel.Optimal,
- RetentionDays = 30
- };
-}
-
-// Usage examples
-public class ContextPreservationTests
-{
- [Test]
- [PreserveContext]
- public async Task ComplexIntegrationTest()
- {
- // Test will automatically capture context on failure
- await SetupComplexDataAsync();
- var result = await PerformComplexOperationAsync();
- Assert.That(result).IsSuccessful();
- }
-
- [Test]
- [RestoreContext("context-12345")]
- public async Task ReplayFailedTest()
- {
- // Restore exact context from previous failure
- var result = await PerformOperationAsync();
- // Debug with exact same conditions
- }
-
- [Test]
- public async Task ShareTestContext()
- {
- // Capture current context
- var context = await TestContext.CaptureCurrentAsync();
-
- // Share with team
- var shareLink = await context.ShareAsync(new ShareOptions
- {
- Expiration = DateTime.UtcNow.AddDays(7),
- Permissions = SharePermissions.ReadOnly
- });
-
- // Team member can import: await TestContext.ImportAsync(shareLink);
- }
-}
-```
-
-### Storage Format
-```json
-{
- "version": "1.0",
- "id": "ctx-abc123",
- "testId": "TestClass.TestMethod",
- "timestamp": "2024-01-15T10:00:00Z",
- "environment": {
- "os": "Windows 11",
- "runtime": ".NET 8.0",
- "machine": "DEV-001"
- },
- "providers": {
- "database": {
- "type": "SqlServer",
- "compressed": true,
- "data": "base64_encoded_compressed_data"
- },
- "fileSystem": {
- "rootPath": "C:\\TestData",
- "fileCount": 42,
- "totalSize": 1048576,
- "data": "base64_encoded_compressed_data"
- }
- }
-}
-```
-
-### Integration Points
-1. **Docker Integration**: Export contexts as Docker images
-2. **CI/CD Systems**: Restore contexts in pipeline
-3. **Cloud Storage**: S3/Azure Blob integration
-4. **Version Control**: Store lightweight contexts in git
-
-### Challenges & Solutions
-- **Large Contexts**: Incremental capture and compression
-- **Security**: Encryption for sensitive data
-- **Versioning**: Handle schema/format changes
-- **Performance**: Async capture to avoid blocking tests
-
----
-
-## Implementation Roadmap
-
-### Phase 1: Foundation (Months 1-3)
-1. Smart Test Orchestration - Core ML infrastructure
-2. Performance Profiling - Basic profiling capabilities
-3. Property-Based Testing - Core generators and runners
-
-### Phase 2: Intelligence (Months 4-6)
-4. Live Test Impact Analysis - Roslyn integration
-5. AI-Powered Test Generation - LLM integration
-6. Semantic Snapshot Testing - Smart comparison engine
-
-### Phase 3: Scale (Months 7-9)
-7. Zero-Config Distributed Execution - Agent infrastructure
-8. Time-Travel Debugging - Recording and replay
-9. Test Context Preservation - Context management
-
-### Phase 4: Polish (Months 10-12)
-10. Interactive Visualization - Web UI and dashboards
-11. IDE Integration - VS and Rider extensions
-12. Documentation and Examples
-
-## Success Metrics
-
-- **Adoption Rate**: Number of projects using TUnit
-- **Test Execution Speed**: % improvement over other frameworks
-- **Developer Satisfaction**: Survey scores and feedback
-- **Bug Detection Rate**: Issues found via new features
-- **Community Growth**: Contributors and extensions
-
-## Conclusion
-
-These ten innovative features would position TUnit as the most advanced, intelligent, and developer-friendly testing framework in the .NET ecosystem. By focusing on real pain points and leveraging cutting-edge technology, TUnit would offer compelling reasons for teams to migrate from existing frameworks.
-
-The implementation plan provides a clear technical roadmap with detailed architectures, code examples, and solutions to anticipated challenges. With proper execution, TUnit could revolutionize how .NET developers approach testing.
\ No newline at end of file
diff --git a/TUnit.Engine.Tests/FSharp.cs b/TUnit.Engine.Tests/FSharp.cs
index 068f714cfb..4d8df10074 100644
--- a/TUnit.Engine.Tests/FSharp.cs
+++ b/TUnit.Engine.Tests/FSharp.cs
@@ -24,7 +24,7 @@ public async Task Test()
"--configuration", "Release",
"--report-trx", "--report-trx-filename", trxFilename,
"--diagnostic-verbosity", "Debug",
- "--diagnostic", "--diagnostic-output-fileprefix", $"log_{GetType().Name}_",
+ "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_",
"--timeout", "5m",
// "--hangdump", "--hangdump-filename", $"hangdump.tests-{guid}.dmp", "--hangdump-timeout", "3m",
diff --git a/TUnit.Engine.Tests/InvokableTestBase.cs b/TUnit.Engine.Tests/InvokableTestBase.cs
index 7b052d81d1..a5b210f868 100644
--- a/TUnit.Engine.Tests/InvokableTestBase.cs
+++ b/TUnit.Engine.Tests/InvokableTestBase.cs
@@ -63,7 +63,7 @@ private async Task RunWithoutAot(string filter,
"--treenode-filter", filter,
"--report-trx", "--report-trx-filename", trxFilename,
"--diagnostic-verbosity", "Debug",
- "--diagnostic", "--diagnostic-output-fileprefix", $"log_{GetType().Name}_",
+ "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_",
"--hangdump", "--hangdump-filename", $"hangdump.{Environment.OSVersion.Platform}.tests-{guid}.dmp", "--hangdump-timeout", "5m",
..runOptions.AdditionalArguments
@@ -99,7 +99,7 @@ private async Task RunWithAot(string filter, List> assertions,
"--treenode-filter", filter,
"--report-trx", "--report-trx-filename", trxFilename,
"--diagnostic-verbosity", "Debug",
- "--diagnostic", "--diagnostic-output-fileprefix", $"log_{GetType().Name}_AOT_",
+ "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_AOT_",
"--timeout", "5m",
..runOptions.AdditionalArguments
]
@@ -133,7 +133,7 @@ private async Task RunWithSingleFile(string filter,
"--treenode-filter", filter,
"--report-trx", "--report-trx-filename", trxFilename,
"--diagnostic-verbosity", "Debug",
- "--diagnostic", "--diagnostic-output-fileprefix", $"log_{GetType().Name}_SINGLEFILE_",
+ "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_SINGLEFILE_",
"--timeout", "5m",
..runOptions.AdditionalArguments
]
diff --git a/TUnit.Engine.Tests/VB.cs b/TUnit.Engine.Tests/VB.cs
index 55cf5e78d6..a1c7cb40d6 100644
--- a/TUnit.Engine.Tests/VB.cs
+++ b/TUnit.Engine.Tests/VB.cs
@@ -24,7 +24,7 @@ public async Task Test()
"--configuration", "Release",
"--report-trx", "--report-trx-filename", trxFilename,
"--diagnostic-verbosity", "Debug",
- "--diagnostic", "--diagnostic-output-fileprefix", $"log_{GetType().Name}_",
+ "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_",
"--timeout", "5m",
// "--hangdump", "--hangdump-filename", $"hangdump.tests-{guid}.dmp", "--hangdump-timeout", "3m",
diff --git a/TUnit.Engine/Extensions/TestExtensions.cs b/TUnit.Engine/Extensions/TestExtensions.cs
index 491822a443..0b7df1b17b 100644
--- a/TUnit.Engine/Extensions/TestExtensions.cs
+++ b/TUnit.Engine/Extensions/TestExtensions.cs
@@ -22,13 +22,13 @@ internal static TestNode ToTestNode(this TestContext testContext)
new LinePosition(testDetails.TestLineNumber, 0)
)),
new TestMethodIdentifierProperty(
- Namespace: testDetails.MethodMetadata.Class.Type.Namespace ?? "",
- AssemblyFullName: testDetails.MethodMetadata.Class.Type.Assembly.GetName().FullName,
- TypeName: testContext.GetClassTypeName(),
- MethodName: testDetails.MethodName,
- ParameterTypeFullNames: CreateParameterTypeArray(testDetails.MethodMetadata.Parameters.Select(static p => p.Type).ToArray()),
- ReturnTypeFullName: testDetails.ReturnType.FullName ?? typeof(void).FullName!,
- MethodArity: testDetails.MethodMetadata.GenericTypeCount
+ @namespace: testDetails.MethodMetadata.Class.Type.Namespace ?? "",
+ assemblyFullName: testDetails.MethodMetadata.Class.Type.Assembly.GetName().FullName,
+ typeName: testContext.GetClassTypeName(),
+ methodName: testDetails.MethodName,
+ parameterTypeFullNames: CreateParameterTypeArray(testDetails.MethodMetadata.Parameters.Select(static p => p.Type).ToArray()),
+ returnTypeFullName: testDetails.ReturnType.FullName ?? typeof(void).FullName!,
+ methodArity: testDetails.MethodMetadata.GenericTypeCount
),
// Custom TUnit Properties
diff --git a/TUnit.Engine/Logging/TUnitFrameworkLogger.cs b/TUnit.Engine/Logging/TUnitFrameworkLogger.cs
index d29ccb510d..c6b7c1a068 100644
--- a/TUnit.Engine/Logging/TUnitFrameworkLogger.cs
+++ b/TUnit.Engine/Logging/TUnitFrameworkLogger.cs
@@ -40,7 +40,7 @@ public async ValueTask LogAsync(LogLevel logLevel, TState state, Excepti
{
ConsoleColor = GetConsoleColor(logLevel)
}
- });
+ }, CancellationToken.None);
await _adapter.LogAsync(logLevel, state, exception, formatter);
}
@@ -60,7 +60,7 @@ public void Log(LogLevel logLevel, TState state, Exception? exception, F
{
ConsoleColor = GetConsoleColor(logLevel)
}
- });
+ }, CancellationToken.None);
_adapter.Log(logLevel, state, exception, formatter);
}
diff --git a/TUnit.Engine/TUnitMessageBus.cs b/TUnit.Engine/TUnitMessageBus.cs
index 4a3c8743e9..20226cbd05 100644
--- a/TUnit.Engine/TUnitMessageBus.cs
+++ b/TUnit.Engine/TUnitMessageBus.cs
@@ -205,7 +205,7 @@ private IEnumerable GetTrxMessages(TestContext testContext, string s
if (!string.IsNullOrEmpty(testContext.SkipReason))
{
- yield return new TrxMessage($"Skipped: {testContext.SkipReason}");
+ yield return new DebugOrTraceTrxMessage($"Skipped: {testContext.SkipReason}");
}
}
diff --git a/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs b/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs
index 73cb330a76..796c740b68 100644
--- a/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs
+++ b/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs
@@ -17,8 +17,9 @@ public class RunAnalyzersTestsModule : Module
{
var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Analyzers.Tests.csproj").AssertExists();
- return await context.DotNet().Test(new DotNetTestOptions(project)
+ return await context.DotNet().Test(new DotNetTestOptions
{
+ WorkingDirectory = project.Folder!,
NoBuild = true,
Configuration = Configuration.Release,
Framework = "net8.0",
diff --git a/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs b/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs
index 3ce3f2884d..01458e50f1 100644
--- a/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs
+++ b/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs
@@ -17,8 +17,9 @@ public class RunAssertionsAnalyzersTestsModule : Module
{
var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Assertions.Analyzers.Tests.csproj").AssertExists();
- return await context.DotNet().Test(new DotNetTestOptions(project)
+ return await context.DotNet().Test(new DotNetTestOptions
{
+ WorkingDirectory = project.Folder!,
NoBuild = true,
Configuration = Configuration.Release,
Framework = "net8.0",
diff --git a/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs b/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs
index 72e58bbb83..ac7e4af46e 100644
--- a/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs
+++ b/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs
@@ -17,8 +17,9 @@ public class RunAssertionsCodeFixersTestsModule : Module
{
var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Assertions.Analyzers.CodeFixers.Tests.csproj").AssertExists();
- return await context.DotNet().Test(new DotNetTestOptions(project)
+ return await context.DotNet().Test(new DotNetTestOptions
{
+ WorkingDirectory = project.Folder!,
NoBuild = true,
Configuration = Configuration.Release,
Framework = "net8.0",
diff --git a/TUnit.Pipeline/Modules/RunRpcTestsModule.cs b/TUnit.Pipeline/Modules/RunRpcTestsModule.cs
index 06c07a6d25..a85724add0 100644
--- a/TUnit.Pipeline/Modules/RunRpcTestsModule.cs
+++ b/TUnit.Pipeline/Modules/RunRpcTestsModule.cs
@@ -8,6 +8,7 @@
namespace TUnit.Pipeline.Modules;
[NotInParallel("DotNetTests")]
+[RunOnLinuxOnly, RunOnWindowsOnly]
public class RunRpcTestsModule : TestBaseModule
{
protected override IEnumerable TestableFrameworks =>
diff --git a/TUnit.Pipeline/Modules/RunTemplateTestsModule.cs b/TUnit.Pipeline/Modules/RunTemplateTestsModule.cs
index 7277ce520c..ad6f2384bd 100644
--- a/TUnit.Pipeline/Modules/RunTemplateTestsModule.cs
+++ b/TUnit.Pipeline/Modules/RunTemplateTestsModule.cs
@@ -17,8 +17,9 @@ public class RunTemplateTestsModule : Module
{
var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Templates.Tests.csproj").AssertExists();
- return await context.DotNet().Test(new DotNetTestOptions(project)
+ return await context.DotNet().Test(new DotNetTestOptions
{
+ WorkingDirectory = project.Folder!,
NoBuild = true,
Configuration = Configuration.Release,
Framework = "net9.0",
diff --git a/accept-snapshots.csx b/accept-snapshots.csx
deleted file mode 100644
index 9120689bff..0000000000
--- a/accept-snapshots.csx
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.IO;
-
-var testDir = @"C:\git\TUnit\TUnit.Assertions.SourceGenerator.Tests";
-var receivedFiles = Directory.GetFiles(testDir, "*.received.txt");
-
-Console.WriteLine($"Found {receivedFiles.Length} received files");
-
-foreach (var file in receivedFiles)
-{
- var verifiedFile = file.Replace(".received.txt", ".verified.txt");
- File.Move(file, verifiedFile, overwrite: true);
- Console.WriteLine($"Moved: {Path.GetFileName(file)} -> {Path.GetFileName(verifiedFile)}");
-}
-
-Console.WriteLine("Done!");
diff --git a/aot_output.txt b/aot_output.txt
deleted file mode 100644
index 252f99bf01..0000000000
--- a/aot_output.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- Determining projects to restore...
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Analyzers\TUnit.Analyzers.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Core.SourceGenerator\TUnit.Core.SourceGenerator.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Analyzers.CodeFixers\TUnit.Analyzers.CodeFixers.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Assertions.Analyzers\TUnit.Assertions.Analyzers.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Assertions.Analyzers.CodeFixers\TUnit.Assertions.Analyzers.CodeFixers.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit\TUnit.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Core\TUnit.Core.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Assertions.SourceGenerator\TUnit.Assertions.SourceGenerator.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.Assertions\TUnit.Assertions.csproj::TargetFramework=netstandard2.0]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net472]
-C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(107,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net6.0]
diff --git a/build-output.txt b/build-output.txt
deleted file mode 100644
index 7cfb5640fb..0000000000
--- a/build-output.txt
+++ /dev/null
@@ -1,684 +0,0 @@
- Determining projects to restore...
- All projects are up-to-date for restore.
-C:\Users\thomh\.nuget\packages\system.text.encodings.web\9.0.0\buildTransitive\netcoreapp2.0\System.Text.Encodings.Web.targets(4,5): warning : System.Text.Encodings.Web 9.0.0 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set true in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net6.0]
-C:\Users\thomh\.nuget\packages\system.io.pipelines\9.0.0\buildTransitive\netcoreapp2.0\System.IO.Pipelines.targets(4,5): warning : System.IO.Pipelines 9.0.0 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set true in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net6.0]
-C:\Users\thomh\.nuget\packages\microsoft.bcl.asyncinterfaces\9.0.0\buildTransitive\netcoreapp2.0\Microsoft.Bcl.AsyncInterfaces.targets(4,5): warning : Microsoft.Bcl.AsyncInterfaces 9.0.0 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set true in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net6.0]
-C:\Users\thomh\.nuget\packages\system.text.json\9.0.0\buildTransitive\netcoreapp2.0\System.Text.Json.targets(4,5): warning : System.Text.Json 9.0.0 doesn't support net6.0 and has not been tested with it. Consider upgrading your TargetFramework to net8.0 or later. You may also set true in the project file to ignore this warning and attempt to run in this unsupported configuration at your own risk. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net6.0]
- Removing SourceGeneratedViewer directory...
- Removing SourceGeneratedViewer directory...
-C:\git\TUnit\TUnit.Assertions.Analyzers\AnalyzerReleases.Shipped.md(5,1): warning RS2007: Analyzer release file 'AnalyzerReleases.Shipped.md' has a missing or invalid release header '#### Assertion Usage Rules' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md) [C:\git\TUnit\TUnit.Assertions.Analyzers\TUnit.Assertions.Analyzers.csproj::TargetFramework=netstandard2.0]
- TUnit.Assertions.Analyzers -> C:\git\TUnit\TUnit.Assertions.Analyzers\bin\Debug\netstandard2.0\TUnit.Assertions.Analyzers.dll
- TUnit.Assertions.Analyzers.CodeFixers -> C:\git\TUnit\TUnit.Assertions.Analyzers.CodeFixers\bin\Debug\netstandard2.0\TUnit.Assertions.Analyzers.CodeFixers.dll
- TUnit.Assertions.SourceGenerator -> C:\git\TUnit\TUnit.Assertions.SourceGenerator\bin\Debug\netstandard2.0\TUnit.Assertions.SourceGenerator.dll
- TUnit.Core -> C:\git\TUnit\TUnit.Core\bin\Debug\net9.0\TUnit.Core.dll
- TUnit.Assertions -> C:\git\TUnit\TUnit.Assertions\bin\Debug\net9.0\TUnit.Assertions.dll
-C:\git\TUnit\TUnit.Analyzers\AnalyzerReleases.Shipped.md(5,1): warning RS2007: Analyzer release file 'AnalyzerReleases.Shipped.md' has a missing or invalid release header '#### Test Method and Structure Rules' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md) [C:\git\TUnit\TUnit.Analyzers\TUnit.Analyzers.csproj::TargetFramework=netstandard2.0]
- TUnit.Analyzers -> C:\git\TUnit\TUnit.Analyzers\bin\Debug\netstandard2.0\TUnit.Analyzers.dll
- TUnit.Core.SourceGenerator -> C:\git\TUnit\TUnit.Core.SourceGenerator\bin\Debug\netstandard2.0\TUnit.Core.SourceGenerator.dll
- TUnit.Analyzers.CodeFixers -> C:\git\TUnit\TUnit.Analyzers.CodeFixers\bin\Debug\netstandard2.0\TUnit.Analyzers.CodeFixers.dll
-C:\git\TUnit\TUnit.TestProject.Library\AsyncBaseTests.cs(4,23): warning TUnit0059: Abstract test class 'AsyncBaseTests' has test methods with data sources. Add [InheritsTests] on a concrete class to execute these tests. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject.Library\Bugs\1889\BaseTests.cs(3,23): warning TUnit0059: Abstract test class 'BaseTest' has test methods with data sources. Add [InheritsTests] on a concrete class to execute these tests. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject.Library\Bugs\1889\BaseTests.cs(12,17): warning TUnit0300: Generic test method may require runtime type creation may not be AOT-compatible. All generic type combinations must be known at compile time. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject.Library\Bugs\1889\BaseTests.cs(19,17): warning TUnit0300: Generic test method may require runtime type creation may not be AOT-compatible. All generic type combinations must be known at compile time. [C:\git\TUnit\TUnit.TestProject.Library\TUnit.TestProject.Library.csproj::TargetFramework=net9.0]
- TUnit.TestProject.Library -> C:\git\TUnit\TUnit.TestProject.Library\bin\Debug\net9.0\TUnit.TestProject.Library.dll
- TUnit.Engine -> C:\git\TUnit\TUnit.Engine\bin\Debug\net9.0\TUnit.Engine.dll
- TUnit -> C:\git\TUnit\TUnit\bin\Debug\net9.0\TUnit.dll
-C:\git\TUnit\TUnit.TestProject\SourceGeneratedViewer\TUnit.Core.SourceGenerator\TUnit.Core.SourceGenerator.Generators.PropertyInjectionSourceGenerator\TUnit_TestProject_PropertyInitializationTests_PropertyInjection.g.cs(39,86): warning CS8669: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\SourceGeneratedViewer\TUnit.Core.SourceGenerator\TUnit.Core.SourceGenerator.Generators.PropertyInjectionSourceGenerator\TUnit_TestProject_PropertyInitializationTests_PropertyInjection.g.cs(56,97): warning CS8669: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\AbstractBaseClassPropertyInjectionTests.cs(20,27): warning CS8602: Dereference of a possibly null reference. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\AbstractBaseClassPropertyInjectionTests.cs(37,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\TransactionTest.cs(11,30): warning CS8618: Non-nullable field '_scope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\AsyncDataSourceExampleTests.cs(7,67): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\AsyncDataSourceExampleTests.cs(59,71): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\AsyncLocalTest.cs(27,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Tests.cs(13,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, StringComparison comparison, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1570\Tests.cs(21,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(52,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(54,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(53,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(55,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(69,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(71,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(71,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(73,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\2075\Tests.cs(53,45): warning CS9113: Parameter 'factory' is unread. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(86,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(89,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(93,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(96,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\2136\Tests.cs(17,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(89,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(91,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(94,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(96,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(112,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(115,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(119,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(122,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(112,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(114,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(117,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\AsyncHookTests.cs(119,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(138,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(141,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(145,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(148,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(152,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Bugs\1914\SyncHookTests.cs(155,9): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Tests.cs(189,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource' in 'StringEqualsAssertion AssertionExtensions.IsEqualTo(IAssertionSource source, string expected, string? expression = null)' due to differences in the nullability of reference types. [C:\git\TUnit\TUnit.TestProject\TUnit.TestProject.csproj::TargetFramework=net9.0]
-C:\git\TUnit\TUnit.TestProject\Tests.cs(196,15): warning CS8620: Argument of type 'ValueAssertion' cannot be used for parameter 'source' of type 'IAssertionSource