Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 7, 2025

Summary

This PR introduces a new test project TraceParserGen.Tests that implements a comprehensive test framework for validating TraceParserGen.exe.

Changes Made

Latest Updates

  • Removed FindInputDir method - Simplified to use Path.Combine(Environment.CurrentDirectory, "inputs") directly since inputs are copied to the output directory
  • Use ProjectReference for test apps - Changed from <Reference> tag to <ProjectReference> pointing to TraceEvent.csproj, ensuring all dependencies are included

Previous Updates

  • Simplified to net462 only - Changed from multi-targeting to just net462 since tests only need to run on Windows
  • Removed Windows platform check - No longer needed since net462 only runs on Windows
  • Removed TraceEvent ProjectReference from test project - Not needed in the test project itself
  • Use system TEMP directory - Changed to .NET's standard temp directory via Path.GetTempPath()
  • Simplified directory creation - Removed redundant check before Directory.CreateDirectory
  • Removed else path - Test app always creates a parser and processes a trace file
  • Enhanced test validation with real trace files - Uses TraceEventDispatcher.GetDispatcherFromFileName and hooks TraceEventParser.All
  • Removed --no-build flag - Test app rebuilds each time
  • Deterministic TraceParserGen.exe location - Added build target to copy TraceParserGen.exe to test output

Test Framework Features

The test framework validates the entire code generation pipeline:

  1. Runs TraceParserGen.exe with test input (ETW manifest files)
  2. Verifies successful generation of C# parser files
  3. Creates temporary console projects that:
    • Use ProjectReference to TraceEvent.csproj (found at runtime)
    • Include the generated parsers
    • Always use real trace files to validate event parsing
    • Hook All event to count processed events
  4. Builds and runs the temporary projects to ensure generated code works correctly

Benefits

  • Enables safe refactoring - Changes to TraceParserGen can now be validated automatically
  • Regression prevention - Catches breaking changes before they reach production
  • Real-world validation - Tests always use actual trace files to verify parsers work correctly
  • Proper dependency management - Uses ProjectReference to ensure all TraceEvent dependencies are included
  • Windows-focused - Targets net462 only, ensuring tests run in the correct environment
  • Clean and simple - Uses standard .NET patterns for temp directories and project structure
Original prompt

The repo contains an exe that we build from source called TraceParserGen. This exe is responsible for taking ETW manifests or DLLs containing EventSource implementations and building C# classes that implement parsers for the events defined in the manifest for EventSource. We do not currently have a set of test cases, which means that we are unable to make changes to TraceParserGen without breaking it.

I'd like you to build a project called TraceParserGen.Tests that implements a test framework for TraceParserGen. The test cases won't be standard in-app C# test cases, but instead will need to be able to do the following:

  1. Run the built copy of TraceParserGen.exe with test input (a manifest file or a C# EventSource dll).
  2. Ensure that TraceParserGen.exe successfully runs and generates a C# file.
  3. Create a temporary console project that depends on the TraceEvent (also built in the repo) and includes the newly generated C# file.
  4. Build the temporary project and run the resulting executable, making sure that no asserts or errors occur. NOTE: We likely won't have traces to run the parser against, but we can make sure that we don't run into any obvious C# failures.

I would like you to build the test framework and maybe a single sample test. For step 3, create a sample application that uses reflection to find all of the TraceEvent-based parsers that exist in the current assembly and then create an instance of each and subscribe to all of the events.

Expect that I will review this work and then provide additional coaching.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Add testing framework for TraceParserGen executable Add comprehensive test framework for TraceParserGen Oct 7, 2025
Copilot AI requested a review from brianrob October 7, 2025 01:14
Copilot finished work on behalf of brianrob October 7, 2025 01:14
Copy link
Member

@brianrob brianrob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot, please address these comments.

// Since we don't have a real source, we'll just verify the type can be instantiated
// by checking if it has expected methods

var enumerateMethod = parserType.GetMethod(""EnumerateTemplates"",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of searching for EnumerateTemplates lets assume that the caller of this executable passed in the path to a trace file with events that will be parsed by the generated parser. You can create a TraceEventSource by calling TraceEventDispatcher.GetDispatcherFromFileName. Then you can make sure that the events show up properly in the parser by hooking the TraceEventParser.All on the generated parser.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the test application to use TraceEventDispatcher.GetDispatcherFromFileName with a trace file. The generated parser is now instantiated with the source, hooks TraceEventParser.All to count events, and processes the trace to validate the parser works correctly. Commit: f5dd42c

var startInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = "run -c Release --no-build",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove --no-build.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed --no-build flag. Commit: f5dd42c

string[] searchPaths = new[]
{
// Relative to test output directory
Path.Combine(Environment.CurrentDirectory, @"../../../../TraceParserGen/bin/Release/net462/TraceParserGen.exe"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a deterministic way to get TraceParserGen.exe. Instead, please update the TraceParserGen.Tests.csproj to depend on the TraceParserGen build. Copy the binary that matches the flavor (debug/release) into the binaries directory when building TraceParserGen.Tests. Then, you can directly point at the current bin directory for the exe to target rather than searching for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ProjectReference to TraceParserGen and a build target that copies TraceParserGen.exe to the test output directory. GetTraceParserGenExePath() now simply returns the exe from the current directory. Commit: f5dd42c

protected string GetTraceEventAssemblyPath()
{
// Search for TraceEvent DLL in common build output locations
string[] searchPaths = new[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than referencing TraceEvent.dll directly, please reference the Project via a in the test applications.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test project already references TraceEvent via ProjectReference. The generated test app uses the TraceEvent.dll from the test project's output directory (where it's copied as part of the ProjectReference). Commit: f5dd42c

CreateNoWindow = true
};
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests only run on Windows, so you can remove the else here and just unconditionally run the Windows path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the else block and mono-related code. Tests now only support Windows execution path. Commit: f5dd42c

Copilot AI requested a review from brianrob October 7, 2025 03:02
Copilot finished work on behalf of brianrob October 7, 2025 03:02
Copy link
Member

@brianrob brianrob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address this comment.

}}
}}
}}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the else path. We always want to create a parser and process the trace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the else path. The test app now always creates a parser and processes the trace file. If the trace file doesn't exist, it returns an error instead of skipping. Commit: 04562ba

Copilot AI requested a review from brianrob October 7, 2025 03:18
Copilot finished work on behalf of brianrob October 7, 2025 03:18
Copy link
Member

@brianrob brianrob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address these comments.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests themselves don't need to run against multiple TFMs. Please just run these against net462. Then you can also remove the code that confirms that we're only running on Windows, since net462 can only run on Windows.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to target net462 only and removed Windows platform check. Commit: 5f3a8c7

</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TraceEvent\TraceEvent.csproj" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the TraceEvent ProjectReference - it is not needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed TraceEvent ProjectReference. Commit: 5f3a8c7

string dir = Environment.CurrentDirectory;
while (dir != null)
{
string candidate = Path.Combine(dir, @"TraceParserGen.Tests\inputs");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should just be "inputs" because the inputs are being copied into the output directory and the output directory will be the current directory when running.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed TestDataDir to just "inputs" since inputs are copied to the output directory. Commit: 5f3a8c7

{
protected static string OriginalInputDir = FindInputDir();
protected static string TestDataDir = Path.GetFullPath("inputs");
protected static string BaseOutputDir = Path.GetFullPath("output");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using BaseOutputDir, just use .NET's standard facility to get a random directory in TEMP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to use Path.GetTempPath() instead of custom BaseOutputDir. Commit: 5f3a8c7

OutputDir = Path.Combine(BaseOutputDir, Guid.NewGuid().ToString("N").Substring(0, 8));

// Ensure output directory exists
if (!Directory.Exists(OutputDir))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check - Directory.CreateDirectory will check before attempting to create it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the existence check - Directory.CreateDirectory handles it. Commit: 5f3a8c7

Copilot AI requested a review from brianrob October 7, 2025 15:41
Copilot finished work on behalf of brianrob October 7, 2025 15:41
Copy link
Member

@brianrob brianrob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address these comments.

/// <summary>
/// Finds the input directory for test files
/// </summary>
private static string FindInputDir()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not needed - since you're operating from Environment.CurrentDirectory, the location of the inputs should be Path.Combine(Environment.CurrentDirectory, "inputs").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed FindInputDir method. TestDataDir now uses Path.Combine(Environment.CurrentDirectory, "inputs") directly. Commit: 0bc8f45

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include=""Microsoft.Diagnostics.Tracing.TraceEvent"">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using a <Reference> tag, this should be a <ProjectReference> tag pointing at TraceEvent.csproj in the repo. You'll need to implement this by using a relative path (e.g. ....\TraceEvent\TraceEvent.csproj). This might not be the right relative path, but you can tell by finding the source code at runtime. You'll need to do this because TraceEvent.dll won't be the only dependency needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to use <ProjectReference> tag pointing to TraceEvent.csproj. The path is found at runtime by navigating from the test assembly location to the source directory. Commit: 0bc8f45

Copilot AI requested a review from brianrob October 7, 2025 15:51
Copilot finished work on behalf of brianrob October 7, 2025 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants